From 71228bac1999b0e0fc781d58e176c37a30d76ded Mon Sep 17 00:00:00 2001 From: Maximiliano Curia Date: Sat, 18 Jun 2016 08:32:47 +0100 Subject: [PATCH] Import kcontacts_16.04.2.orig.tar.xz [dgit import orig kcontacts_16.04.2.orig.tar.xz] --- .arcconfig | 4 + .krazy | 1 + .reviewboardrc | 5 + CMakeLists.txt | 67 + COPYING.LIB | 510 +++ KF5ContactsConfig.cmake.in | 5 + Mainpage.dox | 34 + README | 28 + README.AddressFormat | 66 + autotests/CMakeLists.txt | 14 + autotests/addresseetest.cpp | 478 +++ autotests/addresseetest.h | 44 + autotests/addresstest.cpp | 226 + autotests/addresstest.h | 41 + autotests/calendarurltest.cpp | 310 ++ autotests/calendarurltest.h | 47 + autotests/contactgrouptest.cpp | 385 ++ autotests/data/v4_0.vcard1.vcf.ref | 15 + autotests/data/v4_0.vcard2.vcf.ref | 12 + autotests/data/v4_0.vcard3.vcf.ref | 12 + autotests/data/v4_0.vcard4.vcf.ref | 14 + autotests/data/v4_0.vcard5.vcf.ref | 313 ++ autotests/data/v4_0.vcard6.vcf.ref | 10 + autotests/data/v4_0.vcard7.vcf.ref | 8 + autotests/data/v4_0.vcard8.vcf.ref | 8 + autotests/data/vcard1.vcf | 14 + autotests/data/vcard1.vcf.2_1ref | 14 + autotests/data/vcard1.vcf.ref | 15 + autotests/data/vcard10.vcf | 56 + autotests/data/vcard10.vcf.ref | 52 + autotests/data/vcard11.vcf | 10 + autotests/data/vcard11.vcf.ref | 10 + autotests/data/vcard12.vcf | 15 + autotests/data/vcard12.vcf.2_1ref | Bin 0 -> 555 bytes autotests/data/vcard12.vcf.ref | 16 + autotests/data/vcard13.vcf | 12 + autotests/data/vcard13.vcf.ref | 12 + autotests/data/vcard14.vcf | 12 + autotests/data/vcard14.vcf.2_1ref | 11 + autotests/data/vcard14.vcf.ref | 12 + autotests/data/vcard2.vcf | 12 + autotests/data/vcard2.vcf.2_1ref | 12 + autotests/data/vcard2.vcf.ref | 12 + autotests/data/vcard3.vcf | 12 + autotests/data/vcard3.vcf.2_1ref | 12 + autotests/data/vcard3.vcf.ref | 12 + autotests/data/vcard4.vcf | 14 + autotests/data/vcard4.vcf.ref | 14 + autotests/data/vcard5.vcf | 313 ++ autotests/data/vcard5.vcf.ref | 312 ++ autotests/data/vcard6.vcf | 10 + autotests/data/vcard6.vcf.2_1ref | 9 + autotests/data/vcard6.vcf.ref | 10 + autotests/data/vcard7.vcf | 7 + autotests/data/vcard7.vcf.2_1ref | 8 + autotests/data/vcard7.vcf.ref | 8 + autotests/data/vcard8.vcf | 8 + autotests/data/vcard8.vcf.ref | 8 + autotests/data/vcard9.vcf | 14 + autotests/data/vcard9.vcf.ref | 14 + autotests/emailtest.cpp | 187 + autotests/emailtest.h | 45 + autotests/gendertest.cpp | 258 ++ autotests/gendertest.h | 51 + autotests/geotest.cpp | 206 + autotests/geotest.h | 44 + autotests/impptest.cpp | 305 ++ autotests/impptest.h | 51 + autotests/keytest.cpp | 99 + autotests/keytest.h | 38 + autotests/langtest.cpp | 244 ++ autotests/langtest.h | 46 + autotests/ldifconvertertest.cpp | 500 +++ autotests/ldifconvertertest.h | 57 + autotests/phonenumbertest.cpp | 173 + autotests/phonenumbertest.h | 40 + autotests/picturetest.cpp | 267 ++ autotests/picturetest.h | 49 + autotests/relatedtest.cpp | 243 ++ autotests/relatedtest.h | 46 + autotests/resourcelocatorurltest.cpp | 229 ++ autotests/resourcelocatorurltest.h | 45 + autotests/secrecytest.cpp | 86 + autotests/secrecytest.h | 39 + autotests/soundtest.cpp | 262 ++ autotests/soundtest.h | 47 + autotests/testlock.h | 52 + autotests/testroundtrip.cpp | 206 + autotests/testroundtrip.qrc | 61 + autotests/timezonetest.cpp | 112 + autotests/timezonetest.h | 40 + autotests/vcarddragtest.cpp | 182 + metainfo.yaml | 14 + src/CMakeLists.txt | 120 + src/Messages.sh | 2 + src/address.cpp | 717 ++++ src/address.h | 343 ++ src/addressee.cpp | 2381 +++++++++++ src/addressee.h | 1053 +++++ src/addresseehelper.cpp | 119 + src/addresseehelper.h | 121 + src/addresseelist.cpp | 363 ++ src/addresseelist.h | 426 ++ src/calendarurl.cpp | 179 + src/calendarurl.h | 85 + src/contactgroup.cpp | 507 +++ src/contactgroup.h | 490 +++ src/contactgroup.xsd | 76 + src/contactgrouptool.cpp | 370 ++ src/contactgrouptool.h | 77 + src/converter/CMakeLists.txt | 22 + src/converter/ldifconverter.cpp | 643 +++ src/converter/ldifconverter.h | 96 + src/converter/vcardconverter.cpp | 148 + src/converter/vcardconverter.h | 158 + src/countrytransl.map | 5685 ++++++++++++++++++++++++++ src/email.cpp | 140 + src/email.h | 77 + src/field.cpp | 654 +++ src/field.h | 240 ++ src/gender.cpp | 131 + src/gender.h | 72 + src/geo.cpp | 174 + src/geo.h | 141 + src/impp.cpp | 195 + src/impp.h | 96 + src/key.cpp | 245 ++ src/key.h | 186 + src/lang.cpp | 139 + src/lang.h | 71 + src/ldapdn.cpp | 208 + src/ldapdn_p.h | 84 + src/ldif.cpp | 453 ++ src/ldif_p.h | 197 + src/phonenumber.cpp | 272 ++ src/phonenumber.h | 232 ++ src/picture.cpp | 250 ++ src/picture.h | 204 + src/related.cpp | 139 + src/related.h | 68 + src/resourcelocatorurl.cpp | 133 + src/resourcelocatorurl.h | 76 + src/secrecy.cpp | 162 + src/secrecy.h | 127 + src/sortmode.cpp | 114 + src/sortmode.h | 137 + src/sound.cpp | 171 + src/sound.h | 184 + src/timezone.cpp | 134 + src/timezone.h | 108 + src/vcarddrag.cpp | 91 + src/vcarddrag.h | 102 + src/vcardparser/CMakeLists.txt | 10 + src/vcardparser/vcard.cpp | 121 + src/vcardparser/vcard.h | 92 + src/vcardparser/vcardline.cpp | 139 + src/vcardparser/vcardline.h | 128 + src/vcardparser/vcardparser.cpp | 390 ++ src/vcardparser/vcardparser.h | 47 + src/vcardtool.cpp | 1409 +++++++ src/vcardtool.h | 99 + tests/CMakeLists.txt | 24 + tests/README.testing | 12 + tests/checkvcard.pl | 79 + tests/testread.cpp | 81 + tests/testread2.cpp | 61 + tests/testutils.cpp | 117 + tests/testutils.h | 36 + tests/testwrite.cpp | 129 + 169 files changed, 31425 insertions(+) create mode 100644 .arcconfig create mode 100644 .krazy create mode 100644 .reviewboardrc create mode 100644 CMakeLists.txt create mode 100644 COPYING.LIB create mode 100644 KF5ContactsConfig.cmake.in create mode 100644 Mainpage.dox create mode 100644 README create mode 100644 README.AddressFormat create mode 100644 autotests/CMakeLists.txt create mode 100644 autotests/addresseetest.cpp create mode 100644 autotests/addresseetest.h create mode 100644 autotests/addresstest.cpp create mode 100644 autotests/addresstest.h create mode 100644 autotests/calendarurltest.cpp create mode 100644 autotests/calendarurltest.h create mode 100644 autotests/contactgrouptest.cpp create mode 100644 autotests/data/v4_0.vcard1.vcf.ref create mode 100644 autotests/data/v4_0.vcard2.vcf.ref create mode 100644 autotests/data/v4_0.vcard3.vcf.ref create mode 100644 autotests/data/v4_0.vcard4.vcf.ref create mode 100644 autotests/data/v4_0.vcard5.vcf.ref create mode 100644 autotests/data/v4_0.vcard6.vcf.ref create mode 100644 autotests/data/v4_0.vcard7.vcf.ref create mode 100644 autotests/data/v4_0.vcard8.vcf.ref create mode 100644 autotests/data/vcard1.vcf create mode 100644 autotests/data/vcard1.vcf.2_1ref create mode 100644 autotests/data/vcard1.vcf.ref create mode 100644 autotests/data/vcard10.vcf create mode 100644 autotests/data/vcard10.vcf.ref create mode 100644 autotests/data/vcard11.vcf create mode 100644 autotests/data/vcard11.vcf.ref create mode 100644 autotests/data/vcard12.vcf create mode 100644 autotests/data/vcard12.vcf.2_1ref create mode 100644 autotests/data/vcard12.vcf.ref create mode 100644 autotests/data/vcard13.vcf create mode 100644 autotests/data/vcard13.vcf.ref create mode 100644 autotests/data/vcard14.vcf create mode 100644 autotests/data/vcard14.vcf.2_1ref create mode 100644 autotests/data/vcard14.vcf.ref create mode 100644 autotests/data/vcard2.vcf create mode 100644 autotests/data/vcard2.vcf.2_1ref create mode 100644 autotests/data/vcard2.vcf.ref create mode 100644 autotests/data/vcard3.vcf create mode 100644 autotests/data/vcard3.vcf.2_1ref create mode 100644 autotests/data/vcard3.vcf.ref create mode 100644 autotests/data/vcard4.vcf create mode 100644 autotests/data/vcard4.vcf.ref create mode 100644 autotests/data/vcard5.vcf create mode 100644 autotests/data/vcard5.vcf.ref create mode 100644 autotests/data/vcard6.vcf create mode 100644 autotests/data/vcard6.vcf.2_1ref create mode 100644 autotests/data/vcard6.vcf.ref create mode 100644 autotests/data/vcard7.vcf create mode 100644 autotests/data/vcard7.vcf.2_1ref create mode 100644 autotests/data/vcard7.vcf.ref create mode 100644 autotests/data/vcard8.vcf create mode 100644 autotests/data/vcard8.vcf.ref create mode 100644 autotests/data/vcard9.vcf create mode 100644 autotests/data/vcard9.vcf.ref create mode 100644 autotests/emailtest.cpp create mode 100644 autotests/emailtest.h create mode 100644 autotests/gendertest.cpp create mode 100644 autotests/gendertest.h create mode 100644 autotests/geotest.cpp create mode 100644 autotests/geotest.h create mode 100644 autotests/impptest.cpp create mode 100644 autotests/impptest.h create mode 100644 autotests/keytest.cpp create mode 100644 autotests/keytest.h create mode 100644 autotests/langtest.cpp create mode 100644 autotests/langtest.h create mode 100644 autotests/ldifconvertertest.cpp create mode 100644 autotests/ldifconvertertest.h create mode 100644 autotests/phonenumbertest.cpp create mode 100644 autotests/phonenumbertest.h create mode 100644 autotests/picturetest.cpp create mode 100644 autotests/picturetest.h create mode 100644 autotests/relatedtest.cpp create mode 100644 autotests/relatedtest.h create mode 100644 autotests/resourcelocatorurltest.cpp create mode 100644 autotests/resourcelocatorurltest.h create mode 100644 autotests/secrecytest.cpp create mode 100644 autotests/secrecytest.h create mode 100644 autotests/soundtest.cpp create mode 100644 autotests/soundtest.h create mode 100644 autotests/testlock.h create mode 100644 autotests/testroundtrip.cpp create mode 100644 autotests/testroundtrip.qrc create mode 100644 autotests/timezonetest.cpp create mode 100644 autotests/timezonetest.h create mode 100644 autotests/vcarddragtest.cpp create mode 100644 metainfo.yaml create mode 100644 src/CMakeLists.txt create mode 100644 src/Messages.sh create mode 100644 src/address.cpp create mode 100644 src/address.h create mode 100644 src/addressee.cpp create mode 100644 src/addressee.h create mode 100644 src/addresseehelper.cpp create mode 100644 src/addresseehelper.h create mode 100644 src/addresseelist.cpp create mode 100644 src/addresseelist.h create mode 100644 src/calendarurl.cpp create mode 100644 src/calendarurl.h create mode 100644 src/contactgroup.cpp create mode 100644 src/contactgroup.h create mode 100644 src/contactgroup.xsd create mode 100644 src/contactgrouptool.cpp create mode 100644 src/contactgrouptool.h create mode 100644 src/converter/CMakeLists.txt create mode 100644 src/converter/ldifconverter.cpp create mode 100644 src/converter/ldifconverter.h create mode 100644 src/converter/vcardconverter.cpp create mode 100644 src/converter/vcardconverter.h create mode 100644 src/countrytransl.map create mode 100644 src/email.cpp create mode 100644 src/email.h create mode 100644 src/field.cpp create mode 100644 src/field.h create mode 100644 src/gender.cpp create mode 100644 src/gender.h create mode 100644 src/geo.cpp create mode 100644 src/geo.h create mode 100644 src/impp.cpp create mode 100644 src/impp.h create mode 100644 src/key.cpp create mode 100644 src/key.h create mode 100644 src/lang.cpp create mode 100644 src/lang.h create mode 100644 src/ldapdn.cpp create mode 100644 src/ldapdn_p.h create mode 100644 src/ldif.cpp create mode 100644 src/ldif_p.h create mode 100644 src/phonenumber.cpp create mode 100644 src/phonenumber.h create mode 100644 src/picture.cpp create mode 100644 src/picture.h create mode 100644 src/related.cpp create mode 100644 src/related.h create mode 100644 src/resourcelocatorurl.cpp create mode 100644 src/resourcelocatorurl.h create mode 100644 src/secrecy.cpp create mode 100644 src/secrecy.h create mode 100644 src/sortmode.cpp create mode 100644 src/sortmode.h create mode 100644 src/sound.cpp create mode 100644 src/sound.h create mode 100644 src/timezone.cpp create mode 100644 src/timezone.h create mode 100644 src/vcarddrag.cpp create mode 100644 src/vcarddrag.h create mode 100644 src/vcardparser/CMakeLists.txt create mode 100644 src/vcardparser/vcard.cpp create mode 100644 src/vcardparser/vcard.h create mode 100644 src/vcardparser/vcardline.cpp create mode 100644 src/vcardparser/vcardline.h create mode 100644 src/vcardparser/vcardparser.cpp create mode 100644 src/vcardparser/vcardparser.h create mode 100644 src/vcardtool.cpp create mode 100644 src/vcardtool.h create mode 100644 tests/CMakeLists.txt create mode 100644 tests/README.testing create mode 100755 tests/checkvcard.pl create mode 100644 tests/testread.cpp create mode 100644 tests/testread2.cpp create mode 100644 tests/testutils.cpp create mode 100644 tests/testutils.h create mode 100644 tests/testwrite.cpp diff --git a/.arcconfig b/.arcconfig new file mode 100644 index 0000000..20d53ee --- /dev/null +++ b/.arcconfig @@ -0,0 +1,4 @@ +{ + "phabricator.uri" : "https://phabricator.kde.org/project/profile/34/", + "history.immutable" : true +} diff --git a/.krazy b/.krazy new file mode 100644 index 0000000..80b3c47 --- /dev/null +++ b/.krazy @@ -0,0 +1 @@ +SKIP /scripts/|/tests/|/testroundtrip diff --git a/.reviewboardrc b/.reviewboardrc new file mode 100644 index 0000000..8d7e2e9 --- /dev/null +++ b/.reviewboardrc @@ -0,0 +1,5 @@ +REVIEWBOARD_URL = "https://git.reviewboard.kde.org" +#REPOSITORY = "git://anongit.kde.org/kcontacts" +BRANCH = "master" +TARGET_GROUPS = "kdepimlibs" +TARGET_PEOPLE = "mlaurent" diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..9abb646 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,67 @@ +cmake_minimum_required(VERSION 2.8.12) + +project(KContacts) + +# ECM setup +find_package(ECM 5.19.0 CONFIG REQUIRED) +set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${KContacts_SOURCE_DIR}/cmake) + +include(GenerateExportHeader) +include(ECMGenerateHeaders) +include(ECMGeneratePriFile) +include(ECMPackageConfigHelpers) +include(ECMSetupVersion) +include(FeatureSummary) +include(KDEInstallDirs) +include(KDECMakeSettings) +include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) +include(ECMQtDeclareLoggingCategory) + +set(KF5_VERSION "5.19.0") +set(KCONTACTS_LIB_VERSION "5.2.2") + +ecm_setup_version(${KCONTACTS_LIB_VERSION} 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 5.4 REQUIRED COMPONENTS DBus Gui) +find_package(KF5 ${KF5_VERSION} REQUIRED COMPONENTS CoreAddons I18n Config Codecs) + +########### Targets ########### + +add_definitions(-DTRANSLATION_DOMAIN=\"kcontacts5\") +add_definitions("-DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII") +add_subdirectory(src) + +if(BUILD_TESTING) + add_subdirectory(autotests) + add_subdirectory(tests) +endif() + +########### CMake Config Files ########### +set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5Contacts") + +ecm_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 +) + +feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/COPYING.LIB b/COPYING.LIB new file mode 100644 index 0000000..2d2d780 --- /dev/null +++ b/COPYING.LIB @@ -0,0 +1,510 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/KF5ContactsConfig.cmake.in b/KF5ContactsConfig.cmake.in new file mode 100644 index 0000000..2047983 --- /dev/null +++ b/KF5ContactsConfig.cmake.in @@ -0,0 +1,5 @@ +@PACKAGE_INIT@ + +find_dependency(KF5CoreAddons "@KF5_VERSION@") + +include("${CMAKE_CURRENT_LIST_DIR}/KF5ContactsTargets.cmake") diff --git a/Mainpage.dox b/Mainpage.dox new file mode 100644 index 0000000..fafd789 --- /dev/null +++ b/Mainpage.dox @@ -0,0 +1,34 @@ +/* + Mainpage.dox -- for now, copied from README + */ + +/** +@mainpage LIBKContacts - new address book API for KDE + +@section purpose Purpose + +libkabc provides an API for address book data. This can be used by all KDE +application using data of this type, e.g. KAddressBook, KMail, KOrganizer, +KPilot etc. It is meant as replacement for libkab (in kdebase/kab). + +@section features Features + +- Value based interface, addressbook entry data is implicitly shared. +- Address book entries are identified by a unique id. +- vCard backend (RFC 2425 / RFC 2426). +- Locking mechanism to support concurrent access to the address book by + multiple processes. +- Notification on change of addressbook by other process. +- Dialog for selecting address book entries, supports mouse and keyboard + selection, supports automatic name completion. +- GUI client for viewing, modifying address book data. This is aimed at + developers not end users. +- Tool for converting data, written with libkab, to libkabc format. +- Multiple backends (resources) for storing entries e.g. LDAP + +@authors Cornelius Schumacher \ + +LICENCE: LGPL +*/ +// DOXYGEN_REFERENCES = kdecore kdeui kresources +// DOXYGEN_TOOLTIP = "An API for the KDE Addressbook." diff --git a/README b/README new file mode 100644 index 0000000..5376317 --- /dev/null +++ b/README @@ -0,0 +1,28 @@ +KContacts - new address book API for KDE + +PURPOSE: + +KCcontacts provides an API for address book data. This can be used by all +application using data of this type, e.g. KAddressBook, KMail, KOrganizer, +etc. + +FEATURES: + +- Value based interface, addressbook entry data is implicitly shared. +- Address book entries are identified by a unique id. +- vCard backend (RFC 2425 / RFC 2426). +- Locking mechanism to support concurrent access to the address book by + multiple processes. +- Notification on change of addressbook by other process. +- Dialog for selecting address book entries, supports mouse and keyboard + selection, supports automatic name completion. +- GUI client for viewing, modifying address book data. This is aimed at + developers not end users. +- Tool for converting data, written with libkab, to libkabc format. +- Multiple backends (resources) for storing entries e.g. LDAP + +AUTHOR: Cornelius Schumacher + +LICENCE: LGPL + +DATE: 13 Oct 2001 diff --git a/README.AddressFormat b/README.AddressFormat new file mode 100644 index 0000000..6c53f5c --- /dev/null +++ b/README.AddressFormat @@ -0,0 +1,66 @@ +Address formats can be a tricky thing. KContacts tries very hard to perfectly fit +the needs of ~95% of users and to be at least sufficient for the other 5%. + +The formatting of an address depends on the destination country as well as on +the origin country of a letter. Basically, the part indicating the destination +country follows the rules of the country of origin, all the rest follows the +rules of the destination country. So we need to store for every country a) the +country positioning and b) the address formatting. + +Address formats should usually be stored in a country's entry.desktop. There we +store the country position in field "AddressCountryPosition" and the address +format in a field "AddressFormat". Note that for most countries one field +"AddressFormat" is sufficient for personal as well as company addresses +(because personal addresses look just like business addresses without company); +however, in some countries (eg. Hungary) business addresses differ in their +structure. In this case you have the possibility of adding another field +"BusinessAddressFormat" which will be preferred for formatting of business +addresses; if KContacts can't find such a field, it will fall back to +"AddressFormat". (Please use BusinessAddressFormat ONLY if you really need to) + +The format consists mainly of tags that will be replaced by address fields. +The list of tags may grow in the future, the format *might* change in the near +future, but I hope not. + +Any comments very very welcome to kde-pim@kde.org or to jost@schenck.de. + +-Jost. + +Fields AddressFormat and BusinessAddressFormat +------------------------------------------------ +%n = real name +%N = REAL NAME +%cm = company +%CM = COMPANY +%s = street +%S = STREET +%z = zip code +%l = location +%L = LOCATION +%r = region +%R = REGION +%p = post office box +%, = conditional comma+whitespace, + will be left out if the value left or right of it is purged +%w = conditional whitespace, + will be left out if the value left or right of it is purged +%0(...) = the text inside the brackets will be completely purged if not + at least one tag inside it evaluates to something. Example: when the + address doesn't have a postbox, the string %0(PO Box %p) will not + evaluate to "PO Box " but to an empty string. +\n = newline + +Field AddressCountryPosition +------------------------------------------------ +below = country name below rest of address +BELOW = country name below in capital letters +above = country name above rest of address +ABOVE = country name above in capital letters + +Some Tips +------------------------------------------------ +- You sometimes have three fields in a line which can all be empty. If you eg. +separate them all with conditional whitespace (same goes for cond. comma) like +in "%z%w%r%w%l" and only the middle value (here: region) is empty, there will +be no whitespace at all between the outer values (here: zipcode and location). +To avoid this, combine two of these values with purge brackets: %0(%z%w%r)%w%l. diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt new file mode 100644 index 0000000..7c18331 --- /dev/null +++ b/autotests/CMakeLists.txt @@ -0,0 +1,14 @@ +include(ECMAddTests) + +set(QT_REQUIRED_VERSION "5.2.0") +find_package(Qt5Test ${QT_REQUIRED_VERSION} CONFIG REQUIRED) + +########### next target ############### + +set(testroundtrip_srcs testroundtrip.cpp) +qt5_add_resources(testroundtrip_srcs testroundtrip.qrc) +add_executable(testroundtrip ${testroundtrip_srcs}) +add_test(NAME kcontacts-testroundtrip COMMAND testroundtrip) +target_link_libraries(testroundtrip KF5Contacts Qt5::Test) + +ecm_add_tests(addresseetest.cpp impptest.cpp emailtest.cpp addresstest.cpp geotest.cpp keytest.cpp phonenumbertest.cpp picturetest.cpp secrecytest.cpp soundtest.cpp timezonetest.cpp contactgrouptest.cpp vcarddragtest.cpp langtest.cpp gendertest.cpp calendarurltest.cpp ldifconvertertest.cpp relatedtest.cpp resourcelocatorurltest.cpp NAME_PREFIX "kcontacts-" LINK_LIBRARIES KF5Contacts Qt5::Test KF5::ConfigCore Qt5::Gui) diff --git a/autotests/addresseetest.cpp b/autotests/addresseetest.cpp new file mode 100644 index 0000000..156d642 --- /dev/null +++ b/autotests/addresseetest.cpp @@ -0,0 +1,478 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2007 Tobias Koenig + + 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. +*/ +//krazy:excludeall=contractions + +#include "addresseetest.h" +#include "kcontacts/addressee.h" +#include + +QTEST_MAIN(AddresseeTest) + +void AddresseeTest::emptyTest() +{ + KContacts::Addressee addressee; + QVERIFY(addressee.isEmpty()); + + KContacts::Addressee addresseeWithMail; + addresseeWithMail.insertEmail(QStringLiteral("foo@bar.org")); + QVERIFY(!addresseeWithMail.isEmpty()); +} + +void AddresseeTest::storeTest() +{ + KContacts::Addressee addressee; + + KContacts::Picture logo(QStringLiteral("http://scottlandyard.info/pics/logo.png")); + KContacts::Picture photo(QStringLiteral("http://scottlandyard.info/~sinclair/photo.png")); + KContacts::Sound sound(QStringLiteral("http://scottlandyard.info/~sinclair/sound.wav")); + + QStringList emails; + emails << QStringLiteral("john@sinclair.com") << QStringLiteral("ghosthunter@sinclair.com"); + + KContacts::Key::List keys; + keys << KContacts::Key(QStringLiteral("SecretKey")); + + QStringList categories; + categories << QStringLiteral("Helper") << QStringLiteral("Friend"); + + QStringList customs; + customs << QStringLiteral("X-Danger: high"); + + KContacts::Gender gender(QStringLiteral("H")); + addressee.setGender(gender); + KContacts::Lang lang(QLatin1String("lang")); + addressee.setLangs(KContacts::Lang::List() << lang); + + addressee.setUid(QStringLiteral("My uid")); + addressee.setName(QStringLiteral("John Sinclair")); + addressee.setFormattedName(QStringLiteral("Sinclair, John")); + addressee.setFamilyName(QStringLiteral("Sinclair")); + addressee.setGivenName(QStringLiteral("John")); + addressee.setAdditionalName(QStringLiteral("Bob")); + addressee.setPrefix(QStringLiteral("Sir")); + addressee.setSuffix(QStringLiteral("II")); + addressee.setNickName(QStringLiteral("ghosthunter")); + addressee.setBirthday(QDateTime(QDate(1982, 7, 19))); + addressee.setMailer(QStringLiteral("mutt")); + addressee.setTimeZone(KContacts::TimeZone(2)); + addressee.setGeo(KContacts::Geo(42, 23)); + addressee.setTitle(QStringLiteral("Ghost Hunter")); + addressee.setRole(QStringLiteral("Leader")); + addressee.setOrganization(QStringLiteral("Scottland Yard")); + addressee.setNote(QStringLiteral("Don't cross black deads way...")); + addressee.setProductId(QStringLiteral("ProductId45")); + addressee.setRevision(QDateTime(QDate(1982, 9, 15))); + addressee.setSortString(QStringLiteral("Name")); + KContacts::ResourceLocatorUrl url; + url.setUrl(QUrl(QStringLiteral("www.scottlandyard.info"))); + addressee.setUrl(url); + addressee.setSecrecy(KContacts::Secrecy(KContacts::Secrecy::Public)); + addressee.setLogo(logo); + addressee.setPhoto(photo); + addressee.setSound(sound); + addressee.setEmails(emails); + addressee.setKeys(keys); + addressee.setCategories(categories); + addressee.setCustoms(customs); + addressee.setKind(QStringLiteral("foo")); + addressee.setChanged(false); + KContacts::Impp imp; + imp.setType(KContacts::Impp::GaduGadu); + imp.setAddress(QStringLiteral("foo@kde.org")); + KContacts::Impp::List listImp; + listImp << imp; + addressee.setImppList(listImp); + + QVERIFY(addressee.imppList() == listImp); + QVERIFY(addressee.langs() == (KContacts::Lang::List() << lang)); + QVERIFY(addressee.gender() == gender); + QVERIFY(addressee.uid() == QStringLiteral("My uid")); + QVERIFY(addressee.name() == QStringLiteral("John Sinclair")); + QVERIFY(addressee.formattedName() == QStringLiteral("Sinclair, John")); + QVERIFY(addressee.familyName() == QStringLiteral("Sinclair")); + QVERIFY(addressee.givenName() == QStringLiteral("John")); + QVERIFY(addressee.additionalName() == QStringLiteral("Bob")); + QVERIFY(addressee.prefix() == QStringLiteral("Sir")); + QVERIFY(addressee.suffix() == QStringLiteral("II")); + QVERIFY(addressee.nickName() == QStringLiteral("ghosthunter")); + QVERIFY(addressee.birthday() == QDateTime(QDate(1982, 7, 19))); + QVERIFY(addressee.mailer() == QStringLiteral("mutt")); + QVERIFY(addressee.timeZone() == KContacts::TimeZone(2)); + QVERIFY(addressee.geo() == KContacts::Geo(42, 23)); + QVERIFY(addressee.title() == QStringLiteral("Ghost Hunter")); + QVERIFY(addressee.role() == QStringLiteral("Leader")); + QVERIFY(addressee.organization() == QStringLiteral("Scottland Yard")); + QVERIFY(addressee.note() == QStringLiteral("Don't cross black deads way...")); + QVERIFY(addressee.productId() == QStringLiteral("ProductId45")); + QVERIFY(addressee.revision() == QDateTime(QDate(1982, 9, 15))); + QVERIFY(addressee.sortString() == QStringLiteral("Name")); + QVERIFY(addressee.url() == url); + QVERIFY(addressee.secrecy() == KContacts::Secrecy(KContacts::Secrecy::Public)); + QVERIFY(addressee.logo() == logo); + QVERIFY(addressee.photo() == photo); + QVERIFY(addressee.sound() == sound); + QVERIFY(addressee.emails() == emails); + QVERIFY(addressee.keys() == keys); + QVERIFY(addressee.categories() == categories); + QVERIFY(addressee.customs() == customs); + QVERIFY(addressee.changed() == false); + QCOMPARE(addressee.kind(), QStringLiteral("foo")); +} + +void AddresseeTest::equalsTest() +{ + KContacts::Addressee addressee1, addressee2; + + KContacts::Picture logo(QStringLiteral("http://scottlandyard.info/pics/logo.png")); + KContacts::Picture photo(QStringLiteral("http://scottlandyard.info/~sinclair/photo.png")); + KContacts::Sound sound(QStringLiteral("http://scottlandyard.info/~sinclair/sound.wav")); + + QStringList emails; + emails << QStringLiteral("john@sinclair.com") << QStringLiteral("ghosthunter@sinclair.com"); + + KContacts::Key::List keys; + keys << KContacts::Key(QStringLiteral("SecretKey")); + + QStringList categories; + categories << QStringLiteral("Helper") << QStringLiteral("Friend"); + + QStringList customs; + customs << QStringLiteral("X-Danger: high"); + + addressee1.setUid(QStringLiteral("My uid")); + addressee1.setName(QStringLiteral("John Sinclair")); + addressee1.setFormattedName(QStringLiteral("Sinclair, John")); + addressee1.setFamilyName(QStringLiteral("Sinclair")); + addressee1.setGivenName(QStringLiteral("John")); + addressee1.setAdditionalName(QStringLiteral("Bob")); + addressee1.setPrefix(QStringLiteral("Sir")); + addressee1.setSuffix(QStringLiteral("II")); + addressee1.setNickName(QStringLiteral("ghosthunter")); + addressee1.setBirthday(QDateTime(QDate(1982, 7, 19))); + addressee1.setMailer(QStringLiteral("mutt")); + addressee1.setTimeZone(KContacts::TimeZone(2)); + addressee1.setGeo(KContacts::Geo(42, 23)); + addressee1.setTitle(QStringLiteral("Ghost Hunter")); + addressee1.setRole(QStringLiteral("Leader")); + addressee1.setOrganization(QStringLiteral("Scottland Yard")); + addressee1.setNote(QStringLiteral("Don't cross black deads way...")); + addressee1.setProductId(QStringLiteral("ProductId45")); + addressee1.setRevision(QDateTime(QDate(1982, 9, 15))); + addressee1.setSortString(QStringLiteral("Name")); + KContacts::ResourceLocatorUrl url; + url.setUrl(QUrl(QStringLiteral("www.scottlandyard.info"))); + addressee1.setUrl(url); + addressee1.setSecrecy(KContacts::Secrecy(KContacts::Secrecy::Public)); + addressee1.setLogo(logo); + addressee1.setPhoto(photo); + addressee1.setSound(sound); + addressee1.setEmails(emails); + addressee1.setKeys(keys); + addressee1.setCategories(categories); + addressee1.setCustoms(customs); + addressee1.setChanged(false); + + addressee2.setUid(QStringLiteral("My uid")); + addressee2.setName(QStringLiteral("John Sinclair")); + addressee2.setFormattedName(QStringLiteral("Sinclair, John")); + addressee2.setFamilyName(QStringLiteral("Sinclair")); + addressee2.setGivenName(QStringLiteral("John")); + addressee2.setAdditionalName(QStringLiteral("Bob")); + addressee2.setPrefix(QStringLiteral("Sir")); + addressee2.setSuffix(QStringLiteral("II")); + addressee2.setNickName(QStringLiteral("ghosthunter")); + addressee2.setBirthday(QDateTime(QDate(1982, 7, 19))); + addressee2.setMailer(QStringLiteral("mutt")); + addressee2.setTimeZone(KContacts::TimeZone(2)); + addressee2.setGeo(KContacts::Geo(42, 23)); + addressee2.setTitle(QStringLiteral("Ghost Hunter")); + addressee2.setRole(QStringLiteral("Leader")); + addressee2.setOrganization(QStringLiteral("Scottland Yard")); + addressee2.setNote(QStringLiteral("Don't cross black deads way...")); + addressee2.setProductId(QStringLiteral("ProductId45")); + addressee2.setRevision(QDateTime(QDate(1982, 9, 15))); + addressee2.setSortString(QStringLiteral("Name")); + addressee2.setUrl(url); + addressee2.setSecrecy(KContacts::Secrecy(KContacts::Secrecy::Public)); + addressee2.setLogo(logo); + addressee2.setPhoto(photo); + addressee2.setSound(sound); + addressee2.setEmails(emails); + addressee2.setKeys(keys); + addressee2.setCategories(categories); + addressee2.setCustoms(customs); + addressee2.setChanged(false); + + QVERIFY(addressee1 == addressee2); +} + +void AddresseeTest::differsTest() +{ + KContacts::Addressee addressee1, addressee2; + + addressee1.setNameFromString(QStringLiteral("John Sinclair")); + addressee2.setNameFromString(QStringLiteral("Suko")); + + QVERIFY(addressee1 != addressee2); +} + +void AddresseeTest::assignmentTest() +{ + KContacts::Addressee addressee1, addressee2; + + KContacts::Picture logo(QStringLiteral("http://scottlandyard.info/pics/logo.png")); + KContacts::Picture photo(QStringLiteral("http://scottlandyard.info/~sinclair/photo.png")); + KContacts::Sound sound(QStringLiteral("http://scottlandyard.info/~sinclair/sound.wav")); + + QStringList emails; + emails << QStringLiteral("john@sinclair.com") << QStringLiteral("ghosthunter@sinclair.com"); + + KContacts::Key::List keys; + keys << KContacts::Key(QStringLiteral("SecretKey")); + + QStringList categories; + categories << QStringLiteral("Helper") << QStringLiteral("Friend"); + + QStringList customs; + customs << QStringLiteral("X-Danger: high"); + + addressee1.setUid(QStringLiteral("My uid")); + addressee1.setName(QStringLiteral("John Sinclair")); + addressee1.setFormattedName(QStringLiteral("Sinclair, John")); + addressee1.setFamilyName(QStringLiteral("Sinclair")); + addressee1.setGivenName(QStringLiteral("John")); + addressee1.setAdditionalName(QStringLiteral("Bob")); + addressee1.setPrefix(QStringLiteral("Sir")); + addressee1.setSuffix(QStringLiteral("II")); + addressee1.setNickName(QStringLiteral("ghosthunter")); + addressee1.setBirthday(QDateTime(QDate(1982, 7, 19))); + addressee1.setMailer(QStringLiteral("mutt")); + addressee1.setTimeZone(KContacts::TimeZone(2)); + addressee1.setGeo(KContacts::Geo(42, 23)); + addressee1.setTitle(QStringLiteral("Ghost Hunter")); + addressee1.setRole(QStringLiteral("Leader")); + addressee1.setOrganization(QStringLiteral("Scottland Yard")); + addressee1.setNote(QStringLiteral("Don't cross black deads way...")); + addressee1.setProductId(QStringLiteral("ProductId45")); + addressee1.setRevision(QDateTime(QDate(1982, 9, 15))); + addressee1.setSortString(QStringLiteral("Name")); + KContacts::ResourceLocatorUrl url; + url.setUrl(QUrl(QStringLiteral("www.scottlandyard.info"))); + addressee1.setUrl(url); + addressee1.setSecrecy(KContacts::Secrecy(KContacts::Secrecy::Public)); + addressee1.setLogo(logo); + addressee1.setPhoto(photo); + addressee1.setSound(sound); + addressee1.setEmails(emails); + addressee1.setKeys(keys); + addressee1.setCategories(categories); + addressee1.setCustoms(customs); + addressee1.setChanged(false); + + addressee2 = addressee1; + + QVERIFY(addressee1 == addressee2); +} + +void AddresseeTest::serializeTest() +{ + KContacts::Addressee addressee1, addressee2; + + KContacts::Picture logo(QStringLiteral("http://scottlandyard.info/pics/logo.png")); + KContacts::Picture photo(QStringLiteral("http://scottlandyard.info/~sinclair/photo.png")); + KContacts::Sound sound(QStringLiteral("http://scottlandyard.info/~sinclair/sound.wav")); + + QStringList emails; + emails << QStringLiteral("john@sinclair.com") << QStringLiteral("ghosthunter@sinclair.com"); + + KContacts::Key::List keys; + keys << KContacts::Key(QStringLiteral("SecretKey")); + + QStringList categories; + categories << QStringLiteral("Helper") << QStringLiteral("Friend"); + + QStringList customs; + customs << QStringLiteral("FirstApp-FirstKey:FirstValue") + << QStringLiteral("SecondApp-SecondKey:SecondValue") + << QStringLiteral("ThirdApp-ThirdKey:ThirdValue"); + + addressee1.setUid(QStringLiteral("My uid")); + addressee1.setName(QStringLiteral("John Sinclair")); + addressee1.setFormattedName(QStringLiteral("Sinclair, John")); + addressee1.setFamilyName(QStringLiteral("Sinclair")); + addressee1.setGivenName(QStringLiteral("John")); + addressee1.setAdditionalName(QStringLiteral("Bob")); + addressee1.setPrefix(QStringLiteral("Sir")); + addressee1.setSuffix(QStringLiteral("II")); + addressee1.setNickName(QStringLiteral("ghosthunter")); + addressee1.setBirthday(QDateTime(QDate(1982, 7, 19))); + addressee1.setMailer(QStringLiteral("mutt")); + addressee1.setTimeZone(KContacts::TimeZone(2)); + addressee1.setGeo(KContacts::Geo(42, 23)); + addressee1.setTitle(QStringLiteral("Ghost Hunter")); + addressee1.setRole(QStringLiteral("Leader")); + addressee1.setOrganization(QStringLiteral("Scottland Yard")); + addressee1.setNote(QStringLiteral("Don't cross black deads way...")); + addressee1.setProductId(QStringLiteral("ProductId45")); + addressee1.setRevision(QDateTime(QDate(1982, 9, 15))); + addressee1.setSortString(QStringLiteral("Name")); + KContacts::ResourceLocatorUrl url; + url.setUrl(QUrl(QStringLiteral("www.scottlandyard.info"))); + + addressee1.setUrl(url); + addressee1.setSecrecy(KContacts::Secrecy(KContacts::Secrecy::Public)); + addressee1.setLogo(logo); + addressee1.setPhoto(photo); + addressee1.setSound(sound); + addressee1.setEmails(emails); + addressee1.setKeys(keys); + addressee1.setCategories(categories); + addressee1.setCustoms(customs); + addressee1.setChanged(false); + + QByteArray data; + QDataStream s(&data, QIODevice::WriteOnly); + s << addressee1; + + QDataStream t(&data, QIODevice::ReadOnly); + t >> addressee2; + + QVERIFY(addressee1 == addressee2); +} + +void AddresseeTest::fullEmailTest() +{ + KContacts::Addressee a; + QStringList emails; + emails << QStringLiteral("foo@bar.com"); + a.setEmails(emails); + a.setFormattedName(QStringLiteral("firstname \"nickname\" lastname")); + QCOMPARE(a.fullEmail(), + QStringLiteral("\"firstname \\\"nickname\\\" lastname\" ")); +} + +void AddresseeTest::nameFromStringTest() +{ + KContacts::Addressee a; + a.setNameFromString(QStringLiteral("Firstname Lastname")); + QCOMPARE(a.givenName(), QStringLiteral("Firstname")); + QCOMPARE(a.familyName(), QStringLiteral("Lastname")); + QCOMPARE(a.formattedName(), QStringLiteral("Firstname Lastname")); +} + +void AddresseeTest::customFieldsTest() +{ + KContacts::Addressee a; + + // test for empty + QVERIFY(a.customs().isEmpty()); + + // test insert + a.insertCustom(QStringLiteral("MyApp"), QStringLiteral("MyKey"), QStringLiteral("MyValue")); + QCOMPARE(a.customs().count(), 1); + QCOMPARE(a.custom(QStringLiteral("MyApp"), QStringLiteral("MyKey")), QStringLiteral("MyValue")); + + a.insertCustom(QStringLiteral("MyApp"), QStringLiteral("MyKey"), QStringLiteral("YourValue")); + QCOMPARE(a.customs().count(), 1); // still one, we overwrite... + QCOMPARE(a.custom(QStringLiteral("MyApp"), QStringLiteral("MyKey")), QStringLiteral("YourValue")); + + // test query non-existing app/key + QCOMPARE(a.custom(QStringLiteral("MyApp"), QStringLiteral("UnknownKey")), QString()); + QCOMPARE(a.custom(QStringLiteral("UnknownApp"), QStringLiteral("MyKey")), QString()); + + // test insert with different key + a.insertCustom(QStringLiteral("MyApp"), QStringLiteral("AnotherKey"), QStringLiteral("OtherValue")); + QCOMPARE(a.customs().count(), 2); + QCOMPARE(a.custom(QStringLiteral("MyApp"), QStringLiteral("AnotherKey")), QStringLiteral("OtherValue")); + QCOMPARE(a.custom(QStringLiteral("MyApp"), QStringLiteral("MyKey")), QStringLiteral("YourValue")); + + // test insert with different app + a.insertCustom(QStringLiteral("OtherApp"), QStringLiteral("OtherKey"), QStringLiteral("OurValue")); + QCOMPARE(a.customs().count(), 3); + QCOMPARE(a.custom(QStringLiteral("OtherApp"), QStringLiteral("OtherKey")), QStringLiteral("OurValue")); + QCOMPARE(a.custom(QStringLiteral("MyApp"), QStringLiteral("AnotherKey")), QStringLiteral("OtherValue")); + QCOMPARE(a.custom(QStringLiteral("MyApp"), QStringLiteral("MyKey")), QStringLiteral("YourValue")); + +#if 0 //Order is not defined now as we use a QHash + // test customs + QCOMPARE(a.customs().at(0), QStringLiteral("MyApp-MyKey:YourValue")); + QCOMPARE(a.customs().at(1), QStringLiteral("MyApp-AnotherKey:OtherValue")); + QCOMPARE(a.customs().at(2), QStringLiteral("OtherApp-OtherKey:OurValue")); +#endif + // test equal operator + KContacts::Addressee b; + b.setUid(a.uid()); + b.insertCustom(QStringLiteral("OtherApp"), QStringLiteral("OtherKey"), QStringLiteral("OurValue")); + b.insertCustom(QStringLiteral("MyApp"), QStringLiteral("MyKey"), QStringLiteral("YourValue")); + b.insertCustom(QStringLiteral("MyApp"), QStringLiteral("AnotherKey"), QStringLiteral("OtherValue")); + + QCOMPARE(a, b); + + b.insertCustom(QStringLiteral("MyApp"), QStringLiteral("AnotherKey"), QStringLiteral("WrongValue")); + QVERIFY(a != b); + + // test setCustoms + KContacts::Addressee c; + c.insertCustom(QStringLiteral("ThisApp"), QStringLiteral("ShouldNotBe"), QStringLiteral("There")); + QCOMPARE(c.customs().count(), 1); + + const QStringList testData = QStringList() << QStringLiteral("FirstApp-FirstKey:FirstValue") + << QStringLiteral("SecondApp-SecondKey:SecondValue") + << QStringLiteral("ThirdApp-ThirdKey:ThirdValue"); + + c.setCustoms(testData); + QCOMPARE(c.customs().count(), 3); + + QCOMPARE(c.custom(QStringLiteral("FirstApp"), QStringLiteral("FirstKey")), QStringLiteral("FirstValue")); + QCOMPARE(c.custom(QStringLiteral("SecondApp"), QStringLiteral("SecondKey")), QStringLiteral("SecondValue")); + QCOMPARE(c.custom(QStringLiteral("ThirdApp"), QStringLiteral("ThirdKey")), QStringLiteral("ThirdValue")); + + // test remove + QCOMPARE(c.customs().count(), 3); + c.removeCustom(QStringLiteral("UnknownApp"), QStringLiteral("FirstKey")); + QCOMPARE(c.customs().count(), 3); + c.removeCustom(QStringLiteral("FirstApp"), QStringLiteral("UnknownKey")); + QCOMPARE(c.customs().count(), 3); + c.removeCustom(QStringLiteral("FirstApp"), QStringLiteral("FirstKey")); + QCOMPARE(c.customs().count(), 2); +} + +void AddresseeTest::parseEmailAddress_data() +{ + QTest::addColumn("inputEmail"); + QTest::addColumn("email"); + QTest::addColumn("name"); + QTest::newRow("simpleemail") << QStringLiteral("foo@kde.org") << QStringLiteral("foo@kde.org") << QString(); + QTest::newRow("email") << QStringLiteral("foo ") << QStringLiteral("foo@kde.org") << QStringLiteral("foo"); + QTest::newRow("namewithdoublequote") << QStringLiteral("\"foo\" ") << QStringLiteral("foo@kde.org") << QStringLiteral("foo"); +} + +void AddresseeTest::parseEmailAddress() +{ + QFETCH(QString, inputEmail); + QFETCH(QString, email); + QFETCH(QString, name); + + QString parsedName; + QString parsedEmail; + KContacts::Addressee::parseEmailAddress(inputEmail, parsedName, parsedEmail); + QCOMPARE(parsedEmail, email); + QCOMPARE(parsedName, name); +} diff --git a/autotests/addresseetest.h b/autotests/addresseetest.h new file mode 100644 index 0000000..fb161ac --- /dev/null +++ b/autotests/addresseetest.h @@ -0,0 +1,44 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2007 Tobias Koenig + + 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 ADDRESSEE_TEST_H +#define ADDRESSEE_TEST_H + +#include + +class AddresseeTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void emptyTest(); + void storeTest(); + void equalsTest(); + void differsTest(); + void assignmentTest(); + void serializeTest(); + void fullEmailTest(); + void nameFromStringTest(); + void customFieldsTest(); + void parseEmailAddress_data(); + void parseEmailAddress(); +}; + +#endif diff --git a/autotests/addresstest.cpp b/autotests/addresstest.cpp new file mode 100644 index 0000000..3632934 --- /dev/null +++ b/autotests/addresstest.cpp @@ -0,0 +1,226 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2007 Tobias Koenig + + 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 "addresstest.h" +#include "kcontacts/address.h" +#include +#include +#include +#include +#include + +QTEST_MAIN(AddressTest) + +void AddressTest::initTestCase() +{ + setenv("LANG", "C", 1); +} + +void AddressTest::emptyTest() +{ + KContacts::Address address; + + QVERIFY(address.isEmpty()); +} + +void AddressTest::storeTest() +{ + KContacts::Address address; + + address.setId(QStringLiteral("My Id")); + address.setType(KContacts::Address::Home); + address.setPostOfficeBox(QStringLiteral("1234")); + address.setExtended(QStringLiteral("My Extended Label")); + address.setStreet(QStringLiteral("My Street")); + address.setLocality(QStringLiteral("My Locality")); + address.setRegion(QStringLiteral("My Region")); + address.setPostalCode(QStringLiteral("My PostalCode")); + address.setCountry(QStringLiteral("My Country")); + address.setLabel(QStringLiteral("My Label")); + + QCOMPARE(address.id(), QStringLiteral("My Id")); + QCOMPARE(address.type(), KContacts::Address::Home); + QCOMPARE(address.postOfficeBox(), QStringLiteral("1234")); + QCOMPARE(address.extended(), QStringLiteral("My Extended Label")); + QCOMPARE(address.street(), QStringLiteral("My Street")); + QCOMPARE(address.locality(), QStringLiteral("My Locality")); + QCOMPARE(address.region(), QStringLiteral("My Region")); + QCOMPARE(address.postalCode(), QStringLiteral("My PostalCode")); + QCOMPARE(address.country(), QStringLiteral("My Country")); + QCOMPARE(address.label(), QStringLiteral("My Label")); +} + +void AddressTest::equalsTest() +{ + KContacts::Address address1, address2; + + address1.setId(QStringLiteral("My Id")); + address1.setType(KContacts::Address::Home); + address1.setPostOfficeBox(QStringLiteral("1234")); + address1.setExtended(QStringLiteral("My Extended Label")); + address1.setStreet(QStringLiteral("My Street")); + address1.setLocality(QStringLiteral("My Locality")); + address1.setRegion(QStringLiteral("My Region")); + address1.setPostalCode(QStringLiteral("My Postalcode")); + address1.setCountry(QStringLiteral("My country")); + address1.setLabel(QStringLiteral("My Label")); + + address2.setId(QStringLiteral("My Id")); + address2.setType(KContacts::Address::Home); + address2.setPostOfficeBox(QStringLiteral("1234")); + address2.setExtended(QStringLiteral("My Extended Label")); + address2.setStreet(QStringLiteral("My Street")); + address2.setLocality(QStringLiteral("My Locality")); + address2.setRegion(QStringLiteral("My Region")); + address2.setPostalCode(QStringLiteral("My Postalcode")); + address2.setCountry(QStringLiteral("My country")); + address2.setLabel(QStringLiteral("My Label")); + + QVERIFY(address1 == address2); +} + +void AddressTest::differsTest() +{ + KContacts::Address address1(KContacts::Address::Home); + KContacts::Address address2(KContacts::Address::Work); + + QVERIFY(address1 != address2); +} + +void AddressTest::assignmentTest() +{ + KContacts::Address address1, address2; + + address1.setId(QStringLiteral("My Id")); + address1.setType(KContacts::Address::Home); + address1.setPostOfficeBox(QStringLiteral("1234")); + address1.setExtended(QStringLiteral("My Extended Label")); + address1.setStreet(QStringLiteral("My Street")); + address1.setLocality(QStringLiteral("My Locality")); + address1.setRegion(QStringLiteral("My Region")); + address1.setPostalCode(QStringLiteral("My Postalcode")); + address1.setCountry(QStringLiteral("My country")); + address1.setLabel(QStringLiteral("My Label")); + + address2 = address1; + + QVERIFY(address1 == address2); +} + +void AddressTest::serializeTest() +{ + KContacts::Address address1, address2; + + address1.setType(KContacts::Address::Work); + address1.setPostOfficeBox(QStringLiteral("1234")); + address1.setExtended(QStringLiteral("My Extended Label")); + address1.setStreet(QStringLiteral("My Street")); + address1.setLocality(QStringLiteral("My Locality")); + address1.setRegion(QStringLiteral("My Region")); + address1.setPostalCode(QStringLiteral("My Postalcode")); + address1.setCountry(QStringLiteral("My country")); + address1.setLabel(QStringLiteral("My Label")); + + QByteArray data; + QDataStream s(&data, QIODevice::WriteOnly); + s << address1; + + QDataStream t(&data, QIODevice::ReadOnly); + t >> address2; + + QVERIFY(address1 == address2); +} + +void AddressTest::formatTest() +{ + { + // check availability of country to ISO code mapping data file + const QString mapfile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kf5/kcontacts/countrytransl.map")); + QVERIFY2(!mapfile.isEmpty(), "Country to ISO code mapping data file does not exist"); + + QFileInfo fileInfo(mapfile); + QVERIFY2(fileInfo.exists(), "Country to ISO code mapping data file does not exist"); + QVERIFY2(fileInfo.isReadable(), "Country to ISO code mapping data file is not readable"); + } + + { + const QString templateFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kf5/locale/countries/de/country.desktop")); + QVERIFY(!templateFile.isEmpty()); + const KConfig templateConfig(templateFile); + QVERIFY2(templateConfig.hasGroup("KCM Locale"), + "Address format config for 'de' is missing expected 'KCM Locale' group"); + const KConfigGroup templateGroup = templateConfig.group("KCM Locale"); + QVERIFY2(templateGroup.hasKey("AddressFormat"), + "Address format config is missing expected key 'AddressFormat'"); + const QString addressTemplate = templateGroup.readEntry("AddressFormat"); + QVERIFY2(!addressTemplate.isEmpty(), + "Address format template for 'de' is empty"); + + KContacts::Address address; + address.setStreet(QStringLiteral("Lummerlandstr. 1")); + address.setPostalCode(QStringLiteral("12345")); + address.setLocality(QStringLiteral("Lummerstadt")); + address.setCountry(QStringLiteral("Germany")); + + const QString result(QStringLiteral("Jim Knopf\nLummerlandstr. 1\n" + "12345 Lummerstadt\n\nGERMANY")); + + QCOMPARE(address.formattedAddress(QStringLiteral("Jim Knopf")), result); + } + + { + KContacts::Address address; + address.setStreet(QStringLiteral("457 Foobar Ave")); + address.setPostalCode(QStringLiteral("1A2B3C")); + address.setLocality(QStringLiteral("Nervousbreaktown")); + address.setRegion(QStringLiteral("DC")); + address.setCountry(QStringLiteral("United States of America")); + + const QString result( + QStringLiteral("Huck Finn\n457 Foobar Ave\nNervousbreaktown," + " DC 1A2B3C\n\nUNITED STATES OF AMERICA")); + QCOMPARE(address.formattedAddress(QStringLiteral("Huck Finn")), result); + } + + { + KContacts::Address address; + address.setStreet(QStringLiteral("Lummerlandstr. 1")); + address.setPostalCode(QStringLiteral("12345")); + address.setLocality(QStringLiteral("Lummerstadt")); + address.setCountry(QStringLiteral("Deutschland")); + + const QString result(QStringLiteral("Jim Knopf\nLummerlandstr. 1\n" + "12345 Lummerstadt\n\nDEUTSCHLAND")); + + QCOMPARE(address.formattedAddress(QStringLiteral("Jim Knopf")), result); + } + + { + KContacts::Address address; + address.setStreet(QStringLiteral("Lummerlandstr. 1")); + address.setPostalCode(QStringLiteral("12345")); + address.setLocality(QStringLiteral("Lummerstadt")); + address.setCountry(QString()); + + const QString result(QStringLiteral("Jim Knopf\nLummerlandstr. 1\nLummerstadt, 12345")); + + QCOMPARE(address.formattedAddress(QStringLiteral("Jim Knopf")), result); + } +} diff --git a/autotests/addresstest.h b/autotests/addresstest.h new file mode 100644 index 0000000..bd19441 --- /dev/null +++ b/autotests/addresstest.h @@ -0,0 +1,41 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2007 Tobias Koenig + + 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 ADDRESS_TEST_H +#define ADDRESS_TEST_H + +#include + +class AddressTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void emptyTest(); + void storeTest(); + void equalsTest(); + void differsTest(); + void assignmentTest(); + void serializeTest(); + void formatTest(); +}; + +#endif diff --git a/autotests/calendarurltest.cpp b/autotests/calendarurltest.cpp new file mode 100644 index 0000000..73dd3ad --- /dev/null +++ b/autotests/calendarurltest.cpp @@ -0,0 +1,310 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2015 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 "calendarurltest.h" + +#include "calendarurl.h" +#include "vcardtool.h" +#include + +using namespace KContacts; +Q_DECLARE_METATYPE(KContacts::CalendarUrl::CalendarType) +CalendarUrlTest::CalendarUrlTest(QObject *parent) + : QObject(parent) +{ + +} + +CalendarUrlTest::~CalendarUrlTest() +{ + +} + +void CalendarUrlTest::shouldHaveDefaultValue() +{ + CalendarUrl calendarUrl(CalendarUrl::FBUrl); + QVERIFY(!calendarUrl.isValid()); + QVERIFY(calendarUrl.url().isEmpty()); + QVERIFY(calendarUrl.parameters().isEmpty()); +} + +void CalendarUrlTest::shouldAssignValue() +{ + QMap params; + params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + CalendarUrl calendarUrl(CalendarUrl::FBUrl); + calendarUrl.setParameters(params); + QVERIFY(!calendarUrl.isValid()); + QCOMPARE(calendarUrl.type(), CalendarUrl::FBUrl); + QVERIFY(calendarUrl.url().isEmpty()); + QVERIFY(!calendarUrl.parameters().isEmpty()); + QCOMPARE(calendarUrl.parameters(), params); +} + +void CalendarUrlTest::shouldAssignExternal() +{ + CalendarUrl calendarUrl(CalendarUrl::FBUrl); + const CalendarUrl::CalendarType type = CalendarUrl::CALUri; + calendarUrl.setType(type); + QVERIFY(calendarUrl.url().isEmpty()); + QCOMPARE(calendarUrl.type(), type); +} + +void CalendarUrlTest::shouldSerialized() +{ + for (int i = 0; i < CalendarUrl::EndCalendarType; ++i) { + CalendarUrl calendarUrl; + CalendarUrl result; + CalendarUrl::CalendarType type = static_cast(i); + calendarUrl.setType(type); + QMap params; + params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + calendarUrl.setParameters(params); + calendarUrl.setUrl(QUrl(QStringLiteral("mailto:foo@kde.org"))); + + QByteArray data; + QDataStream s(&data, QIODevice::WriteOnly); + s << calendarUrl; + + QDataStream t(&data, QIODevice::ReadOnly); + t >> result; + + QVERIFY(calendarUrl == result); + } +} + +void CalendarUrlTest::shouldEqualCalendarUrl() +{ + for (int i = 0; i < CalendarUrl::EndCalendarType; ++i) { + CalendarUrl calendarUrl; + CalendarUrl result; + CalendarUrl::CalendarType type = static_cast(i); + calendarUrl.setType(type); + QMap params; + params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + calendarUrl.setUrl(QUrl(QStringLiteral("mailto:foo@kde.org"))); + calendarUrl.setParameters(params); + + result = calendarUrl; + QVERIFY(calendarUrl == result); + } +} + +void CalendarUrlTest::shouldParseCalendarUrl() +{ + for (int i = CalendarUrl::Unknown + 1; i < CalendarUrl::EndCalendarType; ++i) { + CalendarUrl::CalendarType type = static_cast(i); + QByteArray baType; + switch (type) { + case CalendarUrl::Unknown: + case CalendarUrl::EndCalendarType: + break; + case CalendarUrl::FBUrl: + baType = QByteArray("FBURL"); + break; + case CalendarUrl::CALUri: + baType = QByteArray("CALURI"); + break; + case CalendarUrl::CALADRUri: + baType = QByteArray("CALADRURI"); + break; + + } + + QByteArray vcarddata("BEGIN:VCARD\n" + "VERSION:3.0\n" + "N:LastName;FirstName;;;\n" + "UID:c80cf296-0825-4eb0-ab16-1fac1d522a33@xxxxxx.xx\n"); + vcarddata += baType; + vcarddata += QByteArray( + ";PREF=1:https://sherlockholmes.com/calendar/sherlockholmes\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); + QCOMPARE(lst.at(0).calendarUrlList().count(), 1); + const CalendarUrl calurl = lst.at(0).calendarUrlList().at(0); + QCOMPARE(calurl.type(), type); + QCOMPARE(calurl.url(), QUrl(QStringLiteral("https://sherlockholmes.com/calendar/sherlockholmes"))); + QVERIFY(!calurl.parameters().isEmpty()); + } +} + +void CalendarUrlTest::shouldGenerateVCard_data() +{ + QTest::addColumn("type"); + QTest::addColumn("value"); + for (int i = CalendarUrl::Unknown + 1; i < CalendarUrl::EndCalendarType; ++i) { + KContacts::CalendarUrl::CalendarType type = static_cast(i); + QByteArray baType; + switch (type) { + case CalendarUrl::Unknown: + case CalendarUrl::EndCalendarType: + break; + case CalendarUrl::FBUrl: + baType = QByteArray("FBURL"); + break; + case CalendarUrl::CALUri: + baType = QByteArray("CALURI"); + break; + case CalendarUrl::CALADRUri: + baType = QByteArray("CALADRURI"); + break; + + } + QTest::newRow(baType.constData()) << type << baType; + } +} + +void CalendarUrlTest::shouldGenerateVCard() +{ + QFETCH(KContacts::CalendarUrl::CalendarType, type); + QFETCH(QByteArray, value); + + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + CalendarUrl url; + url.setType(type); + url.setUrl(QUrl(QStringLiteral("https://sherlockholmes.com/calendar/sherlockholmes"))); + addr.insertCalendarUrl(url); + lst << addr; + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v4_0); + QByteArray expected; + // Different order + if (type == KContacts::CalendarUrl::FBUrl) { + expected = QByteArray("BEGIN:VCARD\r\n" + "VERSION:4.0\r\n" + "EMAIL:foo@kde.org\r\n"); + expected += value + QByteArray(":https://sherlockholmes.com/calendar/sherlockholmes\r\n" + "N:;;;;\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + } else { + expected = QByteArray("BEGIN:VCARD\r\n" + "VERSION:4.0\r\n"); + expected += value + QByteArray(":https://sherlockholmes.com/calendar/sherlockholmes\r\n" + "EMAIL:foo@kde.org\r\n" + "N:;;;;\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + } + + QCOMPARE(ba, expected); +} + +void CalendarUrlTest::shouldGenerateVCardWithParameter() +{ + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + CalendarUrl url; + url.setType(CalendarUrl::CALUri); + url.setUrl(QUrl(QStringLiteral("https://sherlockholmes.com/calendar/sherlockholmes"))); + QMap params; + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + url.setParameters(params); + addr.insertCalendarUrl(url); + lst << addr; + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v4_0); + QByteArray expected = QByteArray("BEGIN:VCARD\r\n" + "VERSION:4.0\r\n" + "CALURI;FOO2=bla2,blo2:https://sherlockholmes.com/calendar/sherlockholmes\r\n" + "EMAIL:foo@kde.org\r\n" + "N:;;;;\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + QCOMPARE(ba, expected); +} + +void CalendarUrlTest::shouldNotGeneratedAttributeForVcard3() +{ + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + CalendarUrl url; + url.setType(CalendarUrl::CALUri); + url.setUrl(QUrl(QStringLiteral("https://sherlockholmes.com/calendar/sherlockholmes"))); + QMap params; + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + url.setParameters(params); + addr.insertCalendarUrl(url); + lst << addr; + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v3_0); + QByteArray expected = QByteArray("BEGIN:VCARD\r\n" + "VERSION:3.0\r\n" + "EMAIL:foo@kde.org\r\n" + "N:;;;;\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + QCOMPARE(ba, expected); +} + +void CalendarUrlTest::shouldGenerateMultiCalendarUrl() +{ + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + CalendarUrl url; + url.setType(CalendarUrl::CALUri); + url.setUrl(QUrl(QStringLiteral("https://sherlockholmes.com/calendar/sherlockholmes"))); + QMap params; + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + url.setParameters(params); + addr.insertCalendarUrl(url); + + url.setType(CalendarUrl::FBUrl); + url.setUrl(QUrl(QStringLiteral("https://sherlockholmes.com/calendar/sherlockholmes2"))); + params.clear(); + + params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); + url.setParameters(params); + addr.insertCalendarUrl(url); + + lst << addr; + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v4_0); + QByteArray expected = QByteArray("BEGIN:VCARD\r\n" + "VERSION:4.0\r\n" + "CALURI;FOO2=bla2,blo2:https://sherlockholmes.com/calendar/sherlockholmes\r\n" + "EMAIL:foo@kde.org\r\n" + "FBURL;FOO1=bla1,blo1:https://sherlockholmes.com/calendar/sherlockholmes2\r\n" + "N:;;;;\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + QCOMPARE(ba, expected); + +} + +QTEST_MAIN(CalendarUrlTest) + diff --git a/autotests/calendarurltest.h b/autotests/calendarurltest.h new file mode 100644 index 0000000..418e91d --- /dev/null +++ b/autotests/calendarurltest.h @@ -0,0 +1,47 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2015 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 CALENDARURLTEST_H +#define CALENDARURLTEST_H + +#include + +class CalendarUrlTest : public QObject +{ + Q_OBJECT +public: + explicit CalendarUrlTest(QObject *parent = Q_NULLPTR); + ~CalendarUrlTest(); + +private Q_SLOTS: + void shouldHaveDefaultValue(); + void shouldAssignValue(); + void shouldAssignExternal(); + void shouldSerialized(); + void shouldEqualCalendarUrl(); + void shouldParseCalendarUrl(); + void shouldGenerateVCard_data(); + void shouldGenerateVCard(); + void shouldGenerateVCardWithParameter(); + void shouldNotGeneratedAttributeForVcard3(); + void shouldGenerateMultiCalendarUrl(); +}; + +#endif // CALENDARURLTEST_H diff --git a/autotests/contactgrouptest.cpp b/autotests/contactgrouptest.cpp new file mode 100644 index 0000000..89563db --- /dev/null +++ b/autotests/contactgrouptest.cpp @@ -0,0 +1,385 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2008 Kevin Krammer + + 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 + +#include "kcontacts/contactgroup.h" +#include "kcontacts/contactgrouptool.h" + +#include + +using namespace KContacts; + +class ContactGroupTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void contactGroupContactReference(); + void contactGroupContactGroupReference(); + void contactGroupData(); + void contactGroup(); + void testGroupRoundTrip(); + void testGroupListRoundTrip(); +}; + +QTEST_MAIN(ContactGroupTest) + +void ContactGroupTest::contactGroupContactReference() +{ + const QLatin1String uid("MyReferenceId"); + const QLatin1String gid("GID"); + const QLatin1String preferredEMail("tokoe@kde.org"); + const QLatin1String customKey("MyCustomKey"); + const QLatin1String customValue("MyCustomValue"); + + // uid test + { + ContactGroup::ContactReference ref(uid); + QCOMPARE(ref.uid(), uid); + } + + // uid test + { + ContactGroup::ContactReference ref; + ref.setUid(uid); + QCOMPARE(ref.uid(), uid); + } + + // preferredEmail test + { + ContactGroup::ContactReference ref(uid); + ref.setPreferredEmail(preferredEMail); + QCOMPARE(ref.preferredEmail(), preferredEMail); + } + + // custom test + { + ContactGroup::ContactReference ref(uid); + ref.insertCustom(customKey, customValue); + QCOMPARE(ref.custom(customKey), customValue); + ref.removeCustom(customKey); + QCOMPARE(ref.custom(customKey), QString()); + } + + // assignment test + { + ContactGroup::ContactReference ref(uid); + ref.setGid(gid); + ref.setPreferredEmail(preferredEMail); + ref.insertCustom(customKey, customValue); + + ContactGroup::ContactReference ref2(ref); + QCOMPARE(ref.uid(), ref2.uid()); + QCOMPARE(ref.gid(), ref2.gid()); + QCOMPARE(ref.preferredEmail(), ref2.preferredEmail()); + QCOMPARE(ref.custom(customKey), ref2.custom(customKey)); + + QVERIFY(ref == ref2); + } + + // const test + { + ContactGroup::ContactReference ref(uid); + ref.setPreferredEmail(preferredEMail); + ref.insertCustom(customKey, customValue); + + const ContactGroup::ContactReference constRef(ref); + constRef.uid(); + constRef.preferredEmail(); + constRef.custom(customKey); + constRef.gid(); + } +} + +void ContactGroupTest::contactGroupContactGroupReference() +{ + const QLatin1String uid("MyReferenceId"); + const QLatin1String customKey("MyCustomKey"); + const QLatin1String customValue("MyCustomValue"); + + // uid test + { + ContactGroup::ContactGroupReference ref(uid); + QCOMPARE(ref.uid(), uid); + } + + // uid test + { + ContactGroup::ContactGroupReference ref; + ref.setUid(uid); + QCOMPARE(ref.uid(), uid); + } + + // custom test + { + ContactGroup::ContactGroupReference ref(uid); + ref.insertCustom(customKey, customValue); + QCOMPARE(ref.custom(customKey), customValue); + ref.removeCustom(customKey); + QCOMPARE(ref.custom(customKey), QString()); + } + + // assignment test + { + ContactGroup::ContactGroupReference ref(uid); + ref.insertCustom(customKey, customValue); + + ContactGroup::ContactGroupReference ref2(ref); + QCOMPARE(ref.uid(), ref2.uid()); + QCOMPARE(ref.custom(customKey), ref2.custom(customKey)); + + QVERIFY(ref == ref2); + } + + // const test + { + ContactGroup::ContactGroupReference ref(uid); + ref.insertCustom(customKey, customValue); + + const ContactGroup::ContactGroupReference constRef(ref); + constRef.uid(); + constRef.custom(customKey); + } +} + +void ContactGroupTest::contactGroupData() +{ + const QLatin1String name("Tobias Koenig"); + const QLatin1String email("tokoe@kde.org"); + const QLatin1String customKey("MyCustomKey"); + const QLatin1String customValue("MyCustomValue"); + + // name/email test + { + ContactGroup::Data data(name, email); + QCOMPARE(data.name(), name); + QCOMPARE(data.email(), email); + } + + // name test + { + ContactGroup::Data data; + data.setName(name); + QCOMPARE(data.name(), name); + } + + // email test + { + ContactGroup::Data data; + data.setEmail(email); + QCOMPARE(data.email(), email); + } + + // custom test + { + ContactGroup::Data data(name, email); + data.insertCustom(customKey, customValue); + QCOMPARE(data.custom(customKey), customValue); + data.removeCustom(customKey); + QCOMPARE(data.custom(customKey), QString()); + } + + // assignment test + { + ContactGroup::Data data(name, email); + data.insertCustom(customKey, customValue); + + ContactGroup::Data data2(data); + QCOMPARE(data.name(), data2.name()); + QCOMPARE(data.email(), data2.email()); + QCOMPARE(data.custom(customKey), data2.custom(customKey)); + + QVERIFY(data == data2); + } + + // const test + { + ContactGroup::Data data(name, email); + data.insertCustom(customKey, customValue); + + const ContactGroup::Data constData(data); + constData.name(); + constData.email(); + constData.custom(customKey); + } +} + +void ContactGroupTest::contactGroup() +{ + const QLatin1String groupName("MyGroupName"); + const QLatin1String groupId("MyGroupID"); + const QLatin1String name("Tobias Koenig"); + const QLatin1String email("tokoe@kde.org"); + const QLatin1String uid("MyUid"); + + // name test + { + ContactGroup group(groupName); + QCOMPARE(group.name(), groupName); + } + + // id test + { + ContactGroup group(groupName); + group.setId(groupId); + QCOMPARE(group.id(), groupId); + } + + // contact reference test + { + ContactGroup group(groupName); + QCOMPARE(group.contactReferenceCount(), (unsigned int)0); + + ContactGroup::ContactReference ref(uid); + ref.setPreferredEmail(email); + + group.append(ref); + QCOMPARE(group.contactReferenceCount(), (unsigned int)1); + + const ContactGroup::ContactReference ref2 = group.contactReference(0); + QCOMPARE(ref, ref2); + + group.remove(ref); + QCOMPARE(group.contactReferenceCount(), (unsigned int)0); + } + + // contact group reference test + { + ContactGroup group(groupName); + QCOMPARE(group.contactGroupReferenceCount(), (unsigned int)0); + + ContactGroup::ContactGroupReference ref(uid); + + group.append(ref); + QCOMPARE(group.contactGroupReferenceCount(), (unsigned int)1); + + const ContactGroup::ContactGroupReference ref2 = group.contactGroupReference(0); + QCOMPARE(ref, ref2); + + group.remove(ref); + QCOMPARE(group.contactGroupReferenceCount(), (unsigned int)0); + } + + // data test + { + ContactGroup group(groupName); + QCOMPARE(group.dataCount(), (unsigned int)0); + + ContactGroup::Data data(name, email); + + group.append(data); + QCOMPARE(group.dataCount(), (unsigned int)1); + + const ContactGroup::Data data2 = group.data(0); + QCOMPARE(data, data2); + + group.remove(data); + QCOMPARE(group.dataCount(), (unsigned int)0); + } + + // mimetype test + { + ContactGroup group(groupName); + QCOMPARE(group.mimeType(), QLatin1String("application/x-vnd.kde.contactgroup")); + } +} + +void ContactGroupTest::testGroupRoundTrip() +{ + // TODO should also test empty group + + ContactGroup group(QLatin1String("TestGroup")); + group.append(ContactGroup::ContactReference(QLatin1String("Xggdjetw"))); + ContactGroup::ContactReference gidReference; + gidReference.setGid(QLatin1String("gid")); + group.append(gidReference); + group.append(ContactGroup::ContactGroupReference(QLatin1String("aaXggdjetw"))); + group.append(ContactGroup::Data(QLatin1String("Tobias Koenig"), + QLatin1String("tokoe@kde.org"))); + group.append(ContactGroup::Data(QLatin1String("Kevin Krammer"), + QLatin1String("kevin.krammer@gmx.at"))); + + QBuffer buffer; + buffer.open(QIODevice::WriteOnly); + + QString errorMessage; + bool result = ContactGroupTool::convertToXml(group, &buffer, &errorMessage); + + QVERIFY(result); + QVERIFY(errorMessage.isEmpty()); + buffer.close(); + QVERIFY(buffer.size() > 0); + buffer.open(QIODevice::ReadOnly); + + ContactGroup group2; + result = ContactGroupTool::convertFromXml(&buffer, group2, &errorMessage); + QVERIFY(result); + QVERIFY(errorMessage.isEmpty()); + QCOMPARE(group, group2); +} + +void ContactGroupTest::testGroupListRoundTrip() +{ + // TODO should also test empty list + + ContactGroup::List list; + + ContactGroup group1(QLatin1String("TestGroup1")); + group1.append(ContactGroup::ContactReference(QLatin1String("Xggdjetw"))); + group1.append(ContactGroup::Data(QLatin1String("Tobias Koenig"), + QLatin1String("tokoe@kde.org"))); + group1.append(ContactGroup::Data(QLatin1String("Kevin Krammer"), + QLatin1String("kevin.krammer@gmx.at"))); + + list.append(group1); + + ContactGroup group2(QLatin1String("TestGroup2")); + group2.append(ContactGroup::ContactReference(QLatin1String("Xggdjetw"))); + group2.append(ContactGroup::Data(QLatin1String("Tobias Koenig"), + QLatin1String("tokoe@kde.org"))); + group2.append(ContactGroup::Data(QLatin1String("Kevin Krammer"), + QLatin1String("kevin.krammer@gmx.at"))); + + list.append(group2); + + QBuffer buffer; + buffer.open(QIODevice::WriteOnly); + + QString errorMessage; + bool result = ContactGroupTool::convertToXml(list, &buffer, &errorMessage); + + QVERIFY(result); + QVERIFY(errorMessage.isEmpty()); + buffer.close(); + QVERIFY(buffer.size() > 0); + + buffer.open(QIODevice::ReadOnly); + + ContactGroup::List list2; + result = ContactGroupTool::convertFromXml(&buffer, list2, &errorMessage); + QVERIFY(result); + QVERIFY(errorMessage.isEmpty()); + QVERIFY(list2.size() == 2); + QCOMPARE(list2[0], group1); + QCOMPARE(list2[1], group2); +} + +#include "contactgrouptest.moc" diff --git a/autotests/data/v4_0.vcard1.vcf.ref b/autotests/data/v4_0.vcard1.vcf.ref new file mode 100644 index 0000000..41030ef --- /dev/null +++ b/autotests/data/v4_0.vcard1.vcf.ref @@ -0,0 +1,15 @@ +BEGIN:VCARD +VERSION:4.0 +ADR;TYPE=parcel;TYPE=postal;TYPE=work:;;6544 Battleford Drive;Raleigh;NC;27 + 613-3502;U.S.A. +EMAIL;TYPE=PREF:Frank_Dawson@Lotus.com +EMAIL:fdawson@earthlink.net +FN:Frank Dawson +N:;;;; +ORG:Lotus Development Corporation +TEL;TYPE=MSG;TYPE=VOICE;TYPE=WORK:+1-919-676-9515 +TEL;TYPE=FAX;TYPE=WORK:+1-919-676-9564 +UID:gDVbA6LY3t +URL:http://home.earthlink.net/~fdawson +END:VCARD + diff --git a/autotests/data/v4_0.vcard2.vcf.ref b/autotests/data/v4_0.vcard2.vcf.ref new file mode 100644 index 0000000..446da45 --- /dev/null +++ b/autotests/data/v4_0.vcard2.vcf.ref @@ -0,0 +1,12 @@ +BEGIN:VCARD +VERSION:4.0 +ADR;TYPE=work:;;501 E. Middlefield Rd.;Mountain View;CA; 94043;U.S.A. +EMAIL:howes@netscape.com +FN:Tim Howes +N:;;;; +ORG:Netscape Communications Corp. +TEL;TYPE=MSG;TYPE=VOICE;TYPE=WORK:+1-415-937-3419 +TEL;TYPE=FAX;TYPE=WORK:+1-415-528-4164 +UID:1UgvYejJMs +END:VCARD + diff --git a/autotests/data/v4_0.vcard3.vcf.ref b/autotests/data/v4_0.vcard3.vcf.ref new file mode 100644 index 0000000..b91a5d7 --- /dev/null +++ b/autotests/data/v4_0.vcard3.vcf.ref @@ -0,0 +1,12 @@ +BEGIN:VCARD +VERSION:4.0 +EMAIL:geiseri@yahoo.com +FN:ian geiser +N:geiser;ian;;; +ORG:Source eXtreme +TITLE:VP of Engineering +UID:ebvq9Wo9rO +X-mozilla-cpt:;0 +X-mozilla-html:FALSE +END:VCARD + diff --git a/autotests/data/v4_0.vcard4.vcf.ref b/autotests/data/v4_0.vcard4.vcf.ref new file mode 100644 index 0000000..5e628d3 --- /dev/null +++ b/autotests/data/v4_0.vcard4.vcf.ref @@ -0,0 +1,14 @@ +BEGIN:VCARD +VERSION:4.0 +EMAIL:hello@ximian.com +FN: +LABEL;TYPE=work:401 Park Drive 3 West\nBoston\, MA 02215\nUSA +NOTE:Welcome to the Ximian Addressbook. +ORG:Ximian\, Inc. +TEL;TYPE=VOICE;TYPE=WORK:(617) 236-0442 +TEL;TYPE=FAX;TYPE=WORK:(617) 236-8630 +UID:pas-id-3E136F9B00000000 +URL:www.ximian.com/ +X-EVOLUTION-FILE-AS:Ximian\, Inc. +END:VCARD + diff --git a/autotests/data/v4_0.vcard5.vcf.ref b/autotests/data/v4_0.vcard5.vcf.ref new file mode 100644 index 0000000..10f6749 --- /dev/null +++ b/autotests/data/v4_0.vcard5.vcf.ref @@ -0,0 +1,313 @@ +BEGIN:VCARD +VERSION:4.0 +ADR;TYPE=home;TYPE=pref:;;Buehlauer Strasse 45;Dresden;Sachsen;01327;German + y +ADR;TYPE=work:;;Prager Strasse 55;Dresden;Sachsen;01066;Germany +BDAY:1955-07-19T00:00:00Z +CATEGORIES:Friend +CLASS:CONFIDENTIAL +EMAIL;TYPE=PREF:heiko.mustermann@freenet.org +EMAIL:heiko8@tst.inf.tu-dresden.de +FN:Mustermann\, Heiko +GEO:19.283333;166.616669 +LOGO;ENCODING=b;TYPE=image/png:iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVU + AAAOW0lEQVR4nO1df2hb1xX+OlyQwQEJXJAgBQlaiEwDsdqO2l1H47RjMe2gbjOoszG2dozG7aC + YMIqTjS7NYKSmbE1StsQpWxMXmsSF1WhlTeSwJlZY06gsSVXWUAkakKAGPajBDxrQ/jjnez8k27 + EjJdyU+/0jPz29X9L57jnnO+deAxYWFhYWFhYWFu3Hbe082XT2ZF3+WgAAdHZ0AgBqTg0A4H7DT + 7oAgNSdKQDAg99/sK33caPB53RqFQBA5PYIAMBdkOf6yc9+ct3P852W786irWjJMs/8+0wdACpV + sZTS50V5vSLb1UoVQMCCvnFDx0c65f3BHw4CABJ3RL19mwYfM4Y1e/+0V5h/VbbPXzwPACiVSgA + A15XnikVjAIB44Dli3TIKjL+2e0XPYxliGFZshSdzZ+r8OyKGjdl8AQCQfe84AKBaFUaUrojlRL + vEUpx5h0eGjo9EZH+kQ7Yz9/d71+vdkAYApO+W16d+/NQNZ8ye8T11ACiV5TkcR5jufCX3XyrLc + 9XmxUe6bvi5XH3OaNRnSKRL9vWsywAAstNTyz6HZYhhsD+IYbjmMPDxfz6uA0BMqQcAR96eAgBM + vSevtTkJa6tzQnVSNn2XOLSZ03ljHHQ7MLxlSIa2kg5pOrTVHHHu/hANRDrke4t2y3cy+KgEMPs + P7F/0O7EMMQzXtNxLn16qA8DUu1nvvcm3DgEAFlxxbo4jFpFYK4woXix8qxhxLYxuH6sDQG5Gvq + NSueLtcxwdNTTASemoUTi3+HdkGWIYlrTkj2clzC1ckGRv3xv7vH2VK7QAlUDuktA0f/bG+YpL5 + 4WpDDXv7TdPbjm472AdACbe9L+r4mdMHuW+42uTAIByuWwZciugY6kdER3zzn8iMkFt3pc93Kvy + d0QzvHYxI5h8Qq/BiK1YLur78nJw4mBIznj2V88ueg+HjxyrA0BEdE7EumLePp773u/e25b7jyb + kfAObh7z3SleELS40SVZ/u+2F0ToA7H99PHRtyxDD0GQZZ9RKKxUZ+/YdmAAAFD4peJ9hbF2dq7 + aHGSpn12p+dJI7PQsAcDS3YcxfmZPXnrt65F40P+pd3wsgwF69x/xHedlWNkfX+PlUep0ck0omA + ACxO+R10w82tfRch8leAJOas82ek+cho/sfkGtnT8xYhpiMJh9CiytVZayjYIgO37KCmWgrOPy3 + w3UAKKpsf/zd496+wkVhpOu5Lje0XS6X9X5lbJ49KxZIJqSSEu+Xrsj9V1Xw5OcBIPJBDoCfPw0 + 9IVn0sanpOgA8NXR9JYBILO7/rd8n/RV9SM1tPg6wDDEOTQxhFEKLYjbuBljBX9tjzyox/Q+xQO + crOf7I20cAAIVz+cCnVNJu8Alo3Nb43nEjoSfa8dIOAMDs6Zy+3wcAyM3kvCtUyZ6qXLd0WZj6z + E+fAeAX4FZbYo5Fmt9zXfeanwEsQ4xDE0Nqbi203ZhztANVZUb2PdF+imqZLgLX0OvSd7lLbPO+ + OFan1B8wGotEE3pCYfpWtX4A2L1rZ+gcHN+Pa8EtEpX3mR9tGlieKSf/dVJ9Ysl7j/fhMYTfuDa + ANMIyxDA0Z+r6Qy7MC1Mi3lge1PijTYetBNNTkjUfOjQJAMi+LzE6S7nJtX50krknE74hZQZbij + o19U7eKcfQAKuaP7lam+hRdZXl19kZX7Xe+PBG2acM7YzE9Bpi1UfeFN9G7Y6+77EfLR59UdGtV + X2G8D7IEPrf7PtZq2XdCmhiCBsUYnGxLJfxP5rzkI0Pb6wDwMypmWXHVupOk0eFEfQZIy+MAQB6 + 79OGhnSvd0yk4c5o4c7Xamlrwj7Nqck9uVf5eblGVnONqIY1W38+4h3DyJH1i6j6jFi3+B1GaPm + 8RGFsa9qrqu7zI6KfHXtHmM8KKq8ZfNZg/rMcLEMMQ5NlH/zLwVDz28SbomVRUxI0RDZJZrqici + biYmHFz8Q6cmox6bR8bsfOVwD44ylzH47dgK9lTf5dqpOzZ0V1Hnh0AIDfXMdmO7Zx0h8MaO2aT + JtQf7D16Se9a9CS0+uEofQVmV7ZjqhPmXhrIvQcnV2doeemv6UfIysAeNoVg9TMfdLqZH3ILYIl + x36Oi/v+Knp+/mwhsFfHcR0X2W3Su0Gy4ZrG3tU5GaOHtwhzXv3jqwB8ZgFiaezamFVWAMDO30u + OQAsjfvFL8QHpdFLOoPE8FQXG99UvxecMbhameOrCnB8tbh0WtjA3IZuYl6TXC1PoY/b9eRwAUL + hYDH3emXdD20EwX4p3SzS4VKWQsAwxDPYHMQxLlnDpJNlbSyEO8BvjvDKrJnZFlcxJ+biGkRT6Y + nf45VMAqHypXfMa0uY+8JM2Fpycr+QzfQ+JM0+nhPoMBHit3FFxuHT6FB8rGsYnusWZVsoBAVOH + QzrlkoqlcW1qSyQkOMmsE+c9sk2Gy+d//Xzo+Ago40RD3wsARKMrG6oIyxDDsCRDOAtodLsU44M + d3QtXKcnzLGELoXN7cos4y3jcl0QAYOFrOZ4ySLGooWqgOYBs4XVp+Qw9i2XZX1GyZtIJvQdhRi + Il23S4ntgYSNB67xcWTs2ouDmn97FRrlX6MlzUSt8jo8XQlq0AgMm3J8Ln1OfmnBBg9U2DliGGY + UmGEON7pE1lVNtWAGD2IwlPK1fF6jhziGMxE8eR54QhnWtUatY5hpS5ixfCPmexsDHRLedOeDK6 + YOARsdLxabHqVJIiozbvqQzvsZnvJ33r7dkgfuXQBWHC6NMSIrvqZ+grOTOsX+evPLlZRMlCXsv + GGsZn1osgOt7Q2rMaWIYYhmsyhAj+6tue2ybNZ59ruVfl5k614igL+90NvoNz9LT5jkJgKiVWS5 + 8CAOVSGYAv9FU0eezXaItsHHkkCQBI360RnDKBzODx7iKNGcPa1FCZk3JArZzT53FC5yB4DxGN8 + IY04d3+m+23AcDMqZmma6wWliGGYcUMCWL/G+HJJsNbhkPtPBxrGwv5pcufAgDcrzlPXayX430w + D2GMTx/CQlkqqUzokGO8MpZGUwtagqbASTAScuZ8ATOVlGa7wT6Jnnb/QacTaO4CFR0JFsXiiXj + oGrte3lUHgJ2/29ly46BliGG4LoY0YvLoZMgyjr9zXCKyTrEozuemsEfRjtEZfUq+4MvWjFxojd + ympTNqamq+iKjP8LJlln6VGQGxkj4hpS2lbJYeXC++xZuQpOxjO2hCi3f0lSxVtAOWIYahLQxpB + KXmijJjQed1R9nbptbNAhbbgRBoQYomxAobW0M5jvuWrpGQRj7MyFlsYg6RSDCS863ZnZf3EmuF + VcNPDMv9/FNKsfsPHAoxf/RFmbpWLLBtVa5JNvY90FcHWpueYRliGNrKkC/+90Ud8EucLjR7dtQ + 3qALLaCz7vsT9nO6V7vVXcqBi6jYUqHB7wyvCDWccz6kGpFU1ZqNCENWaKAWOMjZzn8RsbOTDgU + Ohz690vZJWYBliGNr6i1/6r0zM9LQqVXGZI3yqeQjfZ4ae2SCWyaY3QbhldOB7kqHHEuGaSiNe+ + a3UXlh2zeiaKYOPS7nW19uA8dekPB3TXGf0xVEAgXKv1oCok+VOCcs2DbY2oWc5WIYYhrb4kOms + tFgWL0tUlf9QNB0ygcwoXw5XzQY3D9YBIK7M4MQZwM87HM1dSmzP1KgrFgv7joUFNjlwqSF5efV + 1YUHurFj32PYx75gdL+uUhbyuf6UZeq9WFznJv6KqL33fjYRliGFoiSGc0FLUxQW8VsolmsAa4U + VCSRnng1PlqBPFNO/gKnVs76RP6WRuo35q6HHJsqkKsPZOto7v2e1dY+QF8RkDfaqIdZCVmsOo+ + swIjbX/GwnLEMPQEkPatZoomdE47QsAoHX6aDRcm+B4X/K6YbT+oYxg/ZttopzKxsmhgF8zrzR0 + 0bDjhp/l8iL508s3lbcDliGGwf4ghsGIFXWONaxHAvgrDMVUhmGLEfuA4xoiT70rgQQdrteBr6X + bktcoF94G/GY6hrO5U9pipAEAz1mttmfFipXAMsQw3BD5fbVwuJbUGl868UJMXdNEa0eIdocLUJ + wH8souSfI8eV7DYcr2lPqDgUNlPtzKSqawIMXQ+3rn418PLEMMgxE+hNirCxkDQK82SrgqBqY5K + 1eZUanK+94ahrpaUfGCyCCDm0VMpDBImb4SaHKgD/FWFVVmMGFl6Tl3Qgpok0eXXwS5HbAMMQxG + MSSIsZekXNp7v8zKymzo0T26WpHO42MjNxsmGHWx6a6/rz/0uWDBi+coFJRdnDHLiI4rTqxQCmo + HLEMMgxFR1mJgMOQ1YHO7S14b1zQhQ5iHsLXoiM6g9SbTICDPdIRbiLw5kyqpNK72djNgGWIYjG + VIPB5e+cBrauvSdh5tGWKbEHMJFrn6HxDf0bNOfE+Na7cEWaFPT+m+oNMjip9J/pE90Xrz9GphG + WIYjGUIW/zZyMysOcrGuTjXVAwXjbgST0WjKbZ70nXkC77VFy9r/jEXZteC077W0NXCMsQwGJuH + NGJsp+QlfZqXsHWHKi4n1xS0YZvToWc+lPLr+U+k2BSqgV31MnNjvgfLEMNgjGWsFFytiM3WcZW + BOUWgoj6kqv/Ii00RXBm7GljViBFXwaD/d2IZYhiMjbKWgreUhlb3OAFz4CHZz6aGWHd4hTnHFc + WWjeBAeJKpKbAMMQy3HEO45Mfecfl3qNSyuB5iRtt/XP43hK5w3nK+4rcBNa7FZQIsQwyDMdFFq + xh9UZb+6HtIlr1wF8SHFM6JPsVGueDiMzej8W21sAwxDPYHMQy3nFNfCmltrKuWRDrhv0HlUMWV + 8Rrn1JsGyxDDYLS1XA927ZZWooL+MzC29sycuHmNCq3AMsQwfGt8CFHISwEqskbDWwPlkeVgGWJ + xczH20lidTXe3AixDLCwsLCwsviX4P68/8cprSSqmAAAAAElFTkSuQmCC +N:Mustermann;Heiko;;; +NICKNAME:clown +NOTE:I'm a friendly note text\,\nplease copy me to your address book... +ORG:KDE +PHOTO;ENCODING=b;TYPE=image/png:iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pV + UAAAOW0lEQVR4nO1df2hb1xX+OlyQwQEJXJAgBQlaiEwDsdqO2l1H47RjMe2gbjOoszG2dozG7a + CYMIqTjS7NYKSmbE1StsQpWxMXmsSF1WhlTeSwJlZY06gsSVXWUAkakKAGPajBDxrQ/jjnez8k2 + 7EjJdyU+/0jPz29X9L57jnnO+deAxYWFhYWFhYWFu3Hbe082XT2ZF3+WgAAdHZ0AgBqTg0A4H7D + T7oAgNSdKQDAg99/sK33caPB53RqFQBA5PYIAMBdkOf6yc9+ct3P852W786irWjJMs/8+0wdACp + VsZTS50V5vSLb1UoVQMCCvnFDx0c65f3BHw4CABJ3RL19mwYfM4Y1e/+0V5h/VbbPXzwPACiVSg + AA15XnikVjAIB44Dli3TIKjL+2e0XPYxliGFZshSdzZ+r8OyKGjdl8AQCQfe84AKBaFUaUrojlR + LvEUpx5h0eGjo9EZH+kQ7Yz9/d71+vdkAYApO+W16d+/NQNZ8ye8T11ACiV5TkcR5jufCX3XyrL + c9XmxUe6bvi5XH3OaNRnSKRL9vWsywAAstNTyz6HZYhhsD+IYbjmMPDxfz6uA0BMqQcAR96eAgB + MvSevtTkJa6tzQnVSNn2XOLSZ03ljHHQ7MLxlSIa2kg5pOrTVHHHu/hANRDrke4t2y3cy+KgEMP + sP7F/0O7EMMQzXtNxLn16qA8DUu1nvvcm3DgEAFlxxbo4jFpFYK4woXix8qxhxLYxuH6sDQG5Gv + qNSueLtcxwdNTTASemoUTi3+HdkGWIYlrTkj2clzC1ckGRv3xv7vH2VK7QAlUDuktA0f/bG+YpL + 54WpDDXv7TdPbjm472AdACbe9L+r4mdMHuW+42uTAIByuWwZciugY6kdER3zzn8iMkFt3pc93Kv + yd0QzvHYxI5h8Qq/BiK1YLur78nJw4mBIznj2V88ueg+HjxyrA0BEdE7EumLePp773u/e25b7jy + bkfAObh7z3SleELS40SVZ/u+2F0ToA7H99PHRtyxDD0GQZZ9RKKxUZ+/YdmAAAFD4peJ9hbF2dq + 7aHGSpn12p+dJI7PQsAcDS3YcxfmZPXnrt65F40P+pd3wsgwF69x/xHedlWNkfX+PlUep0ck0om + AACxO+R10w82tfRch8leAJOas82ek+cho/sfkGtnT8xYhpiMJh9CiytVZayjYIgO37KCmWgrOPy + 3w3UAKKpsf/zd496+wkVhpOu5Lje0XS6X9X5lbJ49KxZIJqSSEu+Xrsj9V1Xw5OcBIPJBDoCfPw + 09IVn0sanpOgA8NXR9JYBILO7/rd8n/RV9SM1tPg6wDDEOTQxhFEKLYjbuBljBX9tjzyox/Q+xQ + OcrOf7I20cAAIVz+cCnVNJu8Alo3Nb43nEjoSfa8dIOAMDs6Zy+3wcAyM3kvCtUyZ6qXLd0WZj6 + zE+fAeAX4FZbYo5Fmt9zXfeanwEsQ4xDE0Nqbi203ZhztANVZUb2PdF+imqZLgLX0OvSd7lLbPO + +OFan1B8wGotEE3pCYfpWtX4A2L1rZ+gcHN+Pa8EtEpX3mR9tGlieKSf/dVJ9Ysl7j/fhMYTfuD + aANMIyxDA0Z+r6Qy7MC1Mi3lge1PijTYetBNNTkjUfOjQJAMi+LzE6S7nJtX50krknE74hZQZbi + jo19U7eKcfQAKuaP7lam+hRdZXl19kZX7Xe+PBG2acM7YzE9Bpi1UfeFN9G7Y6+77EfLR59UdGt + VX2G8D7IEPrf7PtZq2XdCmhiCBsUYnGxLJfxP5rzkI0Pb6wDwMypmWXHVupOk0eFEfQZIy+MAQB + 679OGhnSvd0yk4c5o4c7Xamlrwj7Nqck9uVf5eblGVnONqIY1W38+4h3DyJH1i6j6jFi3+B1GaP + m8RGFsa9qrqu7zI6KfHXtHmM8KKq8ZfNZg/rMcLEMMQ5NlH/zLwVDz28SbomVRUxI0RDZJZrqic + ibiYmHFz8Q6cmox6bR8bsfOVwD44ylzH47dgK9lTf5dqpOzZ0V1Hnh0AIDfXMdmO7Zx0h8MaO2a + TJtQf7D16Se9a9CS0+uEofQVmV7ZjqhPmXhrIvQcnV2doeemv6UfIysAeNoVg9TMfdLqZH3ILYI + lx36Oi/v+Knp+/mwhsFfHcR0X2W3Su0Gy4ZrG3tU5GaOHtwhzXv3jqwB8ZgFiaezamFVWAMDO30 + uOQAsjfvFL8QHpdFLOoPE8FQXG99UvxecMbhameOrCnB8tbh0WtjA3IZuYl6TXC1PoY/b9eRwAU + LhYDH3emXdD20EwX4p3SzS4VKWQsAwxDPYHMQxLlnDpJNlbSyEO8BvjvDKrJnZFlcxJ+biGkRT6 + Ynf45VMAqHypXfMa0uY+8JM2Fpycr+QzfQ+JM0+nhPoMBHit3FFxuHT6FB8rGsYnusWZVsoBAVO + HQzrlkoqlcW1qSyQkOMmsE+c9sk2Gy+d//Xzo+Ago40RD3wsARKMrG6oIyxDDsCRDOAtodLsU44 + Md3QtXKcnzLGELoXN7cos4y3jcl0QAYOFrOZ4ySLGooWqgOYBs4XVp+Qw9i2XZX1GyZtIJvQdhR + iIl23S4ntgYSNB67xcWTs2ouDmn97FRrlX6MlzUSt8jo8XQlq0AgMm3J8Ln1OfmnBBg9U2DliGG + YUmGEON7pE1lVNtWAGD2IwlPK1fF6jhziGMxE8eR54QhnWtUatY5hpS5ixfCPmexsDHRLedOeDK + 6YOARsdLxabHqVJIiozbvqQzvsZnvJ33r7dkgfuXQBWHC6NMSIrvqZ+grOTOsX+evPLlZRMlCXs + vGGsZn1osgOt7Q2rMaWIYYhmsyhAj+6tue2ybNZ59ruVfl5k614igL+90NvoNz9LT5jkJgKiVWS + 58CAOVSGYAv9FU0eezXaItsHHkkCQBI360RnDKBzODx7iKNGcPa1FCZk3JArZzT53FC5yB4DxGN + 8IY04d3+m+23AcDMqZmma6wWliGGYcUMCWL/G+HJJsNbhkPtPBxrGwv5pcufAgDcrzlPXayX430 + wD2GMTx/CQlkqqUzokGO8MpZGUwtagqbASTAScuZ8ATOVlGa7wT6Jnnb/QacTaO4CFR0JFsXiiX + joGrte3lUHgJ2/29ly46BliGG4LoY0YvLoZMgyjr9zXCKyTrEozuemsEfRjtEZfUq+4MvWjFxoj + dympTNqamq+iKjP8LJlln6VGQGxkj4hpS2lbJYeXC++xZuQpOxjO2hCi3f0lSxVtAOWIYahLQxp + BKXmijJjQed1R9nbptbNAhbbgRBoQYomxAobW0M5jvuWrpGQRj7MyFlsYg6RSDCS863ZnZf3Emu + FVcNPDMv9/FNKsfsPHAoxf/RFmbpWLLBtVa5JNvY90FcHWpueYRliGNrKkC/+90Ud8EucLjR7dt + Q3qALLaCz7vsT9nO6V7vVXcqBi6jYUqHB7wyvCDWccz6kGpFU1ZqNCENWaKAWOMjZzn8RsbOTDg + UOhz690vZJWYBliGNr6i1/6r0zM9LQqVXGZI3yqeQjfZ4ae2SCWyaY3QbhldOB7kqHHEuGaSiNe + +a3UXlh2zeiaKYOPS7nW19uA8dekPB3TXGf0xVEAgXKv1oCok+VOCcs2DbY2oWc5WIYYhrb4kOm + stFgWL0tUlf9QNB0ygcwoXw5XzQY3D9YBIK7M4MQZwM87HM1dSmzP1KgrFgv7joUFNjlwqSF5ef + V1YUHurFj32PYx75gdL+uUhbyuf6UZeq9WFznJv6KqL33fjYRliGFoiSGc0FLUxQW8VsolmsAa4 + UVCSRnng1PlqBPFNO/gKnVs76RP6WRuo35q6HHJsqkKsPZOto7v2e1dY+QF8RkDfaqIdZCVmsOo + +swIjbX/GwnLEMPQEkPatZoomdE47QsAoHX6aDRcm+B4X/K6YbT+oYxg/ZttopzKxsmhgF8zrzR + 00bDjhp/l8iL508s3lbcDliGGwf4ghsGIFXWONaxHAvgrDMVUhmGLEfuA4xoiT70rgQQdrteBr6 + XbktcoF94G/GY6hrO5U9pipAEAz1mttmfFipXAMsQw3BD5fbVwuJbUGl868UJMXdNEa0eIdocLU + JwH8souSfI8eV7DYcr2lPqDgUNlPtzKSqawIMXQ+3rn418PLEMMgxE+hNirCxkDQK82SrgqBqY5 + K1eZUanK+94ahrpaUfGCyCCDm0VMpDBImb4SaHKgD/FWFVVmMGFl6Tl3Qgpok0eXXwS5HbAMMQx + GMSSIsZekXNp7v8zKymzo0T26WpHO42MjNxsmGHWx6a6/rz/0uWDBi+coFJRdnDHLiI4rTqxQCm + oHLEMMgxFR1mJgMOQ1YHO7S14b1zQhQ5iHsLXoiM6g9SbTICDPdIRbiLw5kyqpNK72djNgGWIYj + GVIPB5e+cBrauvSdh5tGWKbEHMJFrn6HxDf0bNOfE+Na7cEWaFPT+m+oNMjip9J/pE90Xrz9Gph + GWIYjGUIW/zZyMysOcrGuTjXVAwXjbgST0WjKbZ70nXkC77VFy9r/jEXZteC077W0NXCMsQwGJu + HNGJsp+QlfZqXsHWHKi4n1xS0YZvToWc+lPLr+U+k2BSqgV31MnNjvgfLEMNgjGWsFFytiM3WcZ + WBOUWgoj6kqv/Ii00RXBm7GljViBFXwaD/d2IZYhiMjbKWgreUhlb3OAFz4CHZz6aGWHd4hTnHF + cWWjeBAeJKpKbAMMQy3HEO45Mfecfl3qNSyuB5iRtt/XP43hK5w3nK+4rcBNa7FZQIsQwyDMdFF + qxh9UZb+6HtIlr1wF8SHFM6JPsVGueDiMzej8W21sAwxDPYHMQy3nFNfCmltrKuWRDrhv0HlUMW + V8Rrn1JsGyxDDYLS1XA927ZZWooL+MzC29sycuHmNCq3AMsQwfGt8CFHISwEqskbDWwPlkeVgGW + JxczH20lidTXe3AixDLCwsLCwsviX4P68/8cprSSqmAAAAAElFTkSuQmCC +ROLE:Developer +SOUND;ENCODING=b:UklGRiQgAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQAgAA + B/f39/f39/f39/f39/f4B/gH+Af4CAgIGBgYGBgYGBgYGBgYGBgYGBgIGAgICBgYGBgYGBgYCAg + YGAgICAgICAgIGBgICAgYCAgICBgICAgICAgICAgIGAgICAgYCAgICAgICAgICAgICAgICAgICA + gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC + AgICAgICAf4CAgICAgICAgICAgICAgIB/f4CAgICAgICAgIB/f4B/f39/f39/f3+AgICAf4CAf3 + 9/gIB/f4CAgH9/gICAgH+AgICAgICAgICAf4CAgIB/gICAgICAgICAgICAgICAgICAgICAgICAg + ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA + gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC + AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI + CAgICAgICAgICAgICAgICAgIB/gICAf39/f39/f3+Af4CAgICAgICAgICAgICAgICAgICAgICAg + ICAgICAgICAgICAgH9/f39/f39/f39/f39/f4CAgICAgICAgICAgICAgICAgICAgICAgICAgICA + gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC + AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI + CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg + ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA + gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC + AgICAgICAgICAgIGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYCAgICAgICAgI + CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg + ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA + gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC + AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI + CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg + ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA + gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC + AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI + CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg + ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgYCAgICB + gICAgYGBgICAgICAgICAgIGAgICBgICBgYGBgYGBgYGAgYGBgYCBgYGBgYGBgYGBgYGBgYGBgYG + BgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgICAgYGBgIGBgYGAgI + CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg + ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYGAgICAgICAgICAgICAgICAgICAgICA + gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC + AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI + CAgICAgICAgICAgICAgICAgH+AgICAgICAgICAgICAgICAgICAf4CAgIB/gH+Af4B/f39/f39/f + 39/f39/f4CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA + gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgYG + BgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgY + GBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGAgIGBgYCAgICBgYCAgYGBgYCAgICBg + YCAgICAgICAgICAgICAgIGAgICAgICAgICAgICAgYGBgYGAgICAgIGBgYCAgICBgYGAgICAgIGA + gICAgICAgIGBgYCBgYGAgYGBgYGBgoGBgYGCgoGAgICBgYGBgYCBgYKCgYGBgYGBgYGAgYGBgH9 + /gIB/f3+AgIB/gH9/gICAf4CBgYB/f35+gIB/f4CBgX9/gYCAgYKCgYCAgYOBgICAgoGAf4GCgn + 9/gIB/gICBgH5/f4GAfX+BgYB+fn9/fn+Afn6Af39+f35+fn9+fn6AgH9/f4CAgYCAgYKCgH9/g + IKBf3+AgYJ/f4GCg4F/gIGCgoOBfoCDgYF/fH+BgYGAfn6Af4CCgn58gIN/fX+AgICBgYGAgYCB + goOCgICBgYB/fXyBhIGAgH5+f4GBgX9/f35+gIKCgXt9goN/f318f4GAf4B/fHt9fn5+fXx+fn5 + /gH9+fHx/gHx9f4CAfn18gIB9e4GBfn5+foCBfHyAgoGAfX6CgYCBgH+DgHt9gYN/fX2BhYB7en + 6AgH98foKCgH18foCAfoCAf4CAf31+fn+AgH1+goJ/fX5/gIKAgIGAfH6CgX17foCBf3+BgoB/g + YOBgIB/f4KDgoJ+e3+ChIOBfn1/gX+BfX2BgH59foCCfn1/gX99fICAgoB/f39/gISCf36AgoSB + foCBgYGAf4CCf4CCgX5/gYKDgYB/gH+BhIOBgYB/gIOEhIF9foGCg4OBgICBgoOCgICChIOBg4O + CgoSDgoKAgYKBgoODhISBf4CCg4SEgoGCg4SEgH6BhIWEgX+EhYKAgoKFhIB+gIKChYKAgYOCgo + B+gYWFhIKAg4WEg4ODhIWFhYaGhIWGhYWGh4eHhYOCgoSFg4B/gIB+fX1+fn57e3t7fHt6fH5/f + 4GDhYiMkJGQj5GVmZycmZiXlZGIfXRwcnZ4d3Nva2hoamppaWxvc3R0dXl+iJCPjZShqrCzvNHi + rFYxOmKSrJ6UmJOAbV1ZboSMjI6JfnNjW2JweYGFg4B/e3Z0c3Btc3p9fHp4fIGBf3+Dh4qLjJG + YnZuWkY6MhnpwbnN6fHlya2hlZmdmaW9ycXFzd3t/g42cpquzvMzd/sRADiBZkL6xpLa1jFpANV + iHoJ2ioJWGbEQ2VHaOm5aHhIFuYmZzgoVxZFxfdJCSgnt/kKewr7bDsopcSV6JopyRjpOQfmNXZ + HmGhYB8fXtvXExKXnyKgnJsc3t8fZC0ysfK0+vHTxEeXY6yr6rAxJRSNTdbh5+fp7KjglQ6PVx3 + ho6Ph3dmW15oa2x0hIuNkK3R18jJ0Ys8LUlxkqais8WtdlBFT2yDjpywro9mS0VVaXaBiIdyX2J + rcG5udYKKjaXT4dfV2Y82JkBpiaKkvdO2eE9GTGZ4hZu6u51yTUNOX2l9kZWKdl5PXG93dHeAip + KZut7j2tacRjJIYHCOo77XvoRdVlFYZniVuL+kfl9ST1Rcb4mTjoNxW1pqdXd5fH6CiKHN4d7k2 + 4E4N05Yaoqo1eO0emVbTU5ZdKDCuZV9b1tMSVlyiYp8dHl7cmpqdYCCgIqixNTR2OqnRTlPXFt3 + ksbnw4lzcFdKS2KMtLWZiIZwV0lPZXZ1b3uNinZqbXJ3dX2XxOPg4/zDUDRCTUhmiMXx1p+If1g + +O1J7pK+yspN3W0pGVGdugYmCen54b21rb3V9i6vZ7vD92WpAS0gzSny04tq3qp5qPDhHX3uVrs + KukXVhT0hRYnF/gnuCh31ubG9zdHeMs+Dr8P7KalFVOylJeq7QzMPIqmtIRUZOY4KovqicknhZS + 1BWXWh6gIeLiH91b21vc4GcyuXt/umTZGhGIjJfh6y+yt7LkGlfTD1GYYOipKKwnXhkXldVUFhs + dYOMjYWBem9ucoCWvNTm9+2weHdZMSpQboujvtnUrY6BZEdDUmV4jZypppeFd2dcWVFWWWh8hYS + Ii393c3Z7iJ3A1ePp3aGDfVYyOVZkfJe5zsavpJNsU1BTVmR9kpmcn5uGdGxoWU5VVGZ0fIKLh4 + F/d3Z6g4ufuc3e3depjoViPz9VWm2FqLu8tLGifmphWlJZbH+Lj5+elod+c19WU0xUZW11gISEg + nx6e3h6g4qWp7zM3NrSpZGIYkRFVVVlfZ6vsbW3qIl7b2BUWGVwe4ybn52TkIRuX2BVRVFjZmp7 + hIF9fX12cnZ6eX6LlZyousfP0c++jot6X0ZRXF9sgaCnqa6yn4eAdGZZYGlvd4mcnqCWnY91aWN + cSUtYYmJxf399f351cXFzcHF4foOIlZ+hp7CytLm8uLKNg4RtYF5oanN8j5qZnqGaioV9dGpqb3 + J1f42Rk5iZjIKAcmFcW1RXYGhwdXt+e3Z2c25tcXJxd3yChY2Tl5udn6Gho6ioq6uonoaHbWNzZ + GdxgoGPlZqdj5CJgHFzcWxwdH1/hYqOioSFfnFpaWBdX2Jqb3N5fHh4eHNxcXFxc3d7foOJjI6Q + lZOSlZOTl5eYnJucnpyZkYiEfnd1dnZ5fYKHio6QkIyHg394dHRzc3Z5fHt2enJrcG5obG9sbW9 + ucHJzdnh3eXp5eXt9foCDhoeJjI6OkJGSk5aYmZudn6Gjn5qLh4J3cnJ0dHR5g4GEi42Ih4aBfH + h4dXR1eHl4dXhuaW5rZ2ltaWttbW5vcnR1dHZ2dXV2d3d7fn+BhIeIiYuOjpCTlJWZnJueoKarr + ZuJhntvaW1ucnh+hIWJi4qFg4F7d3V1c3R3fH1/gHlvbXJnXmdpYmdtamtxcW9vbm9tamxtbG5z + dXZ5fHx7fX9+fH6AgoWHioyNj5CRlZeYmp2TiYyGenp9eXh9fX19foB/fH1/e3p8e3l5e3x7e3x + 6d3FxcnBwcG9vb29vb29wb25tbWxsbW5vb3Fyc3N1dXV1dnd4ent9fn+BgoGAgoWEhoqJiYyLi4 + yPioaLiYSEh4WDhIOCgoKAgX58fXx5eXp4eHl4dXZ1cnN0dHR1cnJycXBxcnJycW9ubGxsbW1ub + m5ub29vcXNzdHZ2dXh6enp+fn5/gYCBhIKFiYeGiomJi4qKjIuLjIyLiomKh4aKioeIiIWDgYB9 + fHx7e3l4eHh2dnd3d3l7enp6enp5ent7e3x7enl6e3t7fHx7e3p8fX5/gIKDg4GCg4KCg4OEhoe + Hh4iJiomLjIqLi4uLi46Pjo2OjouJiomHh4aDgH9/fXp5eXh3d3h4eHh4d3V2d3Z0dnd0dXd3d3 + p7fH59fX19fH5+fn+Af4CAf3+Af359f4KDgoSIiIeJjI6PkJOUk5SYmZiYmZqZmJqamJiZmJaWl + ZSTkZCQj46Ni4qHh4iFgoKBfn9+fn+AgYCAgYOCgoSEg4SFhIODg4OCgICBf35/gICAgYKCgYGD + hIOBgYOCgYGAgIGBgIGCgoKBgoSEg4KCgH9/f318fHt6e3t7enl5eHh5fH18foCAf4GDg4OFhoa + GhoeJh4aJioiIiYiIhoWGh4aGh4eHiImHh4mIiIeHh4iIiIqJioqJh4mKh4eJiYiHh4eHhoWGhY + OEhYWEhYWDg4SFhYWEg4SDgYKCgH+AgICBgoOCgYGBgYKEhoaGhoiIh4eJiYmKioqKiomKioiJi + oqJiYmJiIiIiYiHh4eHh4eGhYWFhISDgoKCgoKCgYGAf31+fXx9fn58e3x8fHx9fX19fX19fX19 + fHx9fn5/gICBgYGCgoKCg4OCgoODgoKDg4OCgoKCgoGBgYGBgYGCgYCBgIGCgoKDg4KCg4OEhIS + FhYWFhYWFhYWFhoWGhoWEhISDg4ODg4ODg4ODg4SDgoKDg4OCg4SDgoKDgoGBgoGAgIB/f35+fn + 9+fn9/f35+fn5/gICAgIGBgYKCg4ODg4SEg4OEhIODhIODhIODg4ODg4OCgoKBgoKCg4OCgoODg + 4ODg4OEhISEhIWEhIWFhISEhISEhIWEhISEhIODhISEg4ODg4ODg4ODg4ODgoKCgoKCg4KCgoKC + goKCgoKCgoOCgoKCgoKBgYKCgoKCgoGBgYGAgICAgYGBgYCAf39/f39/f3+Af39/f39/f39/gIC + AgIB/f39/f39/gICAgIB/f39/gIB/f39/gH9/f39/f39/fn5+f39/f39/fn5+fn5/f39/f39/fn + 5+fn9/f39/f35+fn5+fn9/f35/f39+fn5+fn9/fn5+fn5+fn5+f39+fn5+fn19fX5+fn5+fn5+f + X5+fn5+fn5+fn19fn5+fn5+fX19fX59fn5+fn19fX19fX1+fX19fX19fX19fX19fX19fX19fX19 + fX19fX19fX19fX19fX19fX19fX19fX19fXx9fX18fH19fXx8fXx9fXx8fHx8fHx8fH19fX19fXx + 9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX + 19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f + X19fX19fX19fX19fX19fX19fX19fX19fX1+fX5+fn19fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+ + fn5+fn5+fn5+fn5+f39/fn5/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39 + /f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f4B/f3 + 9/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f + 39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/ + f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f4B/f39/f39/f39/f39/f39/f39 + /f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f3 + 9/f39/f39/f39/f39/f39/f35+fn5+f35/f39/f39/f39/f39/f39/f39/f39/f39/f39/f35+f + 39+fn5/fn5+f39/fn9/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/ + f39/f39/f39/f39/f39+fn9/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39 + /f39/f39/f39/f39/f39/f39/f39/f4CAf39/f39/f39/gIB/f39/f39/f4B/f4CAgICAgICAgI + CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg + ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA + gICAgICAgICAgIB/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/gICAgIC + AgICAgICAgICAgICAgICAgICAgICAgIGBgYGAgYGBgICAgIGAgICBgYGAgYGBgYGBgYGBgYGBgY + GBgYGBgYGBgYGBgYGBgYGAgYCAgICAgICAgICAgICAgICAgICAgICAgICAgH+AgICAf39/gH9/f + 3+Af39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f4CAgH9/gIB/f39/f4B/f3+AgICAf4CA + gICAgICAgICAgICAgH9/f4CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC + AgICAgICAgICAgICAgICAgICAgICAgIB/f39/f39/f39/f4CAf39/f39/f39/f39/f39/f39+fn + 9/fn5+fn5+fn5+fn5+fX19fX19fX19fX19fX19fX19fn5+fn5+fn9/f39/f4CAgICAgICBgYGBg + YGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYCAgICAgICAgICAgICAgICAgYGAgICA + gICAgICAgICAgICBgYGAgICAgICAgICAgICAgICAgICAgICAgIB/gICAgH9/f39/f39/f39/f39 + /f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/gICAgICAf39/f39/gH+AgI + CAgICAgIB/f39/f39/f4B/f39/f39/f39/f39/f39/f39/f39/f39/f39/fn9/f39/f39/f39+f + 39/f39/f39/f39/f39/f39/f39/f4B/f4CAgICAf39/f39/gICAf39/gICAgICAgICAgICAgICA + gICAgIGAgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYCAgICBgYGBgYGBgYCBgYGBgYCAgIG + BgICAgICAgICAgICAgICAgICAgICAgICAgICBgICAgICAgICAgICAgICAgICAgICAgICAgICAgI + CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg + ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA + gICAgICAgICAgICAf3+AgIB/f4CAf39/f39/f3+AgICAgH+AgICAf3+AgICAgICAgH9/f39/f39 + /f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f3 + 9/f39/f39/gH9/gICAgICAgICAgIB/gICAgH+AgIB/f39/f39/gICAgICAgH9/f3+AgH9/f4B/f + 39/f39/f39/f39/f3+AgICAgICAf3+AgIB/f4CAgIB/f4CAgICAgICAgICAf39/f3+AgIB/f4CA + gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAf39/f39 + /f4CAgH9/f39/f39/f39/f39/f39/f39/f39/f39/f4B/f39/f39/gIB/f39/f39/f39/gH9/f3 + 9/f4CAgICAgIB/gICAgICAgICAgICAgICAgICAgICAgICAgH+AgICAf4CAgICAgICAgIB/gICAf + 4CAgICAgH+Af4CAgH9/f39/f39/f39/gICAgICAgICAgICAf39/f39/f4CAgH9/gICAf3+AgICA + gICAgICAgICAgICAgICAgICAgIB/f39/gIB/f4CAgIB/f4CAgH9/gICAf39/f39/f39/f39/f39 + /f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f39/f3 + 9/f39/f39/f39/f39/f39/f39/f39/f39/f39/gICAf39/gH9/f3+AgH9/f39/f39/f39/f39/f + 39/f39/f39/f39/f39/f39/f39/gICAf3+AgH9/f3+AgH9/f4CAgH9/gICAgICAgICAgICAgICA + gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC + AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI + CAgICAgICAgICAgICAgICAgICAgICBgYGBgIGBgYCAgYGAgICAgYCAgICAgICAgICAgICAgICAg + ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA + gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC + AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI + CAgICAgICAgICAgICAgICAf39/f39/f4CAgIB/f4CAgICAgICAgICAgICAgICAgICAgICAgICAg + ICAf39/f3+Af39/f39/f39/f4B/f39/f4CAgICAgICAgICAgA== +TEL;TYPE=HOME:0351 223344 +TEL;TYPE=WORK:0351 443322 +TEL;TYPE=CELL:0173 223344 +UID:P9HXg34Oav +URL:http://www.mustermann.de/~heiko/ +X-KADDRESSBOOK-X-Anniversary:1982-07-07 +X-KADDRESSBOOK-X-AssistantsName:Mr. Smithers +X-KADDRESSBOOK-X-Department:Edutainment +X-KADDRESSBOOK-X-IMAddress:122334455 +X-KADDRESSBOOK-X-ManagersName:Mr. Burnes +X-KADDRESSBOOK-X-Office:223 2nd stage +X-KADDRESSBOOK-X-Profession:Clown +X-KADDRESSBOOK-X-SpousesName:femal clown +END:VCARD + diff --git a/autotests/data/v4_0.vcard6.vcf.ref b/autotests/data/v4_0.vcard6.vcf.ref new file mode 100644 index 0000000..80622a6 --- /dev/null +++ b/autotests/data/v4_0.vcard6.vcf.ref @@ -0,0 +1,10 @@ +BEGIN:VCARD +VERSION:4.0 +CLASS:PUBLIC +EMAIL;TYPE=PREF:email1@abc.de +EMAIL:email2@abc.de +FN:Test User +N:User;Test;;; +UID:uJTkVqH5Qt +END:VCARD + diff --git a/autotests/data/v4_0.vcard7.vcf.ref b/autotests/data/v4_0.vcard7.vcf.ref new file mode 100644 index 0000000..64ff743 --- /dev/null +++ b/autotests/data/v4_0.vcard7.vcf.ref @@ -0,0 +1,8 @@ +BEGIN:VCARD +VERSION:4.0 +FN: +LABEL;TYPE=work:401 Park Drive 3 West\nBoston\, MA 02215\nUSA\nHerecomesye + tanotherline +UID:pas-id-3E136F9B00000000 +END:VCARD + diff --git a/autotests/data/v4_0.vcard8.vcf.ref b/autotests/data/v4_0.vcard8.vcf.ref new file mode 100644 index 0000000..55bf303 --- /dev/null +++ b/autotests/data/v4_0.vcard8.vcf.ref @@ -0,0 +1,8 @@ +BEGIN:VCARD +VERSION:4.0 +FN:test +N:test;;;; +NOTE:line one\nline two\nline three\n +UID:8OD165Pope +END:VCARD + diff --git a/autotests/data/vcard1.vcf b/autotests/data/vcard1.vcf new file mode 100644 index 0000000..da4613e --- /dev/null +++ b/autotests/data/vcard1.vcf @@ -0,0 +1,14 @@ +BEGIN:vCard +VERSION:3.0 +UID:gDVbA6LY3t +FN:Frank Dawson +ORG:Lotus Development Corporation +ADR;TYPE=WORK,POSTAL,PARCEL:;;6544 Battleford Drive + ;Raleigh;NC;27613-3502;U.S.A. +TEL;TYPE=VOICE,MSG,WORK:+1-919-676-9515 +TEL;TYPE=FAX,WORK:+1-919-676-9564 +EMAIL;TYPE=INTERNET,PREF:Frank_Dawson@Lotus.com +EMAIL;TYPE=INTERNET:fdawson@earthlink.net +URL:http://home.earthlink.net/~fdawson +END:vCard + diff --git a/autotests/data/vcard1.vcf.2_1ref b/autotests/data/vcard1.vcf.2_1ref new file mode 100644 index 0000000..08ede3e --- /dev/null +++ b/autotests/data/vcard1.vcf.2_1ref @@ -0,0 +1,14 @@ +BEGIN:VCARD +VERSION:2.1 +ADR;PARCEL;POSTAL;WORK:;;6544 Battleford Drive;Raleigh;NC;27613-3502;U.S.A. +EMAIL;INTERNET;PREF:Frank_Dawson@Lotus.com +EMAIL;INTERNET:fdawson@earthlink.net +FN:Frank Dawson +N:;;;; +ORG:Lotus Development Corporation +TEL;MSG;VOICE;WORK:+1-919-676-9515 +TEL;FAX;WORK:+1-919-676-9564 +UID:gDVbA6LY3t +URL:http://home.earthlink.net/~fdawson +END:VCARD + diff --git a/autotests/data/vcard1.vcf.ref b/autotests/data/vcard1.vcf.ref new file mode 100644 index 0000000..038cb5f --- /dev/null +++ b/autotests/data/vcard1.vcf.ref @@ -0,0 +1,15 @@ +BEGIN:VCARD +VERSION:3.0 +ADR;TYPE=parcel,postal,work:;;6544 Battleford Drive;Raleigh;NC;27613-3502;U + .S.A. +EMAIL;TYPE=INTERNET,PREF:Frank_Dawson@Lotus.com +EMAIL;TYPE=INTERNET:fdawson@earthlink.net +FN:Frank Dawson +N:;;;; +ORG:Lotus Development Corporation +TEL;TYPE=MSG,VOICE,WORK:+1-919-676-9515 +TEL;TYPE=FAX,WORK:+1-919-676-9564 +UID:gDVbA6LY3t +URL:http://home.earthlink.net/~fdawson +END:VCARD + diff --git a/autotests/data/vcard10.vcf b/autotests/data/vcard10.vcf new file mode 100644 index 0000000..821aea6 --- /dev/null +++ b/autotests/data/vcard10.vcf @@ -0,0 +1,56 @@ +BEGIN:VCARD +VERSION:2.1 +UID:bfa5fdc5-fbfc-4ce2-8196-29ca0deb3bd3 +ADR;WORK;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;;=44=44=44=44=44=44=44=44=44=44=44=44=44=44=44=2D=53=74=61=C3=9F=65=20= +=32=0A=30=30=30=30=30=20=44=44=44=44=44=44=44=44=44=44;;;; +ORG:Bike Shop +Note:This one has a funny character at the end in the contact list +END:VCARD +BEGIN:VCARD +VERSION:2.1 +UID:f8361311-b25c-4237-a94e-3015d8fe19de +N:;Broken;;; +FN:Field after Address broken +ADR;HOME;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;;=41=41=41=41=41=41=41=2D=41=C3=A4=41=41=41=41=41=20= +=31=31;=55=72=74;;=30=30=30=30=30; +URL:http://some-webseite.com +NOTE:This one's URL field is truncated (see contact's edit form). Remove the linebreak in the VCF's address field and the URL will will be correct. +END:VCARD +BEGIN:VCARD +VERSION:2.1 +UID:462269fd-607c-4284-998b-6771143b63a7 +N:;Broken;;; +FN:Field after Address not broken +ADR;HOME;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;;=41=41=41=41=41=41=41=2D=41=C3=A4=41=41=41=41=41=20= +=31=31;=55=72=74;;=30=30=30=30=30; +NOTE:this is identical to "Website broken", but with Note and URL swapped. The Note field does not get truncated as the URL field does. +URL:http://some-webseite.com +END:VCARD +BEGIN:VCARD +VERSION:2.1 +UID:b4fc4930-043f-446a-9a76-cf0b548368d8 +N:Name;Surname;;Dr. med.; +FN:Dr. med. Surname Name +TITLE;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=46=61=63=68=61=72=7A=74=20=66=C3=BC=72=20=41=6C=6C=67=65=6D=65=69=6E= +=6D=65=64=69=7A=69=6E +NOTE;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=53=70=72=65=63=68=7A=65=69=74=65=6E=3A=0A=4D=6F=20=20=20=38=E2=80=93= +=31=32=2C=20=31=35=E2=80=93=31=38=0A=44=69=20=20=20=20=20=38=E2=80=93= +=31=32=0A=4D=69=20=20=20=20=38=E2=80=93=31=32=2C=20=31=34=E2=80=93=31= +=35=0A=44=6F=20=31=34=E2=80=93=31=39=0A=46=72=20=20=20=20=20=38=E2=80= +=93=31=32 +END:VCARD +BEGIN:VCARD +VERSION:2.1 +UID:941b057d-e959-4644-b41f-e122b26c3807 +N:Doctor;Second;;; +FN:Second Doctor +ADR;WORK;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;;=44=44=44=44=44=44=44=44=44=44=44=73=74=72=61=C3=9F=65=20=32=36=0A=30= +=30=30=30=30=20=44=44=44=44=44=44=44=44=44=44=44=44=44=44=44=44=44;;;; +ORG: +TITLE:Dentist +NOTE;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=53=70=72=65=63=68=7A=65=69=74=65=6E=3A=0A=4D=6F=20=20=20=38=E2=80=93= +=31=33=0A=44=69=20=20=20=31=30=E2=80=93=31=32=2C=20=31=33=E2=80=93=31= +=38=0A=4D=69=20=20=31=30=E2=80=93=31=32=2C=20=31=33=E2=80=93=31=38=0A= +=44=6F=20=20=31=33=E2=80=93=31=38=0A=46=72=20=20=20=20=20=20=38=E2=80= +=93=31=32 +END:VCARD diff --git a/autotests/data/vcard10.vcf.ref b/autotests/data/vcard10.vcf.ref new file mode 100644 index 0000000..7a21a4b --- /dev/null +++ b/autotests/data/vcard10.vcf.ref @@ -0,0 +1,52 @@ +BEGIN:VCARD +VERSION:3.0 +ADR;TYPE=work:;;DDDDDDDDDDDDDDD-Staße 2\n00000 DDDDDDDDDD;;;; +N:;;;; +NOTE:This one has a funny character at the end in the contact list +ORG:Bike Shop +UID:bfa5fdc5-fbfc-4ce2-8196-29ca0deb3bd3 +END:VCARD + +BEGIN:VCARD +VERSION:3.0 +ADR;TYPE=home:;;AAAAAAA-AäAAAAA 11;Urt;;00000; +FN:Field after Address broken +N:;Broken;;; +NOTE:This one's URL field is truncated (see contact's edit form). Remove th + e linebreak in the VCF's address field and the URL will will be correct. +UID:f8361311-b25c-4237-a94e-3015d8fe19de +URL:http://some-webseite.com +END:VCARD + +BEGIN:VCARD +VERSION:3.0 +ADR;TYPE=home:;;AAAAAAA-AäAAAAA 11;Urt;;00000; +FN:Field after Address not broken +N:;Broken;;; +NOTE:this is identical to "Website broken"\, but with Note and URL swapped. + The Note field does not get truncated as the URL field does. +UID:462269fd-607c-4284-998b-6771143b63a7 +URL:http://some-webseite.com +END:VCARD + +BEGIN:VCARD +VERSION:3.0 +FN:Dr. med. Surname Name +N:Name;Surname;;Dr. med.; +NOTE:Sprechzeiten:\nMo 8–12\, 15–18\nDi 8–12\nMi 8–12\, 14 + –15\nDo 14–19\nFr 8–12 +TITLE:Facharzt für Allgemeinmedizin +UID:b4fc4930-043f-446a-9a76-cf0b548368d8 +END:VCARD + +BEGIN:VCARD +VERSION:3.0 +ADR;TYPE=work:;;DDDDDDDDDDDstraße 26\n00000 DDDDDDDDDDDDDDDDD;;;; +FN:Second Doctor +N:Doctor;Second;;; +NOTE:Sprechzeiten:\nMo 8–13\nDi 10–12\, 13–18\nMi 10–12\, 13 + –18\nDo 13–18\nFr 8–12 +TITLE:Dentist +UID:941b057d-e959-4644-b41f-e122b26c3807 +END:VCARD + diff --git a/autotests/data/vcard11.vcf b/autotests/data/vcard11.vcf new file mode 100644 index 0000000..904e083 --- /dev/null +++ b/autotests/data/vcard11.vcf @@ -0,0 +1,10 @@ +BEGIN:VCARD +CLASS:PUBLIC +EMAIL;TYPE=HOME;X-EVOLUTION-UI-SLOT=2:thejoe@abc.com +EMAIL;TYPE=WORK;X-EVOLUTION-UI-SLOT=1:johndoe@abc.com +FN:Test User +N:User;Test;;; +UID:uJTkVqH5Qt +VERSION:3.0 +END:VCARD + diff --git a/autotests/data/vcard11.vcf.ref b/autotests/data/vcard11.vcf.ref new file mode 100644 index 0000000..2b8709a --- /dev/null +++ b/autotests/data/vcard11.vcf.ref @@ -0,0 +1,10 @@ +BEGIN:VCARD +VERSION:3.0 +CLASS:PUBLIC +EMAIL;TYPE=HOME;X-EVOLUTION-UI-SLOT=2:thejoe@abc.com +EMAIL;TYPE=WORK;X-EVOLUTION-UI-SLOT=1:johndoe@abc.com +FN:Test User +N:User;Test;;; +UID:uJTkVqH5Qt +END:VCARD + diff --git a/autotests/data/vcard12.vcf b/autotests/data/vcard12.vcf new file mode 100644 index 0000000..ecb2d6c --- /dev/null +++ b/autotests/data/vcard12.vcf @@ -0,0 +1,15 @@ +BEGIN:VCARD +VERSION:3.0 +UID:pas-id-54B2522600000001 +FN:Good Looking +N:Looking;Good;;; +PHOTO;TYPE=WORK;ENCODING=b:iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAA + CXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wELCiUrjAUGmgAAABl0RVh0Q29tbWVudABDcm + VhdGVkIHdpdGggR0lNUFeBDhcAAAAZSURBVAjXY/zPAAVMDAwMDP//MzAwMMLFAEMrBAHo3Yr/ + AAAAAElFTkSuQmCC +PHOTO;TYPE=HOME;ENCODING=b:iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAA + CXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wELCiQG0MFrrgAAABl0RVh0Q29tbWVudABDcm + VhdGVkIHdpdGggR0lNUFeBDhcAAAAUSURBVAjXY/j//z8DAwOEhAG4GACzagv1unIx3wAAAABJ + RU5ErkJggg== +EMAIL;TYPE=WORK;X-EVOLUTION-UI-SLOT=1:goodlooking@example.com +END:VCARD diff --git a/autotests/data/vcard12.vcf.2_1ref b/autotests/data/vcard12.vcf.2_1ref new file mode 100644 index 0000000000000000000000000000000000000000..65601350508304f7ab150524187691b18f3347dd GIT binary patch literal 555 zcmZ>Ab@%kM3UhW0a^d9)a}5gi^!Kwe(lg}ca`koe^sx^25AwE-&~**-_X!OF%ISuB z>IVDxhu9igrRV3TWX80|P@$k*9}C5RkzP z!W>LM@}`&43n0Z=;1OBOz`)JRr63HXgc%uT&5;0#vzK`Ky0YJA + + 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.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=HOME,PREF;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")); + email = lst.at(0).emailList().at(1); + QCOMPARE(email.mail(), QStringLiteral("foo@foo.com")); + + 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; + const 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); +} + +QTEST_MAIN(EmailTest) diff --git a/autotests/emailtest.h b/autotests/emailtest.h new file mode 100644 index 0000000..3974fa1 --- /dev/null +++ b/autotests/emailtest.h @@ -0,0 +1,45 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2015 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 EMAILTEST_H +#define EMAILTEST_H + +#include + +class EmailTest : public QObject +{ + Q_OBJECT +public: + explicit EmailTest(QObject *parent = Q_NULLPTR); + ~EmailTest(); + +private Q_SLOTS: + void shouldHaveDefaultValue(); + void shouldAssignValue(); + void shouldAssignExternal(); + void shouldSerialized(); + void shouldEqualEmail(); + void shouldParseEmailVCard(); + void shouldParseEmailVCardWithoutEmail(); + void shouldParseEmailVCardWithMultiEmails(); + void shouldExportVcard(); +}; + +#endif // EMAILTEST_H diff --git a/autotests/gendertest.cpp b/autotests/gendertest.cpp new file mode 100644 index 0000000..b553d5d --- /dev/null +++ b/autotests/gendertest.cpp @@ -0,0 +1,258 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2015 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 "gendertest.h" +#include "gender.h" +#include "vcardtool.h" +#include + +GenderTest::GenderTest(QObject *parent) + : QObject(parent) +{ + +} + +GenderTest::~GenderTest() +{ + +} + +void GenderTest::shouldHaveDefaultValue() +{ + KContacts::Gender gender; + QVERIFY(!gender.isValid()); + QVERIFY(gender.gender().isEmpty()); + QVERIFY(gender.comment().isEmpty()); +} + +void GenderTest::shouldAssignValue() +{ + const QString genderStr(QStringLiteral("F")); + KContacts::Gender gender(genderStr); + const QString commentStr(QStringLiteral("foo")); + gender.setComment(commentStr); + QVERIFY(gender.isValid()); + QVERIFY(!gender.gender().isEmpty()); + QCOMPARE(gender.gender(), genderStr); + QVERIFY(!gender.comment().isEmpty()); + QCOMPARE(gender.comment(), commentStr); +} + +void GenderTest::shouldAssignExternal() +{ + KContacts::Gender gender; + const QString genderStr(QStringLiteral("H")); + gender.setGender(genderStr); + QVERIFY(gender.isValid()); + QVERIFY(!gender.gender().isEmpty()); + QCOMPARE(gender.gender(), genderStr); +} + +void GenderTest::shouldSerialized() +{ + KContacts::Gender gender; + KContacts::Gender result; + const QString genderStr(QStringLiteral("H")); + gender.setGender(genderStr); + gender.setComment(QStringLiteral("foo")); + + QByteArray data; + QDataStream s(&data, QIODevice::WriteOnly); + s << gender; + + QDataStream t(&data, QIODevice::ReadOnly); + t >> result; + + QVERIFY(gender == result); +} + +void GenderTest::shouldEqualGender() +{ + KContacts::Gender gender; + KContacts::Gender result; + const QString genderStr(QStringLiteral("H")); + gender.setGender(genderStr); + gender.setComment(QStringLiteral("foo")); + + result = gender; + QVERIFY(gender == result); +} + +void GenderTest::shouldParseGender_data() +{ + QTest::addColumn("vcarddata"); + QTest::addColumn("genre"); + QTest::addColumn("comment"); + QTest::addColumn("hasGender"); + + QByteArray str("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"); + QTest::newRow("nogender") << str << QString() << QString() << false; + + str = QByteArray("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" + "GENDER:H\n" + "END:VCARD\n"); + QTest::newRow("hasgenderbutnocomment") << str << QStringLiteral("H") << QString() << true; + + str = QByteArray("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" + "GENDER:;foo\n" + "END:VCARD\n"); + QTest::newRow("hasgenderbutnotypebutcomment") << str << QString() << QStringLiteral("foo") << true; + + str = QByteArray("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" + "GENDER:H;foo\n" + "END:VCARD\n"); + QTest::newRow("hasgendertypeandcomment") << str << QStringLiteral("H") << QStringLiteral("foo") << true; +} + +void GenderTest::shouldParseGender() +{ + QFETCH(QByteArray, vcarddata); + QFETCH(QString, genre); + QFETCH(QString, comment); + QFETCH(bool, hasGender); + + KContacts::VCardTool vcard; + const KContacts::AddresseeList lst = vcard.parseVCards(vcarddata); + QCOMPARE(lst.count(), 1); + QCOMPARE(lst.at(0).gender().isValid(), hasGender); + QCOMPARE(lst.at(0).gender().comment(), comment); + QCOMPARE(lst.at(0).gender().gender(), genre); +} + +QByteArray GenderTest::createCard(const QByteArray &gender) +{ + QByteArray expected("BEGIN:VCARD\r\n" + "VERSION:4.0\r\n" + "EMAIL:foo@kde.org\r\n"); + if (!gender.isEmpty()) { + expected += gender + "\r\n"; + } + expected += QByteArray( + "N:;;;;\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + return expected; +} + +void GenderTest::shouldExportEmptyGender() +{ + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + lst << addr; + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v4_0); + QByteArray expected = createCard(QByteArray()); + QCOMPARE(ba, expected); +} + +void GenderTest::shouldExportOnlyGenderWithoutCommentGender() +{ + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + KContacts::Gender gender; + gender.setGender(QStringLiteral("H")); + addr.setGender(gender); + lst << addr; + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v4_0); + QByteArray expected = createCard(QByteArray("GENDER:H")); + QCOMPARE(ba, expected); +} + +void GenderTest::shouldExportOnlyGenderWithCommentGender() +{ + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + KContacts::Gender gender; + gender.setGender(QStringLiteral("H")); + gender.setComment(QStringLiteral("comment")); + addr.setGender(gender); + lst << addr; + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v4_0); + QByteArray expected = createCard(QByteArray("GENDER:H;comment")); + QCOMPARE(ba, expected); +} + +void GenderTest::shouldExportOnlyGenderWithoutTypeCommentGender() +{ + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + KContacts::Gender gender; + gender.setComment(QStringLiteral("comment")); + addr.setGender(gender); + lst << addr; + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v4_0); + QByteArray expected = createCard(QByteArray("GENDER:;comment")); + QCOMPARE(ba, expected); +} + +void GenderTest::shouldNotExportInVcard3() +{ + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + KContacts::Gender gender; + gender.setComment(QStringLiteral("comment")); + addr.setGender(gender); + lst << addr; + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v3_0); + QByteArray expected("BEGIN:VCARD\r\n" + "VERSION:3.0\r\n" + "EMAIL:foo@kde.org\r\n" + "N:;;;;\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + QCOMPARE(ba, expected); +} + +QTEST_MAIN(GenderTest) diff --git a/autotests/gendertest.h b/autotests/gendertest.h new file mode 100644 index 0000000..2afed5b --- /dev/null +++ b/autotests/gendertest.h @@ -0,0 +1,51 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2015 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 GENDERTEST_H +#define GENDERTEST_H + +#include + +class GenderTest : public QObject +{ + Q_OBJECT +public: + explicit GenderTest(QObject *parent = Q_NULLPTR); + ~GenderTest(); + +private: + QByteArray createCard(const QByteArray &gender); + +private Q_SLOTS: + void shouldHaveDefaultValue(); + void shouldAssignValue(); + void shouldAssignExternal(); + void shouldSerialized(); + void shouldEqualGender(); + void shouldParseGender(); + void shouldParseGender_data(); + void shouldExportOnlyGenderWithoutCommentGender(); + void shouldExportEmptyGender(); + void shouldExportOnlyGenderWithCommentGender(); + void shouldExportOnlyGenderWithoutTypeCommentGender(); + void shouldNotExportInVcard3(); +}; + +#endif // GENDERTEST_H diff --git a/autotests/geotest.cpp b/autotests/geotest.cpp new file mode 100644 index 0000000..c79d868 --- /dev/null +++ b/autotests/geotest.cpp @@ -0,0 +1,206 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2007 KDE-PIM team + + 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 "geotest.h" +#include "kcontacts/geo.h" +#include "vcardtool.h" +#include + +QTEST_MAIN(GeoTest) + +void GeoTest::constructor() +{ + KContacts::Geo geo(1.2f, 3.4f); + + QVERIFY((float)geo.latitude() == (float)1.2); + QVERIFY((float)geo.longitude() == (float)3.4); +} + +void GeoTest::isValid() +{ + KContacts::Geo geo; + + QVERIFY(!geo.isValid()); + + geo.setLatitude(23); + + QVERIFY(!geo.isValid()); + + geo.setLongitude(45); + + QVERIFY(geo.isValid()); + + geo.clear(); + + QVERIFY(!geo.isValid()); + QVERIFY(geo == KContacts::Geo()); +} + +void GeoTest::setData() +{ + KContacts::Geo geo; + + geo.setLatitude(22.5f); + geo.setLongitude(45.1f); + + QVERIFY((float)geo.latitude() == (float)22.5); + QVERIFY((float)geo.longitude() == (float)45.1); +} + +void GeoTest::equals() +{ + KContacts::Geo geo1(22.5f, 33.7f); + KContacts::Geo geo2(22.5f, 33.7f); + + QVERIFY(geo1 == geo2); +} + +void GeoTest::differs() +{ + KContacts::Geo geo1(22.5f, 33.7f); + KContacts::Geo geo2(22.5f, 33.6f); + + QVERIFY(geo1 != geo2); +} + +void GeoTest::serialization() +{ + KContacts::Geo geo1(22.5f, 33.7f); + QByteArray data; + + QDataStream s(&data, QIODevice::WriteOnly); + s << geo1; + + KContacts::Geo geo2; + QDataStream t(&data, QIODevice::ReadOnly); + t >> geo2; + + QVERIFY(geo1 == geo2); +} + +void GeoTest::shouldParseGeoVCard3() +{ + QByteArray vcarddata("BEGIN:VCARD\n" + "VERSION:3.0\n" + "N:LastName;FirstName;;;\n" + "UID:c80cf296-0825-4eb0-ab16-1fac1d522a33@xxxxxx.xx\n" + "GEO:22.5;180.0\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).geo().isValid()); + KContacts::Geo geo = lst.at(0).geo(); + QCOMPARE(geo.latitude(), 22.5); + QCOMPARE(geo.longitude(), 180.0); +} + +void GeoTest::shouldParseGeoVCard4() +{ + QByteArray vcarddata("BEGIN:VCARD\n" + "VERSION:4.0\n" + "N:LastName;FirstName;;;\n" + "UID:c80cf296-0825-4eb0-ab16-1fac1d522a33@xxxxxx.xx\n" + "GEO:geo:22.5,180.0\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).geo().isValid()); + KContacts::Geo geo = lst.at(0).geo(); + QCOMPARE(geo.latitude(), 22.5); + QCOMPARE(geo.longitude(), 180.0); +} + +void GeoTest::shouldGenerateVCard3() +{ + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + + KContacts::Geo geo; + geo.setLongitude(180.0); + geo.setLatitude(22.5); + addr.setGeo(geo); + + lst << addr; + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v3_0); + QByteArray expected("BEGIN:VCARD\r\n" + "VERSION:3.0\r\n" + "EMAIL:foo@kde.org\r\n" + "GEO:22.500000;180.000000\r\n" + "N:;;;;\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + QCOMPARE(ba, expected); + +} + +void GeoTest::shouldGenerateVCard4() +{ + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + + KContacts::Geo geo; + geo.setLongitude(180.0); + geo.setLatitude(22.5); + addr.setGeo(geo); + + lst << addr; + KContacts::VCardTool vcard; + const 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" + "GEO:geo:22.500000,180.000000\r\n" + "N:;;;;\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + QCOMPARE(ba, expected); +} + +void GeoTest::shouldGenerateWithoutGeo() +{ + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + + lst << addr; + KContacts::VCardTool vcard; + const 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" + "N:;;;;\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + QCOMPARE(ba, expected); +} diff --git a/autotests/geotest.h b/autotests/geotest.h new file mode 100644 index 0000000..25a4e47 --- /dev/null +++ b/autotests/geotest.h @@ -0,0 +1,44 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2007 KDE-PIM team + + 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 GEOTEST_H +#define GEOTEST_H + +#include + +class GeoTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void constructor(); + void isValid(); + void setData(); + void equals(); + void differs(); + void serialization(); + void shouldParseGeoVCard3(); + void shouldParseGeoVCard4(); + void shouldGenerateVCard3(); + void shouldGenerateVCard4(); + void shouldGenerateWithoutGeo(); +}; + +#endif diff --git a/autotests/impptest.cpp b/autotests/impptest.cpp new file mode 100644 index 0000000..72f6716 --- /dev/null +++ b/autotests/impptest.cpp @@ -0,0 +1,305 @@ +/* + This file is part of libkabc. + Copyright (c) 2015 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 "impptest.h" +#include "impp.h" +#include +#include "vcardtool.h" +Q_DECLARE_METATYPE(KContacts::Impp::ImppType) + +ImppTest::ImppTest(QObject *parent) + : QObject(parent) +{ + +} + +ImppTest::~ImppTest() +{ + +} + +void ImppTest::shouldHaveDefaultValue() +{ + KContacts::Impp impp; + QVERIFY(!impp.isValid()); + QVERIFY(impp.address().isEmpty()); + QCOMPARE(impp.type(), KContacts::Impp::Unknown); + QVERIFY(impp.parameters().isEmpty()); +} + +void ImppTest::shouldAssignValue() +{ + const QString address(QStringLiteral("address")); + QMap params; + params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + KContacts::Impp impp; + impp.setParameters(params); + impp.setType(KContacts::Impp::Icq); + impp.setAddress(address); + QVERIFY(impp.isValid()); + QVERIFY(!impp.address().isEmpty()); + QCOMPARE(impp.address(), address); + QCOMPARE(impp.type(), KContacts::Impp::Icq); + QVERIFY(!impp.parameters().isEmpty()); + QCOMPARE(impp.parameters(), params); +} + +void ImppTest::shouldSerialized() +{ + const QString address(QStringLiteral("address")); + QMap params; + params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + KContacts::Impp impp; + impp.setParameters(params); + impp.setType(KContacts::Impp::Icq); + impp.setAddress(address); + + QByteArray data; + QDataStream s(&data, QIODevice::WriteOnly); + s << impp; + + KContacts::Impp result; + QDataStream t(&data, QIODevice::ReadOnly); + t >> result; + + QVERIFY(impp == result); +} + +void ImppTest::shouldEqualImpp() +{ + const QString address(QStringLiteral("address")); + QMap params; + params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + KContacts::Impp impp; + impp.setParameters(params); + impp.setType(KContacts::Impp::Icq); + impp.setAddress(address); + + KContacts::Impp result(impp); + QVERIFY(impp == result); +} + +void ImppTest::shouldParseWithoutImpp() +{ + QByteArray vcarddata("BEGIN:VCARD\n" + "VERSION:3.0\n" + "N:LastName;FirstName;;;\n" + "UID:c80cf296-0825-4eb0-ab16-1fac1d522a33@xxxxxx.xx\n" + "LANG:fr" + "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); + QCOMPARE(lst.at(0).imppList().count(), 0); +} + +void ImppTest::shouldParseImpp() +{ + QByteArray vcarddata("BEGIN:VCARD\n" + "VERSION:3.0\n" + "N:LastName;FirstName;;;\n" + "UID:c80cf296-0825-4eb0-ab16-1fac1d522a33@xxxxxx.xx\n" + "IMPP;X-SERVICE-TYPE=skype:skype:xxxxxxxx\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); + QCOMPARE(lst.at(0).imppList().count(), 1); + KContacts::Impp impp = lst.at(0).imppList().at(0); + QCOMPARE(impp.address(), QStringLiteral("skype:xxxxxxxx")); + QCOMPARE(impp.type(), KContacts::Impp::Skype); +} + +QByteArray createCard(KContacts::Impp::ImppType type) +{ + QByteArray expected("BEGIN:VCARD\n" + "VERSION:3.0\n" + "EMAIL:foo@kde.org\n"); + if (type != KContacts::Impp::Unknown) { + const QByteArray baType = KContacts::Impp::typeToString(type).toLatin1(); + expected += "IMPP;X-SERVICE-TYPE=" + baType + ":" + baType + ":address\n"; + } + expected += QByteArray( + "N:;;;;\n" + "UID:testuid\n" + "END:VCARD\n\n"); + return expected; +} + +void ImppTest::shouldParseServiceType_data() +{ + QTest::addColumn("type"); + QTest::addColumn("hasImpp"); + QTest::newRow("withoutimpp") << KContacts::Impp::Unknown << false; + QTest::newRow("skype") << KContacts::Impp::Skype << true; + for (int i = KContacts::Impp::Unknown + 1; i < KContacts::Impp::EndList; ++i) { + KContacts::Impp::ImppType type = static_cast(i); + QTest::newRow(KContacts::Impp::typeToString(type).toLatin1().constData()) << type << true; + } +} + +void ImppTest::shouldParseServiceType() +{ + QFETCH(KContacts::Impp::ImppType, type); + QFETCH(bool, hasImpp); + + QByteArray vcarddata = createCard(type); + + KContacts::VCardTool vcard; + const KContacts::AddresseeList lst = vcard.parseVCards(vcarddata); + QCOMPARE(lst.count(), 1); + + QCOMPARE(!lst.at(0).imppList().isEmpty(), hasImpp); + if (hasImpp) { + KContacts::Impp impp = lst.at(0).imppList().at(0); + QCOMPARE(impp.address(), QStringLiteral("%1:address").arg(KContacts::Impp::typeToString(type))); + QCOMPARE(impp.type(), type); + } +} + +QByteArray expectedVcard(KContacts::Impp::ImppType type) +{ + QByteArray expected("BEGIN:VCARD\r\n" + "VERSION:4.0\r\n" + "EMAIL:foo@kde.org\r\n"); + if (type != KContacts::Impp::Unknown) { + const QByteArray baType = KContacts::Impp::typeToString(type).toLatin1(); + expected += "IMPP;X-SERVICE-TYPE=" + baType + ":address\r\n"; + } + + expected += ("N:;;;;\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + return expected; +} + +void ImppTest::shouldExportEmptyType() +{ + QByteArray expected("BEGIN:VCARD\r\n" + "VERSION:4.0\r\n" + "EMAIL:foo@kde.org\r\n" + "N:;;;;\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + lst << addr; + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v4_0); + QCOMPARE(ba, expected); +} + +void ImppTest::shouldExportType_data() +{ + QTest::addColumn("type"); + for (int i = KContacts::Impp::Unknown + 1; i < KContacts::Impp::EndList; ++i) { + KContacts::Impp::ImppType type = static_cast(i); + QTest::newRow(KContacts::Impp::typeToString(type).toLatin1().constData()) << type; + } +} + +void ImppTest::shouldExportType() +{ + QFETCH(KContacts::Impp::ImppType, type); + + QByteArray expected = expectedVcard(type); + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + KContacts::Impp impp; + impp.setAddress(QStringLiteral("address")); + impp.setType(type); + addr.insertImpp(impp); + lst << addr; + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v4_0); + QCOMPARE(ba, expected); +} + +void ImppTest::shouldExportWithParameters() +{ + QByteArray expected("BEGIN:VCARD\r\n" + "VERSION:4.0\r\n" + "EMAIL:foo@kde.org\r\n" + "IMPP;FOO1=bla1,blo1;FOO2=bla2,blo2;X-SERVICE-TYPE=skype:address\r\n" + "N:;;;;\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + QMap params; + params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + KContacts::Impp impp; + impp.setAddress(QStringLiteral("address")); + impp.setType(KContacts::Impp::Skype); + impp.setParameters(params); + addr.insertImpp(impp); + lst << addr; + + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v4_0); + QCOMPARE(ba, expected); +} + +void ImppTest::shouldShouldNoyExportTwiceServiceType() +{ + QByteArray expected("BEGIN:VCARD\r\n" + "VERSION:4.0\r\n" + "EMAIL:foo@kde.org\r\n" + "IMPP;FOO1=bla1,blo1;FOO2=bla2,blo2;X-SERVICE-TYPE=skype:address\r\n" + "N:;;;;\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + QMap params; + params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + params.insert(QStringLiteral("X-SERVICE-TYPE"), QStringList() << QStringLiteral("aim")); + KContacts::Impp impp; + impp.setAddress(QStringLiteral("address")); + impp.setType(KContacts::Impp::Skype); + impp.setParameters(params); + addr.insertImpp(impp); + lst << addr; + + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v4_0); + QCOMPARE(ba, expected); +} + +QTEST_MAIN(ImppTest) diff --git a/autotests/impptest.h b/autotests/impptest.h new file mode 100644 index 0000000..388fa73 --- /dev/null +++ b/autotests/impptest.h @@ -0,0 +1,51 @@ +/* + This file is part of libkabc. + Copyright (c) 2015 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 IMPPTEST_H +#define IMPPTEST_H + +#include + +class ImppTest : public QObject +{ + Q_OBJECT +public: + explicit ImppTest(QObject *parent = Q_NULLPTR); + ~ImppTest(); + +private Q_SLOTS: + void shouldHaveDefaultValue(); + void shouldAssignValue(); + void shouldSerialized(); + void shouldEqualImpp(); + void shouldParseWithoutImpp(); + void shouldParseImpp(); + void shouldParseServiceType_data(); + void shouldParseServiceType(); + void shouldExportEmptyType(); + + void shouldExportType_data(); + void shouldExportType(); + + void shouldExportWithParameters(); + void shouldShouldNoyExportTwiceServiceType(); +}; + +#endif // IMPPTEST_H diff --git a/autotests/keytest.cpp b/autotests/keytest.cpp new file mode 100644 index 0000000..6fbeb2e --- /dev/null +++ b/autotests/keytest.cpp @@ -0,0 +1,99 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2007 Tobias Koenig + + 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 "keytest.h" +#include "kcontacts/key.h" +#include + +QTEST_MAIN(KeyTest) + +void KeyTest::storeTest() +{ + KContacts::Key key; + + key.setId(QStringLiteral("My Id")); + key.setType(KContacts::Key::Custom); + key.setCustomTypeString(QStringLiteral("GnuPG")); + key.setTextData(QStringLiteral("That's my super secret key")); + + QVERIFY(key.id() == QStringLiteral("My Id")); + QVERIFY(key.type() == KContacts::Key::Custom); + QVERIFY(key.customTypeString() == QStringLiteral("GnuPG")); + QVERIFY(key.textData() == QStringLiteral("That's my super secret key")); + QVERIFY(key.isBinary() == false); +} + +void KeyTest::equalsTest() +{ + KContacts::Key key1, key2; + + key1.setId(QStringLiteral("My Id")); + key1.setType(KContacts::Key::Custom); + key1.setCustomTypeString(QStringLiteral("GnuPG")); + key1.setTextData(QStringLiteral("That's my super secret key")); + + key2.setId(QStringLiteral("My Id")); + key2.setType(KContacts::Key::Custom); + key2.setCustomTypeString(QStringLiteral("GnuPG")); + key2.setTextData(QStringLiteral("That's my super secret key")); + + QVERIFY(key1 == key2); +} + +void KeyTest::differsTest() +{ + KContacts::Key key1(QStringLiteral("TextKey"), KContacts::Key::PGP); + KContacts::Key key2(QStringLiteral("TextKey"), KContacts::Key::Custom); + + QVERIFY(key1 != key2); +} + +void KeyTest::assignmentTest() +{ + KContacts::Key key1, key2; + + key1.setId(QStringLiteral("My Id")); + key1.setType(KContacts::Key::Custom); + key1.setCustomTypeString(QStringLiteral("GnuPG")); + key1.setTextData(QStringLiteral("That's my super secret key")); + + key2 = key1; + + QVERIFY(key1 == key2); +} + +void KeyTest::serializeTest() +{ + KContacts::Key key1, key2; + + key1.setId(QStringLiteral("My Id")); + key1.setType(KContacts::Key::Custom); + key1.setCustomTypeString(QStringLiteral("GnuPG")); + key1.setTextData(QStringLiteral("That's my super secret key")); + + QByteArray data; + QDataStream s(&data, QIODevice::WriteOnly); + s << key1; + + QDataStream t(&data, QIODevice::ReadOnly); + t >> key2; + + QVERIFY(key1 == key2); +} diff --git a/autotests/keytest.h b/autotests/keytest.h new file mode 100644 index 0000000..f097c75 --- /dev/null +++ b/autotests/keytest.h @@ -0,0 +1,38 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2007 Tobias Koenig + + 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 KEY_TEST_H +#define KEY_TEST_H + +#include + +class KeyTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void storeTest(); + void equalsTest(); + void differsTest(); + void assignmentTest(); + void serializeTest(); +}; + +#endif diff --git a/autotests/langtest.cpp b/autotests/langtest.cpp new file mode 100644 index 0000000..95e57e6 --- /dev/null +++ b/autotests/langtest.cpp @@ -0,0 +1,244 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2015 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 "langtest.h" +#include "lang.h" +#include "vcardtool.h" +#include + +LangTest::LangTest(QObject *parent) + : QObject(parent) +{ + +} + +LangTest::~LangTest() +{ + +} + +void LangTest::shouldHaveDefaultValue() +{ + KContacts::Lang language; + QVERIFY(!language.isValid()); + QVERIFY(language.language().isEmpty()); + QVERIFY(language.parameters().isEmpty()); +} + +void LangTest::shouldAssignValue() +{ + const QString lang(QStringLiteral("fr")); + QMap params; + params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + KContacts::Lang language(lang); + language.setParameters(params); + QVERIFY(language.isValid()); + QVERIFY(!language.language().isEmpty()); + QCOMPARE(language.language(), lang); + QVERIFY(!language.parameters().isEmpty()); + QCOMPARE(language.parameters(), params); + +} + +void LangTest::shouldAssignExternal() +{ + KContacts::Lang language; + const QString lang(QStringLiteral("fr")); + language.setLanguage(lang); + QVERIFY(language.isValid()); + QCOMPARE(language.language(), lang); +} + +void LangTest::shouldSerialized() +{ + KContacts::Lang language; + KContacts::Lang result; + const QString lang(QStringLiteral("fr")); + language.setLanguage(lang); + QMap params; + params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + language.setParameters(params); + + QByteArray data; + QDataStream s(&data, QIODevice::WriteOnly); + s << language; + + QDataStream t(&data, QIODevice::ReadOnly); + t >> result; + + QVERIFY(language == result); + +} + +void LangTest::shouldEqualLanguage() +{ + KContacts::Lang language; + KContacts::Lang result; + const QString lang(QStringLiteral("fr")); + language.setLanguage(lang); + QMap params; + params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + language.setParameters(params); + + result = language; + QVERIFY(language == result); +} + +void LangTest::shouldParseLanguage() +{ + QByteArray vcarddata("BEGIN:VCARD\n" + "VERSION:3.0\n" + "N:LastName;FirstName;;;\n" + "UID:c80cf296-0825-4eb0-ab16-1fac1d522a33@xxxxxx.xx\n" + "LANG:fr" + "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); + QCOMPARE(lst.at(0).langs().count(), 1); +} + +void LangTest::shouldParseWithoutLanguage() +{ + 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); + QCOMPARE(lst.at(0).langs().count(), 0); +} + +void LangTest::shouldCreateVCard() +{ + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + KContacts::Lang::List lstLang; + KContacts::Lang lang(QStringLiteral("fr")); + lstLang << lang; + addr.setLangs(lstLang); + lst << addr; + KContacts::VCardTool vcard; + const 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" + "LANG:fr\r\n" + "N:;;;;\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + + QCOMPARE(ba, expected); +} + +void LangTest::shouldCreateVCardWithTwoLang() +{ + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + KContacts::Lang::List lstLang; + KContacts::Lang lang(QStringLiteral("fr")); + KContacts::Lang lang2(QStringLiteral("fr2")); + lstLang << lang << lang2; + addr.setLangs(lstLang); + lst << addr; + KContacts::VCardTool vcard; + const 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" + "LANG:fr\r\n" + "LANG:fr2\r\n" + "N:;;;;\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + + QCOMPARE(ba, expected); + +} + +void LangTest::shouldCreateVCardWithParameters() +{ + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + KContacts::Lang::List lstLang; + KContacts::Lang lang(QStringLiteral("fr")); + QMap params; + params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + lang.setParameters(params); + lstLang << lang; + addr.setLangs(lstLang); + lst << addr; + KContacts::VCardTool vcard; + const 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" + "LANG;FOO1=bla1,blo1;FOO2=bla2,blo2:fr\r\n" + "N:;;;;\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + QCOMPARE(ba, expected); +} + +void LangTest::shouldNotGenerateLangForVCard3() +{ + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + KContacts::Lang::List lstLang; + KContacts::Lang lang(QStringLiteral("fr")); + QMap params; + params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + lang.setParameters(params); + lstLang << lang; + addr.setLangs(lstLang); + lst << addr; + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v3_0); + QByteArray expected("BEGIN:VCARD\r\n" + "VERSION:3.0\r\n" + "EMAIL:foo@kde.org\r\n" + "N:;;;;\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + QCOMPARE(ba, expected); +} + +QTEST_MAIN(LangTest) diff --git a/autotests/langtest.h b/autotests/langtest.h new file mode 100644 index 0000000..97dd918 --- /dev/null +++ b/autotests/langtest.h @@ -0,0 +1,46 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2015 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 LANGTEST_H +#define LANGTEST_H + +#include + +class LangTest : public QObject +{ + Q_OBJECT +public: + explicit LangTest(QObject *parent = Q_NULLPTR); + ~LangTest(); +private Q_SLOTS: + void shouldHaveDefaultValue(); + void shouldAssignValue(); + void shouldAssignExternal(); + void shouldSerialized(); + void shouldEqualLanguage(); + void shouldParseLanguage(); + void shouldParseWithoutLanguage(); + void shouldCreateVCard(); + void shouldCreateVCardWithTwoLang(); + void shouldCreateVCardWithParameters(); + void shouldNotGenerateLangForVCard3(); +}; + +#endif // LANGTEST_H diff --git a/autotests/ldifconvertertest.cpp b/autotests/ldifconvertertest.cpp new file mode 100644 index 0000000..289e7ff --- /dev/null +++ b/autotests/ldifconvertertest.cpp @@ -0,0 +1,500 @@ +/* + This file is part of libkabc. + Copyright (c) 2015 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 "ldifconvertertest.h" +#include "converter/ldifconverter.h" +#include +using namespace KContacts; + +LDifConverterTest::LDifConverterTest(QObject *parent) + : QObject(parent) +{ + +} + +LDifConverterTest::~LDifConverterTest() +{ + +} + +void LDifConverterTest::shouldImportEmail() +{ + QString str = QStringLiteral("dn: cn=laurent,mail=foo@kde.org\n" + "sn: laurent\n" + "cn: laurent\n" + "uid: d1d5cdd4-7d5d-484b-828d-58864d8efe74\n" + "mail: foo@kde.org\n" + "objectclass: top_n" + "objectclass: person\n" + "objectclass: organizationalPerson"); + AddresseeList lst; + ContactGroup::List contactGroup; + bool result = LDIFConverter::LDIFToAddressee(str, lst, contactGroup); + QVERIFY(result); + QCOMPARE(lst.count(), 1); + QCOMPARE(lst.at(0).emails().count(), 1); + QCOMPARE(lst.at(0).emails().at(0), QStringLiteral("foo@kde.org")); + QCOMPARE(contactGroup.count(), 0); +} + +void LDifConverterTest::shouldImportMultiEmails() +{ + QString str = QStringLiteral("dn: cn=laurent,mail=foo@kde.org\n" + "sn: laurent\n" + "cn: laurent\n" + "uid: d1d5cdd4-7d5d-484b-828d-58864d8efe74\n" + "mail: foo@kde.org\n" + "mail: foo2@kde.org\n" + "objectclass: top_n" + "objectclass: person\n" + "objectclass: organizationalPerson"); + AddresseeList lst; + ContactGroup::List contactGroup; + bool result = LDIFConverter::LDIFToAddressee(str, lst, contactGroup); + QVERIFY(result); + QCOMPARE(lst.count(), 1); + QCOMPARE(lst.at(0).emails().count(), 2); + QCOMPARE(lst.at(0).emails().at(0), QStringLiteral("foo@kde.org")); + QCOMPARE(lst.at(0).emails().at(1), QStringLiteral("foo2@kde.org")); + QCOMPARE(contactGroup.count(), 0); +} + +void LDifConverterTest::shouldImportStandardBirthday() +{ + QString str = QStringLiteral("dn: cn=laurent,mail=foo@kde.org\n" + "sn: laurent\n" + "cn: laurent\n" + "uid: d1d5cdd4-7d5d-484b-828d-58864d8efe74\n" + "birthyear: 2015\n" + "birthmonth: 3\n" + "birthday: 19\n" + "mail: foo@kde.org\n" + "objectclass: top_n" + "objectclass: person\n" + "objectclass: organizationalPerson"); + AddresseeList lst; + ContactGroup::List contactGroup; + bool result = LDIFConverter::LDIFToAddressee(str, lst, contactGroup); + QVERIFY(result); + QCOMPARE(lst.count(), 1); + QVERIFY(lst.at(0).birthday().date().isValid()); + QCOMPARE(lst.at(0).birthday().date(), QDate(2015, 3, 19)); + QCOMPARE(contactGroup.count(), 0); +} + +void LDifConverterTest::shouldImportTheBatsBirthday() +{ + QString str = QStringLiteral("dn: cn=laurent,mail=foo@kde.org\n" + "sn: laurent\n" + "cn: laurent\n" + "uid: d1d5cdd4-7d5d-484b-828d-58864d8efe74\n" + "xbatBirthday: 20150319\n" + "mail: foo@kde.org\n" + "objectclass: top_n" + "objectclass: person\n" + "objectclass: organizationalPerson"); + AddresseeList lst; + ContactGroup::List contactGroup; + bool result = LDIFConverter::LDIFToAddressee(str, lst, contactGroup); + QVERIFY(result); + QCOMPARE(lst.count(), 1); + QVERIFY(lst.at(0).birthday().date().isValid()); + QCOMPARE(lst.at(0).birthday().date(), QDate(2015, 3, 19)); + QCOMPARE(contactGroup.count(), 0); +} + +void LDifConverterTest::shouldImportTheBatsEmails() +{ + QString str = QStringLiteral("dn: cn=laurent,mail=foo@kde.org\n" + "sn: laurent\n" + "cn: laurent\n" + "uid: d1d5cdd4-7d5d-484b-828d-58864d8efe74\n" + "mail: foo@kde.org\n" + "othermailbox: foo2@kde.org\n" + "othermailbox: foo3@kde.org\n" + "objectclass: top_n" + "objectclass: person\n" + "objectclass: organizationalPerson"); + AddresseeList lst; + ContactGroup::List contactGroup; + bool result = LDIFConverter::LDIFToAddressee(str, lst, contactGroup); + QVERIFY(result); + QCOMPARE(lst.count(), 1); + QCOMPARE(lst.at(0).emails().count(), 3); + QCOMPARE(lst.at(0).emails().at(0), QStringLiteral("foo@kde.org")); + QCOMPARE(lst.at(0).emails().at(1), QStringLiteral("foo2@kde.org")); + QCOMPARE(lst.at(0).emails().at(2), QStringLiteral("foo3@kde.org")); + QCOMPARE(contactGroup.count(), 0); +} + +void LDifConverterTest::shouldImportTitle() +{ + QString str = QStringLiteral("dn: cn=laurent,mail=foo@kde.org\n" + "sn: laurent\n" + "cn: laurent\n" + "uid: d1d5cdd4-7d5d-484b-828d-58864d8efe74\n" + "title: foo\n" + "mail: foo@kde.org\n" + "objectclass: top_n" + "objectclass: person\n" + "objectclass: organizationalPerson"); + AddresseeList lst; + ContactGroup::List contactGroup; + bool result = LDIFConverter::LDIFToAddressee(str, lst, contactGroup); + QVERIFY(result); + QCOMPARE(lst.count(), 1); + QCOMPARE(lst.at(0).title(), QStringLiteral("foo")); + QCOMPARE(contactGroup.count(), 0); +} + +void LDifConverterTest::shouldImportWorkStreet() +{ + QString str = QStringLiteral("dn: cn=laurent,mail=foo@kde.org\n" + "sn: laurent\n" + "cn: laurent\n" + "uid: d1d5cdd4-7d5d-484b-828d-58864d8efe74\n" + "title: foo\n" + "mail: foo@kde.org\n" + "street: work address\n" + "mozillaWorkStreet2: work address next\n" + "objectclass: top_n" + "objectclass: person\n" + "objectclass: organizationalPerson"); + AddresseeList lst; + ContactGroup::List contactGroup; + bool result = LDIFConverter::LDIFToAddressee(str, lst, contactGroup); + QVERIFY(result); + QCOMPARE(lst.count(), 1); + QCOMPARE(lst.at(0).address(Address::Work).street(), QStringLiteral("work address\nwork address next")); + QCOMPARE(contactGroup.count(), 0); +} + +void LDifConverterTest::shouldImportContactGroup() +{ + QString str = QStringLiteral("dn: cn=test,mail=\n" + "cn: test\n" + "modifyTimeStamp: 20080526T234914Z\n" + "display-name: Test\n" + "objectclass: top\n" + "objectclass: groupOfNames\n" + "member: cn=Jim Doe,mail=jim.doe@foobar.com\n" + "member: cn=Jane Doe,mail=jane.doe@foobar.com\n" + "member: cn=John Doe,mail=john.doe@foobar.com\n"); + AddresseeList lst; + ContactGroup::List contactGroup; + bool result = LDIFConverter::LDIFToAddressee(str, lst, contactGroup); + QVERIFY(result); + QCOMPARE(lst.count(), 0); + QCOMPARE(contactGroup.count(), 1); + ContactGroup first = contactGroup.first(); + QCOMPARE(first.name(), QStringLiteral("Test")); + QCOMPARE((int)first.count(), 3); +} + +void LDifConverterTest::shouldImportMultiEntries() +{ + QString str = QStringLiteral("dn: cn=test1,mail=test1@test.test\n" + "sn: test1\n" + "cn: test1\n" + "uid: jpgdf2NrLQ\n" + "mail: test1@test.test\n" + "modifytimestamp: 20121219T140848Z\n" + "objectclass: top\n" + "objectclass: person\n" + "objectclass: organizationalPerson\n" + "\n" + "dn: cn=test2,mail=test2@test.test\n" + "sn: test2\n" + "cn: test2\n" + "uid: ow2mwdUb6A\n" + "mail: test2@test.test\n" + "objectclass: top\n" + "objectclass: person\n" + "objectclass: organizationalPerson\n"); + AddresseeList lst; + ContactGroup::List contactGroup; + bool result = LDIFConverter::LDIFToAddressee(str, lst, contactGroup); + QVERIFY(result); + QCOMPARE(lst.count(), 2); + QCOMPARE(contactGroup.count(), 0); + QCOMPARE(lst.at(0).emails().at(0), QStringLiteral("test1@test.test")); + QCOMPARE(lst.at(1).emails().at(0), QStringLiteral("test2@test.test")); +} + +void LDifConverterTest::shouldImportGroupAndAddress() +{ + QString str = QStringLiteral("dn: cn=laurent,mail=foo@kde.org\n" + "sn: laurent\n" + "cn: laurent\n" + "uid: d1d5cdd4-7d5d-484b-828d-58864d8efe74\n" + "title: foo\n" + "mail: foo@kde.org\n" + "street: work address\n" + "mozillaWorkStreet2: work address next\n" + "objectclass: top_n" + "objectclass: person\n" + "objectclass: organizationalPerson\n" + "\n" + "dn: cn=test,mail=\n" + "cn: test\n" + "modifyTimeStamp: 20080526T234914Z\n" + "display-name: Test\n" + "objectclass: top\n" + "objectclass: groupOfNames\n" + "member: cn=Jim Doe,mail=jim.doe@foobar.com\n" + "member: cn=Jane Doe,mail=jane.doe@foobar.com\n" + "member: cn=John Doe,mail=john.doe@foobar.com\n"); + + AddresseeList lst; + ContactGroup::List contactGroup; + bool result = LDIFConverter::LDIFToAddressee(str, lst, contactGroup); + QVERIFY(result); + QCOMPARE(lst.count(), 1); + QCOMPARE(contactGroup.count(), 1); +} + +void LDifConverterTest::shouldExportEmail() +{ + AddresseeList lst; + ContactGroup::List contactGroup; + Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + lst << addr; + QString str; + bool result = LDIFConverter::addresseeAndContactGroupToLDIF(lst, contactGroup, str); + QVERIFY(result); + QString expected = QStringLiteral("dn: cn=,mail=foo@kde.org\n" + "objectclass: top\n" + "objectclass: person\n" + "objectclass: organizationalPerson\n" + "uid: testuid\n" + "mail: foo@kde.org\n\n"); + + QCOMPARE(str, expected); +} + +void LDifConverterTest::shouldExportMultiEmails() +{ + AddresseeList lst; + ContactGroup::List contactGroup; + Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org") << QStringLiteral("foo2@kde.org") << QStringLiteral("foo3@kde.org")); + addr.setUid(QStringLiteral("testuid")); + lst << addr; + QString str; + bool result = LDIFConverter::addresseeAndContactGroupToLDIF(lst, contactGroup, str); + QVERIFY(result); + QString expected = QStringLiteral("dn: cn=,mail=foo@kde.org\n" + "objectclass: top\n" + "objectclass: person\n" + "objectclass: organizationalPerson\n" + "uid: testuid\n" + "mail: foo@kde.org\n" + "mozillasecondemail: foo2@kde.org\n" + "othermailbox: foo3@kde.org\n" + "\n"); + + QCOMPARE(str, expected); + +} + +void LDifConverterTest::shouldExportBirthday() +{ + AddresseeList lst; + ContactGroup::List contactGroup; + Addressee addr; + QDate date(2015, 3, 3); + addr.setBirthday(QDateTime(date)); + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + lst << addr; + QString str; + bool result = LDIFConverter::addresseeAndContactGroupToLDIF(lst, contactGroup, str); + QVERIFY(result); + QString expected = QStringLiteral("dn: cn=,mail=foo@kde.org\n" + "objectclass: top\n" + "objectclass: person\n" + "objectclass: organizationalPerson\n" + "uid: testuid\n" + "mail: foo@kde.org\n" + "birthyear: 2015\n" + "birthmonth: 3\n" + "birthday: 3\n" + "\n"); + + QCOMPARE(str, expected); +} + +void LDifConverterTest::shouldExportTitle() +{ + AddresseeList lst; + ContactGroup::List contactGroup; + Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setTitle(QStringLiteral("foo")); + addr.setUid(QStringLiteral("testuid")); + lst << addr; + QString str; + bool result = LDIFConverter::addresseeAndContactGroupToLDIF(lst, contactGroup, str); + QVERIFY(result); + QString expected = QStringLiteral("dn: cn=,mail=foo@kde.org\n" + "objectclass: top\n" + "objectclass: person\n" + "objectclass: organizationalPerson\n" + "uid: testuid\n" + "mail: foo@kde.org\n" + "title: foo\n" + "\n"); + + QCOMPARE(str, expected); +} + +void LDifConverterTest::shouldExportMultiEntries() +{ + AddresseeList lst; + ContactGroup::List contactGroup; + Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setTitle(QStringLiteral("foo")); + addr.setUid(QStringLiteral("testuid")); + lst << addr; + + Addressee addr2; + QDate date(2015, 3, 3); + addr2.setBirthday(QDateTime(date)); + addr2.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr2.setUid(QStringLiteral("testuid")); + lst << addr2; + + QString str; + bool result = LDIFConverter::addresseeAndContactGroupToLDIF(lst, contactGroup, str); + QVERIFY(result); + + const QString expected = QStringLiteral("dn: cn=,mail=foo@kde.org\n" + "objectclass: top\n" + "objectclass: person\n" + "objectclass: organizationalPerson\n" + "uid: testuid\n" + "mail: foo@kde.org\n" + "title: foo\n" + "\n" + "dn: cn=,mail=foo@kde.org\n" + "objectclass: top\n" + "objectclass: person\n" + "objectclass: organizationalPerson\n" + "uid: testuid\n" + "mail: foo@kde.org\n" + "birthyear: 2015\n" + "birthmonth: 3\n" + "birthday: 3\n" + "\n"); + QCOMPARE(str, expected); +} + +void LDifConverterTest::shouldExportGroup() +{ + AddresseeList lst; + ContactGroup::List contactGroup; + ContactGroup grp; + ContactGroup::Data data; + data.setEmail(QStringLiteral("foo@kde.org")); + data.setName(QStringLiteral("foo")); + grp.append(data); + ContactGroup::Data data2; + data2.setEmail(QStringLiteral("foo2@kde.org")); + data2.setName(QStringLiteral("foo2")); + grp.append(data2); + contactGroup.append(grp); + + QString str; + bool result = LDIFConverter::addresseeAndContactGroupToLDIF(lst, contactGroup, str); + QVERIFY(result); + + const QString expected = QStringLiteral("objectclass: top\n" + "objectclass: groupOfNames\n" + "member: cn=foo,mail=foo@kde.org\n" + "member: cn=foo2,mail=foo2@kde.org\n" + "\n"); + QCOMPARE(str, expected); +} + +void LDifConverterTest::shouldExportWorkStreet() +{ + AddresseeList lst; + Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + Address address(Address::Work); + address.setStreet(QStringLiteral("work address")); + address.setPostalCode(QStringLiteral("postal")); + addr.insertAddress(address); + lst << addr; + ContactGroup::List contactGroup; + + QString str; + bool result = LDIFConverter::addresseeAndContactGroupToLDIF(lst, contactGroup, str); + QVERIFY(result); + + const QString expected = QStringLiteral("dn: cn=,mail=foo@kde.org\n" + "objectclass: top\n" + "objectclass: person\n" + "objectclass: organizationalPerson\n" + "uid: testuid\n" + "mail: foo@kde.org\n" + "postalcode: postal\n" + "streetaddress: work address\n" + "street: work address\n" + "\n"); + QCOMPARE(str, expected); +} + +void LDifConverterTest::shouldExportFullName() +{ + AddresseeList lst; + Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + addr.setName(QStringLiteral("name")); + addr.setNickName(QStringLiteral("nickname")); + addr.setFamilyName(QStringLiteral("familyname")); + lst << addr; + ContactGroup::List contactGroup; + + QString str; + bool result = LDIFConverter::addresseeAndContactGroupToLDIF(lst, contactGroup, str); + QVERIFY(result); + + const QString expected = QStringLiteral("dn: cn=,mail=foo@kde.org\n" + "objectclass: top\n" + "objectclass: person\n" + "objectclass: organizationalPerson\n" + "sn: familyname\n" + "uid: testuid\n" + "nickname: nickname\n" + "xmozillanickname: nickname\n" + "mozillanickname: nickname\n" + "mail: foo@kde.org\n" + "\n"); + + QCOMPARE(str, expected); +} + +QTEST_MAIN(LDifConverterTest) diff --git a/autotests/ldifconvertertest.h b/autotests/ldifconvertertest.h new file mode 100644 index 0000000..a7ef354 --- /dev/null +++ b/autotests/ldifconvertertest.h @@ -0,0 +1,57 @@ +/* + This file is part of libkabc. + Copyright (c) 2015 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 LDIFCONVERTERTEST_H +#define LDIFCONVERTERTEST_H + +#include + +class LDifConverterTest : public QObject +{ + Q_OBJECT +public: + explicit LDifConverterTest(QObject *parent = Q_NULLPTR); + ~LDifConverterTest(); + +private Q_SLOTS: + //Import + void shouldImportEmail(); + void shouldImportMultiEmails(); + void shouldImportStandardBirthday(); + void shouldImportTheBatsBirthday(); + void shouldImportTheBatsEmails(); + void shouldImportTitle(); + void shouldImportWorkStreet(); + void shouldImportContactGroup(); + void shouldImportMultiEntries(); + void shouldImportGroupAndAddress(); + + //Export + void shouldExportEmail(); + void shouldExportBirthday(); + void shouldExportTitle(); + void shouldExportMultiEntries(); + void shouldExportGroup(); + void shouldExportWorkStreet(); + void shouldExportMultiEmails(); + void shouldExportFullName(); +}; + +#endif // LDIFCONVERTERTEST_H diff --git a/autotests/phonenumbertest.cpp b/autotests/phonenumbertest.cpp new file mode 100644 index 0000000..fead9b1 --- /dev/null +++ b/autotests/phonenumbertest.cpp @@ -0,0 +1,173 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2007 Tobias Koenig + + 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 "phonenumbertest.h" +#include "kcontacts/phonenumber.h" +#include + +QTEST_MAIN(PhoneNumberTest) + +void PhoneNumberTest::emptyTest() +{ + KContacts::PhoneNumber number; + + QVERIFY(number.isEmpty()); +} + +void PhoneNumberTest::storeTest() +{ + KContacts::PhoneNumber number; + + number.setId(QStringLiteral("My Id")); + number.setType(KContacts::PhoneNumber::Work | KContacts::PhoneNumber::Cell); + number.setNumber(QStringLiteral("2734826345")); + + QVERIFY(number.id() == QLatin1String("My Id")); + QVERIFY(number.type() == (KContacts::PhoneNumber::Work | KContacts::PhoneNumber::Cell)); + QVERIFY(number.number() == QLatin1String("2734826345")); +} + +void PhoneNumberTest::equalsTest() +{ + KContacts::PhoneNumber number1, number2; + + number1.setId(QStringLiteral("My Id")); + number1.setType(KContacts::PhoneNumber::Work | KContacts::PhoneNumber::Cell); + number1.setNumber(QStringLiteral("2734826345")); + + number2.setId(QStringLiteral("My Id")); + number2.setType(KContacts::PhoneNumber::Work | KContacts::PhoneNumber::Cell); + number2.setNumber(QStringLiteral("2734826345")); + + QVERIFY(number1 == number2); +} + +void PhoneNumberTest::differsTest() +{ + KContacts::PhoneNumber number1(QStringLiteral("123"), KContacts::PhoneNumber::Home); + KContacts::PhoneNumber number2(QStringLiteral("123"), KContacts::PhoneNumber::Work); + + QVERIFY(number1 != number2); +} + +void PhoneNumberTest::assignmentTest() +{ + KContacts::PhoneNumber number1, number2; + + number1.setId(QStringLiteral("My Id")); + number1.setType(KContacts::PhoneNumber::Work | KContacts::PhoneNumber::Cell); + number1.setNumber(QStringLiteral("2734826345")); + + number1 = number2; + + QVERIFY(number1 == number2); +} + +void PhoneNumberTest::serializeTest() +{ + KContacts::PhoneNumber number1, number2; + + number1.setId(QStringLiteral("My Id")); + number1.setType(KContacts::PhoneNumber::Work | KContacts::PhoneNumber::Cell); + number1.setNumber(QStringLiteral("2734826345")); + + QByteArray data; + QDataStream s(&data, QIODevice::WriteOnly); + s << number1; + + QDataStream t(&data, QIODevice::ReadOnly); + t >> number2; + + QVERIFY(number1 == number2); +} + +void PhoneNumberTest::labelTest() +{ + QMap labels; + + const KContacts::PhoneNumber::TypeList types = KContacts::PhoneNumber::typeList(); + + // check all types standalone + Q_FOREACH (KContacts::PhoneNumber::Type type, types) { + const KContacts::PhoneNumber phone(QStringLiteral("1"), type); + QCOMPARE(phone.type(), type); + + // Pref is special cased + if (type != KContacts::PhoneNumber::Pref) { + QCOMPARE(phone.typeLabel(), KContacts::PhoneNumber::typeFlagLabel((KContacts::PhoneNumber::TypeFlag)(int)type)); + labels.insert(type, phone.typeLabel()); + } else { + labels.insert(type, KContacts::PhoneNumber::typeFlagLabel((KContacts::PhoneNumber::TypeFlag)(int)type)); + } + QCOMPARE(KContacts::PhoneNumber::typeLabel(type), phone.typeLabel()); + } + + // combine all with Pref + Q_FOREACH (KContacts::PhoneNumber::Type type, types) { + KContacts::PhoneNumber::Type combinedType = type | KContacts::PhoneNumber::Pref; + const KContacts::PhoneNumber phone(QLatin1String("1"), combinedType); + QCOMPARE(phone.type(), combinedType); + QCOMPARE(KContacts::PhoneNumber::typeLabel(combinedType), phone.typeLabel()); + + if (type < KContacts::PhoneNumber::Pref) { + const QString expectedCombinedString = QStringLiteral("%1/%2").arg(labels[type]).arg(labels[KContacts::PhoneNumber::Pref]); + QCOMPARE(phone.typeLabel(), expectedCombinedString); + } else if (type > KContacts::PhoneNumber::Pref) { + const QString expectedCombinedString = QStringLiteral("%1/%2").arg(labels[KContacts::PhoneNumber::Pref]).arg(labels[type]); + QCOMPARE(phone.typeLabel(), expectedCombinedString); + } + } + + // combine all with Fax + Q_FOREACH (KContacts::PhoneNumber::Type type, types) { + KContacts::PhoneNumber::Type combinedType = type | KContacts::PhoneNumber::Fax; + const KContacts::PhoneNumber phone(QLatin1String("1"), combinedType); + QCOMPARE(phone.type(), combinedType); + QCOMPARE(KContacts::PhoneNumber::typeLabel(combinedType), phone.typeLabel()); + + if (type == KContacts::PhoneNumber::Home || + type == KContacts::PhoneNumber::Work) { + // special cased + } else if (type < KContacts::PhoneNumber::Fax) { + const QString expectedCombinedString = QStringLiteral("%1/%2").arg(labels[type]).arg(labels[KContacts::PhoneNumber::Fax]); + QCOMPARE(phone.typeLabel(), expectedCombinedString); + } else if (type > KContacts::PhoneNumber::Fax) { + const QString expectedCombinedString = QStringLiteral("%1/%2").arg(labels[KContacts::PhoneNumber::Fax]).arg(labels[type]); + QCOMPARE(phone.typeLabel(), expectedCombinedString); + } + } + + // special cases + QCOMPARE(KContacts::PhoneNumber::typeLabel(KContacts::PhoneNumber::Pref), QLatin1String("Preferred Number")); + QCOMPARE(KContacts::PhoneNumber::typeLabel(KContacts::PhoneNumber::Home | + KContacts::PhoneNumber::Fax), + QLatin1String("Home Fax")); + QCOMPARE(KContacts::PhoneNumber::typeLabel(KContacts::PhoneNumber::Work | + KContacts::PhoneNumber::Fax), + QLatin1String("Work Fax")); + QCOMPARE(KContacts::PhoneNumber::typeLabel(KContacts::PhoneNumber::Home | + KContacts::PhoneNumber::Fax | + KContacts::PhoneNumber::Pref), + QLatin1String("Home Fax/Preferred")); + QCOMPARE(KContacts::PhoneNumber::typeLabel(KContacts::PhoneNumber::Work | + KContacts::PhoneNumber::Fax | + KContacts::PhoneNumber::Pref), + QLatin1String("Work Fax/Preferred")); +} diff --git a/autotests/phonenumbertest.h b/autotests/phonenumbertest.h new file mode 100644 index 0000000..3920ba5 --- /dev/null +++ b/autotests/phonenumbertest.h @@ -0,0 +1,40 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2007 Tobias Koenig + + 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 PHONENUMBER_TEST_H +#define PHONENUMBER_TEST_H + +#include + +class PhoneNumberTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void emptyTest(); + void storeTest(); + void equalsTest(); + void differsTest(); + void assignmentTest(); + void serializeTest(); + void labelTest(); +}; + +#endif diff --git a/autotests/picturetest.cpp b/autotests/picturetest.cpp new file mode 100644 index 0000000..8893e65 --- /dev/null +++ b/autotests/picturetest.cpp @@ -0,0 +1,267 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2007 Tobias Koenig + + 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 "picturetest.h" +#include "kcontacts/picture.h" +#include +#include +#include + +QTEST_MAIN(PictureTest) + +static QImage testImage() +{ + static QImage image; + + if (image.isNull()) { + image = QImage(200, 200, QImage::Format_RGB32); + QPainter p(&image); + p.drawRect(10, 10, 50, 50); + } + + return image; +} + +static QByteArray testImageRawPNG() +{ + static QByteArray raw; + + if (raw.isNull()) { + QBuffer buffer(&raw); + buffer.open(QIODevice::WriteOnly); + testImage().save(&buffer, "PNG"); + } + + return raw; +} + +static QByteArray testImageRawJPEG() +{ + static QByteArray raw; + + if (raw.isNull()) { + QBuffer buffer(&raw); + buffer.open(QIODevice::WriteOnly); + testImage().save(&buffer, "JPEG"); + } + + return raw; +} + +void PictureTest::emptyTest() +{ + KContacts::Picture picture; + + QVERIFY(picture.isEmpty()); +} + +void PictureTest::storeTestInternImage() +{ + KContacts::Picture picture; + + picture.setData(testImage()); + + QVERIFY(picture.isEmpty() == false); + QVERIFY(picture.isIntern() == true); + QVERIFY(picture.type() == QLatin1String("jpeg")); + QVERIFY(picture.data() == testImage()); + QVERIFY(picture.rawData() == testImageRawJPEG()); +} + +void PictureTest::storeTestInternRawData() +{ + KContacts::Picture picture; + + picture.setRawData(testImageRawPNG(), QStringLiteral("png")); + + QVERIFY(picture.isEmpty() == false); + QVERIFY(picture.isIntern() == true); + QVERIFY(picture.type() == QLatin1String("png")); + QVERIFY(picture.rawData() == testImageRawPNG()); + QVERIFY(picture.data() == testImage()); +} + +void PictureTest::storeTestExtern() +{ + KContacts::Picture picture; + + picture.setUrl(QStringLiteral("http://myhomepage.com/foto.png"), QStringLiteral("png")); + + QVERIFY(picture.isEmpty() == false); + QVERIFY(picture.isIntern() == false); + QVERIFY(picture.type() == QLatin1String("png")); + QVERIFY(picture.url() == QLatin1String("http://myhomepage.com/foto.png")); +} + +void PictureTest::equalsTestInternImage() +{ + KContacts::Picture picture1, picture2; + + picture1.setData(testImage()); + + picture2.setData(testImage()); + + QVERIFY(picture1 == picture2); + + // access rawData() so a QByteArray is created + picture1.rawData(); + QVERIFY(picture1 == picture2); +} + +void PictureTest::equalsTestInternRawData() +{ + KContacts::Picture picture1, picture2; + + picture1.setRawData(testImageRawPNG(), QStringLiteral("png")); + + picture2.setRawData(testImageRawPNG(), QStringLiteral("png")); + + QVERIFY(picture1 == picture2); + + // access data() so a QImage is created + picture1.data(); + QVERIFY(picture1 == picture2); +} + +void PictureTest::equalsTestInternImageAndRawData() +{ + KContacts::Picture picture1, picture2; + + picture1.setData(testImage()); + + picture2.setRawData(testImageRawJPEG(), QStringLiteral("jpeg")); + + QVERIFY(picture1.rawData() == picture2.rawData()); +} + +void PictureTest::equalsTestExtern() +{ + KContacts::Picture picture1, picture2; + + picture1.setUrl(QStringLiteral("http://myhomepage.com/foto.png"), QStringLiteral("png")); + + picture2.setUrl(QStringLiteral("http://myhomepage.com/foto.png"), QStringLiteral("png")); + + QVERIFY(picture1 == picture2); +} + +void PictureTest::differsTest() +{ + KContacts::Picture picture1, picture2; + + picture1.setUrl(QStringLiteral("http://myhomepage.com/foto.png"), QStringLiteral("png")); + + picture2.setData(testImage()); + + QVERIFY(picture1 != picture2); +} + +void PictureTest::differsTestInternRawData() +{ + KContacts::Picture picture1, picture2; + + picture1.setRawData(testImageRawJPEG(), QStringLiteral("jpeg")); + + picture2.setRawData(testImageRawPNG(), QStringLiteral("png")); + + QVERIFY(picture1 != picture2); + QVERIFY(picture1.rawData() != picture2.rawData()); +} + +void PictureTest::differsTestExtern() +{ + KContacts::Picture picture1, picture2; + + picture1.setUrl(QStringLiteral("http://myhomepage.com/foto.png"), QStringLiteral("png")); + + picture1.setUrl(QStringLiteral("http://myhomepage.com/foto2.png"), QStringLiteral("png")); + + QVERIFY(picture1 != picture2); +} + +void PictureTest::assignmentTestIntern() +{ + KContacts::Picture picture1, picture2; + + picture1.setData(testImage()); + + picture2 = picture1; + + QVERIFY(picture1 == picture2); +} + +void PictureTest::assignmentTestExtern() +{ + KContacts::Picture picture1, picture2; + + picture1.setUrl(QStringLiteral("http://myhomepage.com/foto.png"), QStringLiteral("png")); + + picture2 = picture1; + + QVERIFY(picture1 == picture2); +} + +void PictureTest::serializeTestInternImage() +{ + KContacts::Picture picture1, picture2; + + picture1.setData(testImage()); + + QByteArray data; + QDataStream s(&data, QIODevice::WriteOnly); + s << picture1; + + QDataStream t(&data, QIODevice::ReadOnly); + t >> picture2; + + QVERIFY(picture1 == picture2); +} + +void PictureTest::serializeTestInternRawData() +{ + KContacts::Picture picture1, picture2; + + picture1.setRawData(testImageRawPNG(), QStringLiteral("png")); + + QByteArray data; + QDataStream s(&data, QIODevice::WriteOnly); + s << picture1; + + QDataStream t(&data, QIODevice::ReadOnly); + t >> picture2; + + QVERIFY(picture1 == picture2); +} + +void PictureTest::serializeTestExtern() +{ + KContacts::Picture picture1, picture2; + + picture1.setUrl(QStringLiteral("http://myhomepage.com/foto.png"), QStringLiteral("png")); + + QByteArray data; + QDataStream s(&data, QIODevice::WriteOnly); + s << picture1; + + QDataStream t(&data, QIODevice::ReadOnly); + t >> picture2; + + QVERIFY(picture1 == picture2); +} diff --git a/autotests/picturetest.h b/autotests/picturetest.h new file mode 100644 index 0000000..34d84f4 --- /dev/null +++ b/autotests/picturetest.h @@ -0,0 +1,49 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2007 Tobias Koenig + + 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 PICTURE_TEST_H +#define PICTURE_TEST_H + +#include + +class PictureTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void emptyTest(); + void storeTestInternImage(); + void storeTestInternRawData(); + void storeTestExtern(); + void equalsTestInternImage(); + void equalsTestInternRawData(); + void equalsTestInternImageAndRawData(); + void equalsTestExtern(); + void differsTest(); + void differsTestInternRawData(); + void differsTestExtern(); + void assignmentTestIntern(); + void assignmentTestExtern(); + void serializeTestInternImage(); + void serializeTestInternRawData(); + void serializeTestExtern(); +}; + +#endif diff --git a/autotests/relatedtest.cpp b/autotests/relatedtest.cpp new file mode 100644 index 0000000..1f2167b --- /dev/null +++ b/autotests/relatedtest.cpp @@ -0,0 +1,243 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2015 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 "relatedtest.h" +#include "related.h" +#include "vcardtool.h" +#include + +RelatedTest::RelatedTest(QObject *parent) + : QObject(parent) +{ + +} + +RelatedTest::~RelatedTest() +{ + +} + +void RelatedTest::shouldHaveDefaultValue() +{ + KContacts::Related related; + QVERIFY(!related.isValid()); + QVERIFY(related.related().isEmpty()); + QVERIFY(related.parameters().isEmpty()); +} + +void RelatedTest::shouldAssignValue() +{ + const QString relatedTo(QStringLiteral("friend")); + QMap params; + params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + KContacts::Related related(relatedTo); + related.setParameters(params); + QVERIFY(related.isValid()); + QVERIFY(!related.related().isEmpty()); + QCOMPARE(related.related(), relatedTo); + QVERIFY(!related.parameters().isEmpty()); + QCOMPARE(related.parameters(), params); + +} + +void RelatedTest::shouldAssignExternal() +{ + KContacts::Related related; + const QString relatedTo(QStringLiteral("friend")); + related.setRelated(relatedTo); + QVERIFY(related.isValid()); + QCOMPARE(related.related(), relatedTo); +} + +void RelatedTest::shouldSerialized() +{ + KContacts::Related related; + KContacts::Related result; + const QString relatedTo(QStringLiteral("friend")); + related.setRelated(relatedTo); + QMap params; + params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + related.setParameters(params); + + QByteArray data; + QDataStream s(&data, QIODevice::WriteOnly); + s << related; + + QDataStream t(&data, QIODevice::ReadOnly); + t >> result; + + QVERIFY(related == result); +} + +void RelatedTest::shouldEqualRelated() +{ + KContacts::Related related; + KContacts::Related result; + const QString relatedTo(QStringLiteral("friend")); + related.setRelated(relatedTo); + QMap params; + params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + related.setParameters(params); + + result = related; + QVERIFY(related == result); +} + +void RelatedTest::shouldParseRelated() +{ + QByteArray vcarddata("BEGIN:VCARD\n" + "VERSION:4.0\n" + "N:LastName;FirstName;;;\n" + "UID:c80cf296-0825-4eb0-ab16-1fac1d522a33@xxxxxx.xx\n" + "RELATED:friend" + "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); + QCOMPARE(lst.at(0).relationShips().count(), 1); +} + +void RelatedTest::shouldParseWithoutRelated() +{ + 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); + QCOMPARE(lst.at(0).relationShips().count(), 0); +} + +void RelatedTest::shouldCreateVCard4() +{ + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + KContacts::Related::List lstRelated; + KContacts::Related related(QStringLiteral("friend")); + lstRelated << related; + addr.setRelationShips(lstRelated); + lst << addr; + KContacts::VCardTool vcard; + const 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" + "N:;;;;\r\n" + "RELATED:friend\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + + QCOMPARE(ba, expected); +} + +void RelatedTest::shouldCreateVCardWithTwoRelated() +{ + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + KContacts::Related::List lstRelated; + KContacts::Related related(QStringLiteral("friend")); + KContacts::Related related2(QStringLiteral("kde")); + lstRelated << related << related2; + addr.setRelationShips(lstRelated); + lst << addr; + KContacts::VCardTool vcard; + const 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" + "N:;;;;\r\n" + "RELATED:friend\r\n" + "RELATED:kde\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + + QCOMPARE(ba, expected); + +} + +void RelatedTest::shouldCreateVCardWithParameters() +{ + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + KContacts::Related::List lstRelated; + KContacts::Related related(QStringLiteral("friend")); + QMap params; + params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + related.setParameters(params); + lstRelated << related; + addr.setRelationShips(lstRelated); + lst << addr; + KContacts::VCardTool vcard; + const 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" + "N:;;;;\r\n" + "RELATED;FOO1=bla1,blo1;FOO2=bla2,blo2:friend\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + QCOMPARE(ba, expected); +} + +void RelatedTest::shouldNotExportInVcard3() +{ + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + KContacts::Related::List lstRelated; + KContacts::Related related(QStringLiteral("friend")); + QMap params; + params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + related.setParameters(params); + lstRelated << related; + addr.setRelationShips(lstRelated); + lst << addr; + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v3_0); + QByteArray expected("BEGIN:VCARD\r\n" + "VERSION:3.0\r\n" + "EMAIL:foo@kde.org\r\n" + "N:;;;;\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + QCOMPARE(ba, expected); +} + +QTEST_MAIN(RelatedTest) diff --git a/autotests/relatedtest.h b/autotests/relatedtest.h new file mode 100644 index 0000000..14eac7d --- /dev/null +++ b/autotests/relatedtest.h @@ -0,0 +1,46 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2015 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 RELATEDTEST_H +#define RELATEDTEST_H + +#include + +class RelatedTest : public QObject +{ + Q_OBJECT +public: + explicit RelatedTest(QObject *parent = Q_NULLPTR); + ~RelatedTest(); +private Q_SLOTS: + void shouldHaveDefaultValue(); + void shouldAssignValue(); + void shouldAssignExternal(); + void shouldSerialized(); + void shouldEqualRelated(); + void shouldParseRelated(); + void shouldParseWithoutRelated(); + void shouldCreateVCard4(); + void shouldCreateVCardWithTwoRelated(); + void shouldCreateVCardWithParameters(); + void shouldNotExportInVcard3(); +}; + +#endif // RELATEDTEST_H diff --git a/autotests/resourcelocatorurltest.cpp b/autotests/resourcelocatorurltest.cpp new file mode 100644 index 0000000..b14f3ba --- /dev/null +++ b/autotests/resourcelocatorurltest.cpp @@ -0,0 +1,229 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2015 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 "resourcelocatorurltest.h" + +#include "resourcelocatorurl.h" +#include "vcardtool.h" +#include + +using namespace KContacts; +ResourceLocatorUrlTest::ResourceLocatorUrlTest(QObject *parent) + : QObject(parent) +{ + +} + +ResourceLocatorUrlTest::~ResourceLocatorUrlTest() +{ + +} + +void ResourceLocatorUrlTest::shouldHaveDefaultValue() +{ + ResourceLocatorUrl ResourceLocatorUrl; + QVERIFY(!ResourceLocatorUrl.isValid()); + QVERIFY(ResourceLocatorUrl.url().isEmpty()); + QVERIFY(ResourceLocatorUrl.parameters().isEmpty()); +} + +void ResourceLocatorUrlTest::shouldAssignValue() +{ + QMap params; + params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + ResourceLocatorUrl ResourceLocatorUrl; + ResourceLocatorUrl.setParameters(params); + QVERIFY(!ResourceLocatorUrl.isValid()); + QVERIFY(ResourceLocatorUrl.url().isEmpty()); + QVERIFY(!ResourceLocatorUrl.parameters().isEmpty()); + QCOMPARE(ResourceLocatorUrl.parameters(), params); +} + +void ResourceLocatorUrlTest::shouldAssignExternal() +{ + ResourceLocatorUrl resourcelocatorurl; + QUrl url = QUrl(QStringLiteral("https://www.kde.org")); + resourcelocatorurl.setUrl(url); + QVERIFY(!resourcelocatorurl.url().isEmpty()); + QCOMPARE(resourcelocatorurl.url(), url); +} + +void ResourceLocatorUrlTest::shouldSerialized() +{ + ResourceLocatorUrl resourcelocatorurl; + ResourceLocatorUrl result; + QMap params; + params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + resourcelocatorurl.setParameters(params); + resourcelocatorurl.setUrl(QUrl(QStringLiteral("mailto:foo@kde.org"))); + + QByteArray data; + QDataStream s(&data, QIODevice::WriteOnly); + s << resourcelocatorurl; + + QDataStream t(&data, QIODevice::ReadOnly); + t >> result; + + QVERIFY(resourcelocatorurl == result); +} + +void ResourceLocatorUrlTest::shouldEqualResourceLocatorUrl() +{ + ResourceLocatorUrl resourcelocatorurl; + ResourceLocatorUrl result; + QMap params; + params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + resourcelocatorurl.setUrl(QUrl(QStringLiteral("mailto:foo@kde.org"))); + resourcelocatorurl.setParameters(params); + + result = resourcelocatorurl; + QVERIFY(resourcelocatorurl == result); +} + +void ResourceLocatorUrlTest::shouldParseResourceLocatorUrl() +{ + QByteArray vcarddata("BEGIN:VCARD\n" + "VERSION:3.0\n" + "N:LastName;FirstName;;;\n" + "UID:c80cf296-0825-4eb0-ab16-1fac1d522a33@xxxxxx.xx\n" + "URL;PREF=1:https://firsturl\n" + "URL;PREF=1:https://sherlockholmes.com/calendar/sherlockholmes\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); + QCOMPARE(lst.at(0).extraUrlList().count(), 2); + const ResourceLocatorUrl calurl = lst.at(0).extraUrlList().at(0); + QCOMPARE(calurl.url(), QUrl(QStringLiteral("https://firsturl"))); + QVERIFY(!calurl.parameters().isEmpty()); +} + +void ResourceLocatorUrlTest::shouldGenerateVCard4() +{ + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + KContacts::ResourceLocatorUrl webpage; + webpage.setUrl(QUrl(QStringLiteral("https://www.kde.org"))); + addr.setUrl(webpage); + ResourceLocatorUrl url; + url.setUrl(QUrl(QStringLiteral("https://sherlockholmes.com/calendar/sherlockholmes"))); + addr.insertExtraUrl(url); + url.setUrl(QUrl(QStringLiteral("https://foo.kde.org"))); + addr.insertExtraUrl(url); + lst << addr; + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v4_0); + QByteArray expected; + expected = QByteArray("BEGIN:VCARD\r\n" + "VERSION:4.0\r\n" + "EMAIL:foo@kde.org\r\n" + "N:;;;;\r\n" + "UID:testuid\r\n" + "URL:https://www.kde.org\r\n" + "URL:https://sherlockholmes.com/calendar/sherlockholmes\r\n" + "URL:https://foo.kde.org\r\n" + "END:VCARD\r\n\r\n"); + + QCOMPARE(ba, expected); +} + +void ResourceLocatorUrlTest::shouldGenerateVCardWithParameter() +{ + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + KContacts::ResourceLocatorUrl webpage; + webpage.setUrl(QUrl(QStringLiteral("https://www.kde.org"))); + addr.setUrl(webpage); + ResourceLocatorUrl url; + url.setUrl(QUrl(QStringLiteral("https://sherlockholmes.com/calendar/sherlockholmes"))); + QMap params; + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + url.setParameters(params); + addr.insertExtraUrl(url); + url.setUrl(QUrl(QStringLiteral("https://foo.kde.org"))); + QMap params2; + url.setParameters(params2); + addr.insertExtraUrl(url); + lst << addr; + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v4_0); + QByteArray expected; + expected = QByteArray("BEGIN:VCARD\r\n" + "VERSION:4.0\r\n" + "EMAIL:foo@kde.org\r\n" + "N:;;;;\r\n" + "UID:testuid\r\n" + "URL:https://www.kde.org\r\n" + "URL;FOO2=bla2,blo2:https://sherlockholmes.com/calendar/sherlockholmes\r\n" + "URL:https://foo.kde.org\r\n" + "END:VCARD\r\n\r\n"); + + QCOMPARE(ba, expected); +} + +void ResourceLocatorUrlTest::shouldGenerateVCard3() +{ + KContacts::AddresseeList lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + KContacts::ResourceLocatorUrl webpage; + webpage.setUrl(QUrl(QStringLiteral("https://www.kde.org"))); + addr.setUrl(webpage); + ResourceLocatorUrl url; + url.setUrl(QUrl(QStringLiteral("https://sherlockholmes.com/calendar/sherlockholmes"))); + QMap params; + params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); + url.setParameters(params); + addr.insertExtraUrl(url); + url.setUrl(QUrl(QStringLiteral("https://foo.kde.org"))); + QMap params2; + url.setParameters(params2); + addr.insertExtraUrl(url); + lst << addr; + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v3_0); + QByteArray expected; + expected = QByteArray("BEGIN:VCARD\r\n" + "VERSION:3.0\r\n" + "EMAIL:foo@kde.org\r\n" + "N:;;;;\r\n" + "UID:testuid\r\n" + "URL:https://www.kde.org\r\n" + "URL;FOO2=bla2,blo2:https://sherlockholmes.com/calendar/sherlockholmes\r\n" + "URL:https://foo.kde.org\r\n" + "END:VCARD\r\n\r\n"); + + QCOMPARE(ba, expected); + +} + +QTEST_MAIN(ResourceLocatorUrlTest) + diff --git a/autotests/resourcelocatorurltest.h b/autotests/resourcelocatorurltest.h new file mode 100644 index 0000000..62a50e8 --- /dev/null +++ b/autotests/resourcelocatorurltest.h @@ -0,0 +1,45 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2015 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 ResourceLocatorUrlTest_H +#define ResourceLocatorUrlTest_H + +#include + +class ResourceLocatorUrlTest : public QObject +{ + Q_OBJECT +public: + explicit ResourceLocatorUrlTest(QObject *parent = Q_NULLPTR); + ~ResourceLocatorUrlTest(); + +private Q_SLOTS: + void shouldHaveDefaultValue(); + void shouldAssignValue(); + void shouldAssignExternal(); + void shouldSerialized(); + void shouldEqualResourceLocatorUrl(); + void shouldParseResourceLocatorUrl(); + void shouldGenerateVCard4(); + void shouldGenerateVCardWithParameter(); + void shouldGenerateVCard3(); +}; + +#endif // ResourceLocatorUrlTest_H diff --git a/autotests/secrecytest.cpp b/autotests/secrecytest.cpp new file mode 100644 index 0000000..40eb81f --- /dev/null +++ b/autotests/secrecytest.cpp @@ -0,0 +1,86 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2007 Tobias Koenig + + 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 "secrecytest.h" +#include "kcontacts/secrecy.h" +#include "vcardtool.h" +#include + +QTEST_MAIN(SecrecyTest) + +void SecrecyTest::emptyTest() +{ + KContacts::Secrecy secrecy; + + QVERIFY(secrecy.type() == KContacts::Secrecy::Invalid); +} + +void SecrecyTest::storeTest() +{ + KContacts::Secrecy secrecy; + + secrecy.setType(KContacts::Secrecy::Private); + + QVERIFY(secrecy.type() == KContacts::Secrecy::Private); +} + +void SecrecyTest::equalsTest() +{ + KContacts::Secrecy secrecy1, secrecy2; + + secrecy1.setType(KContacts::Secrecy::Confidential); + secrecy2.setType(KContacts::Secrecy::Confidential); + + QVERIFY(secrecy1 == secrecy2); +} + +void SecrecyTest::differsTest() +{ + KContacts::Secrecy secrecy1(KContacts::Secrecy::Private); + KContacts::Secrecy secrecy2(KContacts::Secrecy::Confidential); + + QVERIFY(secrecy1 != secrecy2); +} + +void SecrecyTest::assignmentTest() +{ + KContacts::Secrecy secrecy1, secrecy2; + + secrecy1.setType(KContacts::Secrecy::Confidential); + secrecy1 = secrecy2; + + QVERIFY(secrecy1 == secrecy2); +} + +void SecrecyTest::serializeTest() +{ + KContacts::Secrecy secrecy1, secrecy2; + + secrecy1.setType(KContacts::Secrecy::Confidential); + + QByteArray data; + QDataStream s(&data, QIODevice::WriteOnly); + s << secrecy1; + + QDataStream t(&data, QIODevice::ReadOnly); + t >> secrecy2; + + QVERIFY(secrecy1 == secrecy2); +} diff --git a/autotests/secrecytest.h b/autotests/secrecytest.h new file mode 100644 index 0000000..3580f1c --- /dev/null +++ b/autotests/secrecytest.h @@ -0,0 +1,39 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2007 Tobias Koenig + + 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 SECRECY_TEST_H +#define SECRECY_TEST_H + +#include + +class SecrecyTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void emptyTest(); + void storeTest(); + void equalsTest(); + void differsTest(); + void assignmentTest(); + void serializeTest(); +}; + +#endif diff --git a/autotests/soundtest.cpp b/autotests/soundtest.cpp new file mode 100644 index 0000000..d2df950 --- /dev/null +++ b/autotests/soundtest.cpp @@ -0,0 +1,262 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2007 Tobias Koenig + + 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 "soundtest.h" +#include "kcontacts/sound.h" +#include "addressee.h" +#include +#include "vcardtool.h" + +QTEST_MAIN(SoundTest) + +static QByteArray testData() +{ + static QByteArray data; + + if (data.isNull()) { + for (int i = 0; i < 20; ++i) { + data.append(char(i)); + } + } + + return data; +} + +void SoundTest::emptyTest() +{ + KContacts::Sound sound; + + QVERIFY(sound.isEmpty()); +} + +void SoundTest::storeTestIntern() +{ + KContacts::Sound sound; + + sound.setData(testData()); + + QVERIFY(sound.isIntern() == true); + QVERIFY(sound.data() == testData()); +} + +void SoundTest::storeTestExtern() +{ + KContacts::Sound sound; + + sound.setUrl(QLatin1String("http://myhomepage.com/sound.wav")); + + QVERIFY(sound.isIntern() == false); + QVERIFY(sound.url() == QLatin1String("http://myhomepage.com/sound.wav")); +} + +void SoundTest::equalsTestIntern() +{ + KContacts::Sound sound1, sound2; + + sound1.setData(testData()); + sound2.setData(testData()); + + QVERIFY(sound1 == sound2); +} + +void SoundTest::equalsTestExtern() +{ + KContacts::Sound sound1, sound2; + + sound1.setUrl(QStringLiteral("http://myhomepage.com/sound.wav")); + sound2.setUrl(QStringLiteral("http://myhomepage.com/sound.wav")); + + QVERIFY(sound1 == sound2); +} + +void SoundTest::differsTest() +{ + KContacts::Sound sound1, sound2; + + sound1.setUrl(QStringLiteral("http://myhomepage.com/sound.wav")); + sound2.setData(testData()); + + QVERIFY(sound1 != sound2); +} + +void SoundTest::assignmentTestIntern() +{ + KContacts::Sound sound1, sound2; + + sound1.setData(testData()); + + sound2 = sound1; + + QVERIFY(sound1 == sound2); +} + +void SoundTest::assignmentTestExtern() +{ + KContacts::Sound sound1, sound2; + + sound1.setUrl(QStringLiteral("http://myhomepage.com/sound.wav")); + + sound2 = sound1; + + QVERIFY(sound1 == sound2); +} + +void SoundTest::serializeTest() +{ + KContacts::Sound sound1, sound2; + + sound1.setUrl(QStringLiteral("http://myhomepage.com/sound.wav")); + sound1.setData(testData()); + + QByteArray data; + QDataStream s(&data, QIODevice::WriteOnly); + s << sound1; + + QDataStream t(&data, QIODevice::ReadOnly); + t >> sound2; + + QVERIFY(sound1 == sound2); +} + +void SoundTest::shouldParseSource() +{ + 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" + "SOUND;VALUE=URI:http://myhomepage.com/sound.wav\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).sound().isEmpty()); + KContacts::Sound sound = lst.at(0).sound(); + QVERIFY(!sound.isIntern()); + QCOMPARE(sound.url(), QStringLiteral("http://myhomepage.com/sound.wav")); +} + +void SoundTest::shouldGenerateVCard4WithData() +{ + KContacts::Addressee::List lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + KContacts::Sound sound1; + + sound1.setUrl(QStringLiteral("http://myhomepage.com/sound.wav")); + sound1.setData(testData()); + addr.setSound(sound1); + + lst << addr; + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v4_0); + QByteArray expected; + expected = QByteArray("BEGIN:VCARD\r\n" + "VERSION:4.0\r\n" + "EMAIL:foo@kde.org\r\n" + "N:;;;;\r\n" + "SOUND;ENCODING=b:AAECAwQFBgcICQoLDA0ODxAREhM=\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + + QCOMPARE(ba, expected); +} + +void SoundTest::shouldGenerateVCard4WithUrl() +{ + KContacts::Addressee::List lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + KContacts::Sound sound1; + + sound1.setUrl(QStringLiteral("http://myhomepage.com/sound.wav")); + addr.setSound(sound1); + + lst << addr; + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v4_0); + QByteArray expected; + expected = QByteArray("BEGIN:VCARD\r\n" + "VERSION:4.0\r\n" + "EMAIL:foo@kde.org\r\n" + "N:;;;;\r\n" + "SOUND;VALUE=URI:http://myhomepage.com/sound.wav\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + + QCOMPARE(ba, expected); +} + +void SoundTest::shouldGenerateVCard3WithData() +{ + KContacts::Addressee::List lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + KContacts::Sound sound1; + + sound1.setUrl(QStringLiteral("http://myhomepage.com/sound.wav")); + sound1.setData(testData()); + addr.setSound(sound1); + + lst << addr; + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v3_0); + QByteArray expected; + expected = QByteArray("BEGIN:VCARD\r\n" + "VERSION:3.0\r\n" + "EMAIL:foo@kde.org\r\n" + "N:;;;;\r\n" + "SOUND;ENCODING=b:AAECAwQFBgcICQoLDA0ODxAREhM=\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + + QCOMPARE(ba, expected); +} + +void SoundTest::shouldGenerateVCard3WithUrl() +{ + KContacts::Addressee::List lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + KContacts::Sound sound1; + + sound1.setUrl(QStringLiteral("http://myhomepage.com/sound.wav")); + addr.setSound(sound1); + + lst << addr; + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v3_0); + QByteArray expected; + expected = QByteArray("BEGIN:VCARD\r\n" + "VERSION:3.0\r\n" + "EMAIL:foo@kde.org\r\n" + "N:;;;;\r\n" + "SOUND;VALUE=URI:http://myhomepage.com/sound.wav\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + + QCOMPARE(ba, expected); +} diff --git a/autotests/soundtest.h b/autotests/soundtest.h new file mode 100644 index 0000000..46adb93 --- /dev/null +++ b/autotests/soundtest.h @@ -0,0 +1,47 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2007 Tobias Koenig + + 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 SOUND_TEST_H +#define SOUND_TEST_H + +#include + +class SoundTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void emptyTest(); + void storeTestIntern(); + void storeTestExtern(); + void equalsTestIntern(); + void equalsTestExtern(); + void differsTest(); + void assignmentTestIntern(); + void assignmentTestExtern(); + void serializeTest(); + void shouldParseSource(); + void shouldGenerateVCard4WithData(); + void shouldGenerateVCard4WithUrl(); + void shouldGenerateVCard3WithData(); + void shouldGenerateVCard3WithUrl(); +}; + +#endif diff --git a/autotests/testlock.h b/autotests/testlock.h new file mode 100644 index 0000000..ead7c64 --- /dev/null +++ b/autotests/testlock.h @@ -0,0 +1,52 @@ +/* + This file is part of the KContacts framework. + + Copyright (c) 2003 Cornelius Schumacher + + 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 KCONTACTS_TESTLOCK_H +#define KCONTACTS_TESTLOCK_H + +#include +#include + +#include "kcontacts/lock.h" + +class QLabel; +class QTreeWidget; + +class LockWidget : public QWidget +{ + Q_OBJECT +public: + LockWidget(const QString &identifier); + ~LockWidget(); + +protected Q_SLOTS: + void lock(); + void unlock(); + + void updateLockView(); + +private: + KContacts::Lock *mLock; + + QLabel *mStatus; + QTreeWidget *mLockView; +}; + +#endif diff --git a/autotests/testroundtrip.cpp b/autotests/testroundtrip.cpp new file mode 100644 index 0000000..55ec1a9 --- /dev/null +++ b/autotests/testroundtrip.cpp @@ -0,0 +1,206 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2012 Kevin Krammer + + 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 "addressee.h" +#include "converter/vcardconverter.h" + +#include +#include +#include + +using namespace KContacts; + +class RoundtripTest : public QObject +{ + Q_OBJECT + +private: + + QDir mInputDir; + QDir mOutput2_1Dir; + QDir mOutput3_0Dir; + QDir mOutput4_0Dir; + + QStringList mInputFiles; + +private Q_SLOTS: + void initTestCase(); + void testVCardRoundtrip_data(); + void testVCardRoundtrip(); +}; + +// check the validity of our test data set +void RoundtripTest::initTestCase() +{ + + // check that all resource prefixes exist + + mInputDir = QDir(QStringLiteral(":/input")); + QVERIFY(mInputDir.exists()); + QVERIFY(mInputDir.cd(QStringLiteral("data"))); + + mOutput2_1Dir = QDir(QStringLiteral(":/output2.1")); + QVERIFY(mOutput2_1Dir.exists()); + QVERIFY(mOutput2_1Dir.cd(QStringLiteral("data"))); + + mOutput3_0Dir = QDir(QStringLiteral(":/output3.0")); + QVERIFY(mOutput3_0Dir.exists()); + QVERIFY(mOutput3_0Dir.cd(QStringLiteral("data"))); + + mOutput4_0Dir = QDir(QStringLiteral(":/output4.0")); + QVERIFY(mOutput4_0Dir.exists()); + QVERIFY(mOutput4_0Dir.cd(QStringLiteral("data"))); + + // check that there are input files + + mInputFiles = mInputDir.entryList(); + + QVERIFY(!mInputFiles.isEmpty()); +} + +void RoundtripTest::testVCardRoundtrip_data() +{ + QTest::addColumn("inputFile"); + QTest::addColumn("output2_1File"); + QTest::addColumn("output3_0File"); + QTest::addColumn("output4_0File"); + + QString outFile21Pattern = QLatin1String("%1.2_1ref"); + QString outFile4Pattern = QLatin1String("v4_0.%1.ref"); + QString outFilePattern = QLatin1String("%1.ref"); + Q_FOREACH (const QString &inputFile, mInputFiles) { + const QString outFile = outFilePattern.arg(inputFile); + const QString outFileV2_1 = outFile21Pattern.arg(inputFile); + const QString outFileV4 = outFile4Pattern.arg(inputFile); + QTest::newRow(QFile::encodeName(inputFile).constData()) + << inputFile + << (mOutput2_1Dir.exists(outFileV2_1) ? outFileV2_1 : QString()) + << (mOutput3_0Dir.exists(outFile) ? outFile : QString()) + << (mOutput4_0Dir.exists(outFileV4) ? outFileV4 : QString()); + } +} + +void RoundtripTest::testVCardRoundtrip() +{ + QFETCH(QString, inputFile); + QFETCH(QString, output2_1File); + QFETCH(QString, output3_0File); + QFETCH(QString, output4_0File); + + QVERIFY2(!output2_1File.isEmpty() + || !output3_0File.isEmpty() + || !output4_0File.isEmpty(), + "No reference output file for either format version"); + + QFile input(QFileInfo(mInputDir, inputFile).absoluteFilePath()); + QVERIFY(input.open(QIODevice::ReadOnly)); + + const QByteArray inputData = input.readAll(); + QVERIFY(!inputData.isEmpty()); + + VCardConverter converter; + const Addressee::List list = converter.parseVCards(inputData); + QVERIFY(!list.isEmpty()); + + if (!output2_1File.isEmpty()) { + const QByteArray outputData = converter.createVCards(list, VCardConverter::v2_1); + + QFile outputFile(QFileInfo(mOutput2_1Dir, output2_1File).absoluteFilePath()); + QVERIFY(outputFile.open(QIODevice::ReadOnly)); + + const QByteArray outputRefData = outputFile.readAll(); + QCOMPARE(outputData.size(), outputRefData.size()); + + const QList outputLines = outputData.split('\n'); + const QList outputRefLines = outputRefData.split('\n'); + QCOMPARE(outputLines.count(), outputRefLines.count()); + for (int i = 0; i < outputLines.count(); ++i) { + const QByteArray actual = outputLines[i]; + const QByteArray expect = outputRefLines[i]; + + if (actual != expect) { + qCritical() << "Mismatch in v2.1 output line" << (i + 1); + QCOMPARE(actual.count(), expect.count()); + + qCritical() << "\nActual:" << actual << "\nExpect:" << expect; + QCOMPARE(actual, expect); + } + } + } + + if (!output3_0File.isEmpty()) { + const QByteArray outputData = converter.createVCards(list, VCardConverter::v3_0); + + QFile outputFile(QFileInfo(mOutput3_0Dir, output3_0File).absoluteFilePath()); + QVERIFY(outputFile.open(QIODevice::ReadOnly)); + + const QByteArray outputRefData = outputFile.readAll(); + QCOMPARE(outputData.size(), outputRefData.size()); + + const QList outputLines = outputData.split('\n'); + const QList outputRefLines = outputRefData.split('\n'); + QCOMPARE(outputLines.count(), outputRefLines.count()); + + for (int i = 0; i < outputLines.count(); ++i) { + const QByteArray actual = outputLines[i]; + const QByteArray expect = outputRefLines[i]; + + if (actual != expect) { + qCritical() << "Mismatch in v3.0 output line" << (i + 1); + + qCritical() << "\nActual:" << actual << "\nExpect:" << expect; + QCOMPARE(actual.count(), expect.count()); + QCOMPARE(actual, expect); + } + } + } +#if 0 + if (!output4_0File.isEmpty()) { + const QByteArray outputData = converter.createVCards(list, VCardConverter::v4_0); + + QFile outputFile(QFileInfo(mOutput4_0Dir, output4_0File).absoluteFilePath()); + QVERIFY(outputFile.open(QIODevice::ReadOnly)); + + const QByteArray outputRefData = outputFile.readAll(); + //QCOMPARE( outputData.size(), outputRefData.size() ); + + const QList outputLines = outputData.split('\n'); + const QList outputRefLines = outputRefData.split('\n'); + //QCOMPARE(outputLines.count(), outputRefLines.count()); + + for (int i = 0; i < outputLines.count(); ++i) { + const QByteArray actual = outputLines[i]; + const QByteArray expect = outputRefLines[i]; + + if (actual != expect) { + qCritical() << "Mismatch in v4.0 output line" << (i + 1); + + qCritical() << "\nActual:" << actual << "\nExpect:" << expect; + QCOMPARE(actual.count(), expect.count()); + QCOMPARE(actual, expect); + } + } + } +#endif +} + +QTEST_MAIN(RoundtripTest) + +#include "testroundtrip.moc" diff --git a/autotests/testroundtrip.qrc b/autotests/testroundtrip.qrc new file mode 100644 index 0000000..fdb4844 --- /dev/null +++ b/autotests/testroundtrip.qrc @@ -0,0 +1,61 @@ + + + + data/vcard1.vcf + data/vcard2.vcf + data/vcard3.vcf + data/vcard4.vcf + data/vcard5.vcf + data/vcard6.vcf + data/vcard7.vcf + data/vcard8.vcf + data/vcard9.vcf + data/vcard10.vcf + data/vcard11.vcf + data/vcard12.vcf + data/vcard13.vcf + data/vcard14.vcf + + + + + data/vcard1.vcf.2_1ref + data/vcard2.vcf.2_1ref + data/vcard3.vcf.2_1ref + data/vcard6.vcf.2_1ref + data/vcard7.vcf.2_1ref + data/vcard12.vcf.2_1ref + data/vcard14.vcf.2_1ref + + + + + data/vcard1.vcf.ref + data/vcard2.vcf.ref + data/vcard3.vcf.ref + data/vcard4.vcf.ref + data/vcard5.vcf.ref + data/vcard6.vcf.ref + data/vcard7.vcf.ref + data/vcard8.vcf.ref + data/vcard9.vcf.ref + data/vcard10.vcf.ref + data/vcard11.vcf.ref + data/vcard12.vcf.ref + data/vcard13.vcf.ref + data/vcard14.vcf.ref + + + + + data/v4_0.vcard1.vcf.ref + data/v4_0.vcard2.vcf.ref + data/v4_0.vcard3.vcf.ref + data/v4_0.vcard4.vcf.ref + data/v4_0.vcard5.vcf.ref + data/v4_0.vcard6.vcf.ref + data/v4_0.vcard7.vcf.ref + data/v4_0.vcard8.vcf.ref + + + diff --git a/autotests/timezonetest.cpp b/autotests/timezonetest.cpp new file mode 100644 index 0000000..6f91aa7 --- /dev/null +++ b/autotests/timezonetest.cpp @@ -0,0 +1,112 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2007 Tobias Koenig + + 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 "timezonetest.h" +#include "kcontacts/timezone.h" +#include +#include "vcardtool.h" + +QTEST_MAIN(TimeZoneTest) + +void TimeZoneTest::emptyTest() +{ + KContacts::TimeZone timezone; + + QVERIFY(timezone.isValid() == false); +} + +void TimeZoneTest::storeTest() +{ + KContacts::TimeZone timezone; + + timezone.setOffset(2); + + QVERIFY(timezone.offset() == 2); +} + +void TimeZoneTest::equalsTest() +{ + KContacts::TimeZone timezone1, timezone2; + + timezone1.setOffset(2); + timezone2.setOffset(2); + + QVERIFY(timezone1 == timezone2); +} + +void TimeZoneTest::differsTest() +{ + KContacts::TimeZone timezone1(2); + KContacts::TimeZone timezone2(3); + + QVERIFY(timezone1 != timezone2); + QVERIFY(timezone1 != KContacts::TimeZone()); +} + +void TimeZoneTest::assignmentTest() +{ + KContacts::TimeZone timezone1, timezone2; + + timezone1.setOffset(2); + timezone1 = timezone2; + + QVERIFY(timezone1 == timezone2); +} + +void TimeZoneTest::serializeTest() +{ + KContacts::TimeZone timezone1, timezone2; + + timezone1.setOffset(2); + + QByteArray data; + QDataStream s(&data, QIODevice::WriteOnly); + s << timezone1; + + QDataStream t(&data, QIODevice::ReadOnly); + t >> timezone2; + + QVERIFY(timezone1 == timezone2); +} + +void TimeZoneTest::shouldGenerateVCard3() +{ + KContacts::Addressee::List lst; + KContacts::Addressee addr; + addr.setEmails(QStringList() << QStringLiteral("foo@kde.org")); + addr.setUid(QStringLiteral("testuid")); + KContacts::TimeZone timezone; + + timezone.setOffset(2); + addr.setTimeZone(timezone); + + lst << addr; + KContacts::VCardTool vcard; + const QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v3_0); + QByteArray expected; + expected = QByteArray("BEGIN:VCARD\r\n" + "VERSION:3.0\r\n" + "EMAIL:foo@kde.org\r\n" + "N:;;;;\r\n" + "TZ:+00:02\r\n" + "UID:testuid\r\n" + "END:VCARD\r\n\r\n"); + QCOMPARE(ba, expected); +} diff --git a/autotests/timezonetest.h b/autotests/timezonetest.h new file mode 100644 index 0000000..1ebb237 --- /dev/null +++ b/autotests/timezonetest.h @@ -0,0 +1,40 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2007 Tobias Koenig + + 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 TIMEZONE_TEST_H +#define TIMEZONE_TEST_H + +#include + +class TimeZoneTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void emptyTest(); + void storeTest(); + void equalsTest(); + void differsTest(); + void assignmentTest(); + void serializeTest(); + void shouldGenerateVCard3(); +}; + +#endif diff --git a/autotests/vcarddragtest.cpp b/autotests/vcarddragtest.cpp new file mode 100644 index 0000000..141ac90 --- /dev/null +++ b/autotests/vcarddragtest.cpp @@ -0,0 +1,182 @@ +/* + This file is part of the KContacts framework. + Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net + Author: Kevin Krammer, krake@kdab.com + + 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 + +#include "converter/kcontacts/vcardconverter.h" +#include "kcontacts/vcarddrag.h" + +#include +using namespace KContacts; + +class VCardDragTest : public QObject +{ + Q_OBJECT + +public: + VCardDragTest(); + +private: + Addressee mAddressee1; + Addressee mAddressee2; + +private Q_SLOTS: + void testPopulate(); + void testCanDecode(); + void testFromMimeData(); +}; + +QTEST_MAIN(VCardDragTest) + +VCardDragTest::VCardDragTest() + : QObject() +{ + mAddressee1.setGivenName(QStringLiteral("Kevin")); + mAddressee1.setFamilyName(QStringLiteral("Krammer")); + mAddressee1.insertEmail(QStringLiteral("kevin.krammer@gmx.at")); + + mAddressee2.setGivenName(QStringLiteral("Tobias")); + mAddressee2.setFamilyName(QStringLiteral("König")); + mAddressee2.insertEmail(QStringLiteral("tokoe@kde.org")); +} + +void VCardDragTest::testPopulate() +{ + VCardConverter converter; + const QByteArray vcard = converter.createVCard(mAddressee1); + QVERIFY(!vcard.isEmpty()); + + QMimeData *data = new QMimeData(); + bool result = VCardDrag::populateMimeData(data, vcard); + QVERIFY(result); + QVERIFY(data->hasFormat(KContacts::Addressee::mimeType())); + QCOMPARE(data->data(KContacts::Addressee::mimeType()), vcard); + delete data; + + data = new QMimeData(); + result = VCardDrag::populateMimeData(data, Addressee::List() << mAddressee1); + QVERIFY(result); + QVERIFY(data->hasFormat(KContacts::Addressee::mimeType())); + QCOMPARE(data->data(KContacts::Addressee::mimeType()), vcard); + delete data; + + const QByteArray vcards = converter.createVCards(Addressee::List() << mAddressee1 << mAddressee2); + data = new QMimeData(); + result = VCardDrag::populateMimeData(data, Addressee::List() << mAddressee1 << mAddressee2); + QVERIFY(result); + QVERIFY(data->hasFormat(KContacts::Addressee::mimeType())); + QCOMPARE(data->data(KContacts::Addressee::mimeType()), vcards); + delete data; + + data = new QMimeData(); + result = VCardDrag::populateMimeData(data, Addressee::List()); + QVERIFY(!result); + QVERIFY(!data->hasFormat(KContacts::Addressee::mimeType())); + delete data; +} + +void VCardDragTest::testCanDecode() +{ + VCardConverter converter; + const QByteArray vcard = converter.createVCard(mAddressee1); + QVERIFY(!vcard.isEmpty()); + + QMimeData *data = new QMimeData(); + data->setData(Addressee::mimeType(), vcard); + QVERIFY(VCardDrag::canDecode(data)); + delete data; + + data = new QMimeData(); + data->setData(QStringLiteral("text/x-vcard"), vcard); + QVERIFY(VCardDrag::canDecode(data)); + delete data; + + data = new QMimeData(); + data->setData(QStringLiteral("application/octetstream"), vcard); + QVERIFY(!VCardDrag::canDecode(data)); + delete data; +} + +void VCardDragTest::testFromMimeData() +{ + VCardConverter converter; + const QByteArray vcard = converter.createVCard(mAddressee1); + QVERIFY(!vcard.isEmpty()); + + QByteArray content; + + QMimeData *data = new QMimeData(); + data->setData(Addressee::mimeType(), vcard); + bool result = VCardDrag::fromMimeData(data, content); + QVERIFY(result); + QCOMPARE(content, vcard); + delete data; + + data = new QMimeData(); + data->setData(QStringLiteral("text/x-vcard"), vcard); + result = VCardDrag::fromMimeData(data, content); + QVERIFY(result); + QCOMPARE(content, vcard); + delete data; + + data = new QMimeData(); + data->setData(QStringLiteral("application/octetstream"), vcard); + result = VCardDrag::fromMimeData(data, content); + QVERIFY(!result); + delete data; + + const QByteArray vcards = converter.createVCards(Addressee::List() << mAddressee1 << mAddressee2); + QVERIFY(!vcards.isEmpty()); + + Addressee::List addresseeList; + + data = new QMimeData(); + data->setData(Addressee::mimeType(), vcards); + result = VCardDrag::fromMimeData(data, addresseeList); + QVERIFY(result); + QCOMPARE(addresseeList.count(), 2); + QCOMPARE(addresseeList[0], mAddressee1); + QCOMPARE(addresseeList[1], mAddressee2); + delete data; + + data = new QMimeData(); + data->setData(QStringLiteral("text/x-vcard"), vcards); + result = VCardDrag::fromMimeData(data, addresseeList); + QVERIFY(result); + QCOMPARE(addresseeList.count(), 2); + QCOMPARE(addresseeList[0], mAddressee1); + QCOMPARE(addresseeList[1], mAddressee2); + delete data; + + data = new QMimeData(); + data->setData(QStringLiteral("application/octetstream"), vcards); + result = VCardDrag::fromMimeData(data, addresseeList); + QVERIFY(!result); + delete data; + + data = new QMimeData(); + data->setData(Addressee::mimeType(), QByteArray()); + result = VCardDrag::fromMimeData(data, addresseeList); + QVERIFY(!result); + delete data; +} + +#include "vcarddragtest.moc" diff --git a/metainfo.yaml b/metainfo.yaml new file mode 100644 index 0000000..261fdb5 --- /dev/null +++ b/metainfo.yaml @@ -0,0 +1,14 @@ +maintainer: +description: Address book API for KDE +tier: 3 +type: functional +platforms: + - name: All +portingAid: false +deprecated: false +release: false +libraries: + - qmake: KContacts + cmake: "KF5::Contacts" +cmakename: KF5Contacts + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..7b0b766 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,120 @@ +set(vcardparser_SRCS + vcardparser/vcard.cpp + vcardparser/vcardline.cpp + vcardparser/vcardparser.cpp +) + +set(kcontacts_SRCS + address.cpp + addressee.cpp + addresseehelper.cpp + addresseelist.cpp + calendarurl.cpp + contactgroup.cpp + contactgrouptool.cpp + email.cpp + field.cpp + geo.cpp + gender.cpp + impp.cpp + key.cpp + lang.cpp + ldapdn.cpp + ldif.cpp + phonenumber.cpp + picture.cpp + related.cpp + resourcelocatorurl.cpp + secrecy.cpp + sortmode.cpp + sound.cpp + timezone.cpp + vcarddrag.cpp + vcardtool.cpp + ${vcardparser_SRCS} +) + +set(kcontacts_converter_SRCS + converter/vcardconverter.cpp + converter/ldifconverter.cpp +) + +ecm_qt_declare_logging_category(kcontacts_converter_SRCS HEADER kcontacts_debug.h IDENTIFIER KCONTACTS_LOG CATEGORY_NAME log_kcontacts) + +add_library(KF5Contacts ${kcontacts_SRCS} ${kcontacts_converter_SRCS}) + +generate_export_header(KF5Contacts BASE_NAME kcontacts) + +add_library(KF5::Contacts ALIAS KF5Contacts) + +target_include_directories(KF5Contacts INTERFACE "$") +target_include_directories(KF5Contacts PUBLIC "$") +target_include_directories(KF5Contacts PUBLIC "$") + +target_link_libraries(KF5Contacts +PUBLIC + KF5::CoreAddons + Qt5::Gui +PRIVATE + Qt5::DBus + KF5::ConfigCore + KF5::I18n + KF5::Codecs # for the vcard parser +) + +set_target_properties(KF5Contacts PROPERTIES + VERSION ${KContacts_VERSION_STRING} + SOVERSION ${KContacts_SOVERSION} + EXPORT_NAME Contacts +) + +install(TARGETS KF5Contacts EXPORT KF5ContactsTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) + +ecm_generate_headers(KContacts_CamelCase_HEADERS + HEADER_NAMES + Address + Addressee + AddresseeList + CalendarUrl + ContactGroup + ContactGroupTool + Email + Field + Geo + Gender + Key + Lang + Impp + PhoneNumber + Picture + Related + ResourceLocatorUrl + Secrecy + SortMode + Sound + TimeZone + VCardDrag + PREFIX KContacts + REQUIRED_HEADERS KContacts_HEADERS +) + +add_subdirectory(converter) + +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/kcontacts_export.h + ${KContacts_HEADERS} + DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KContacts/kcontacts + COMPONENT Devel +) + +install(FILES + ${KContacts_CamelCase_HEADERS} + DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KContacts/KContacts + COMPONENT Devel +) + + +install(FILES countrytransl.map DESTINATION ${KDE_INSTALL_DATADIR_KF5}/kcontacts) + +ecm_generate_pri_file(BASE_NAME KContacts LIB_NAME KF5Contacts DEPS "CoreAddons" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/KContacts) +install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/Messages.sh b/src/Messages.sh new file mode 100644 index 0000000..98e3c3c --- /dev/null +++ b/src/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT *.cpp -o $podir/kcontacts5.pot diff --git a/src/address.cpp b/src/address.cpp new file mode 100644 index 0000000..3fbe0b5 --- /dev/null +++ b/src/address.cpp @@ -0,0 +1,717 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2001 Cornelius Schumacher + + 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 "address.h" + +#include "kcontacts_debug.h" +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace KContacts; + +// template tags for address formatting localization +#define KCONTACTS_FMTTAG_realname QStringLiteral("%n") +#define KCONTACTS_FMTTAG_REALNAME QStringLiteral("%N") +#define KCONTACTS_FMTTAG_company QStringLiteral("%cm") +#define KCONTACTS_FMTTAG_COMPANY QStringLiteral("%CM") +#define KCONTACTS_FMTTAG_pobox QStringLiteral("%p") +#define KCONTACTS_FMTTAG_street QStringLiteral("%s") +#define KCONTACTS_FMTTAG_STREET QStringLiteral("%S") +#define KCONTACTS_FMTTAG_zipcode QStringLiteral("%z") +#define KCONTACTS_FMTTAG_location QStringLiteral("%l") +#define KCONTACTS_FMTTAG_LOCATION QStringLiteral("%L") +#define KCONTACTS_FMTTAG_region QStringLiteral("%r") +#define KCONTACTS_FMTTAG_REGION QStringLiteral("%R") +#define KCONTACTS_FMTTAG_newline QStringLiteral("\\n") +#define KCONTACTS_FMTTAG_condcomma QStringLiteral("%,") +#define KCONTACTS_FMTTAG_condwhite QStringLiteral("%w") +#define KCONTACTS_FMTTAG_purgeempty QStringLiteral("%0") + +/** + Finds the balanced closing bracket starting from the opening bracket at + pos in tsection. + @return position of closing bracket, -1 for unbalanced brackets +*/ +static int findBalancedBracket(const QString &tsection, int pos) +{ + int balancecounter = 0; + for (int i = pos + 1; i < tsection.length(); ++i) { + if (QLatin1Char(')') == tsection[i] && 0 == balancecounter) { + // found end of brackets + return i; + } else { + if (QLatin1Char('(') == tsection[i]) { + // nested brackets + balancecounter++; + } + } + } + return -1; +} + +/** + Parses a snippet of an address template + @param tsection the template string to be parsed + @param result QString reference in which the result will be stored + @return true if at least one tag evaluated positively, else false +*/ +static bool parseAddressTemplateSection(const QString &tsection, QString &result, + const QString &realName, const QString &orgaName, + const KContacts::Address &address) +{ + // This method first parses and substitutes any bracketed sections and + // after that replaces any tags with their values. If a bracketed section + // or a tag evaluate to zero, they are not just removed but replaced + // with a placeholder. This is because in the last step conditionals are + // resolved which depend on information about zero-evaluations. + result = tsection; + int stpos = 0; + bool ret = false; + + // first check for brackets that have to be evaluated first + int fpos = result.indexOf(KCONTACTS_FMTTAG_purgeempty, stpos); + while (-1 != fpos) { + int bpos1 = fpos + KCONTACTS_FMTTAG_purgeempty.length(); + int bpos2; + // expect opening bracket and find next balanced closing bracket. If + // next char is no opening bracket, continue parsing (no valid tag) + if (QLatin1Char('(') == result[bpos1]) { + bpos2 = findBalancedBracket(result, bpos1); + if (-1 != bpos2) { + // we have balanced brackets, recursively parse: + QString rplstr; + bool purge = !parseAddressTemplateSection(result.mid(bpos1 + 1, + bpos2 - bpos1 - 1), rplstr, + realName, orgaName, address); + if (purge) { + // purge -> remove all + // replace with !_P_!, so conditional tags work later + result.replace(fpos, bpos2 - fpos + 1, QStringLiteral("!_P_!")); + // leave stpos as it is + } else { + // no purge -> replace with recursively parsed string + result.replace(fpos, bpos2 - fpos + 1, rplstr); + ret = true; + stpos = fpos + rplstr.length(); + } + } else { + // unbalanced brackets: keep on parsing (should not happen + // and will result in bad formatting) + stpos = bpos1; + } + } + fpos = result.indexOf(KCONTACTS_FMTTAG_purgeempty, stpos); + } + + // after sorting out all purge tags, we just search'n'replace the rest, + // keeping track of whether at least one tag evaluates to something. + // The following macro needs QString for R_FIELD + // It substitutes !_P_! for empty fields so conditional tags work later +#define REPLTAG(R_TAG,R_FIELD) \ + if ( result.indexOf( R_TAG ) != -1 ) { \ + QString rpl = R_FIELD.isEmpty() ? QStringLiteral( "!_P_!" ) : R_FIELD; \ + result.replace( R_TAG, rpl ); \ + if ( !R_FIELD.isEmpty() ) { \ + ret = true; \ + } \ + } + REPLTAG(KCONTACTS_FMTTAG_realname, realName); + REPLTAG(KCONTACTS_FMTTAG_REALNAME, realName.toUpper()); + REPLTAG(KCONTACTS_FMTTAG_company, orgaName); + REPLTAG(KCONTACTS_FMTTAG_COMPANY, orgaName.toUpper()); + REPLTAG(KCONTACTS_FMTTAG_pobox, address.postOfficeBox()); + REPLTAG(KCONTACTS_FMTTAG_street, address.street()); + REPLTAG(KCONTACTS_FMTTAG_STREET, address.street().toUpper()); + REPLTAG(KCONTACTS_FMTTAG_zipcode, address.postalCode()); + REPLTAG(KCONTACTS_FMTTAG_location, address.locality()); + REPLTAG(KCONTACTS_FMTTAG_LOCATION, address.locality().toUpper()); + REPLTAG(KCONTACTS_FMTTAG_region, address.region()); + REPLTAG(KCONTACTS_FMTTAG_REGION, address.region().toUpper()); + result.replace(KCONTACTS_FMTTAG_newline, QLatin1String("\n")); +#undef REPLTAG + + // conditional comma + fpos = result.indexOf(KCONTACTS_FMTTAG_condcomma, 0); + while (-1 != fpos) { + const QString str1 = result.mid(fpos - 5, 5); + const QString str2 = result.mid(fpos + 2, 5); + if (str1 != QLatin1String("!_P_!") && str2 != QLatin1String("!_P_!")) { + result.replace(fpos, 2, QStringLiteral(", ")); + } else { + result.remove(fpos, 2); + } + fpos = result.indexOf(KCONTACTS_FMTTAG_condcomma, fpos); + } + // conditional whitespace + fpos = result.indexOf(KCONTACTS_FMTTAG_condwhite, 0); + while (-1 != fpos) { + const QString str1 = result.mid(fpos - 5, 5); + const QString str2 = result.mid(fpos + 2, 5); + if (str1 != QLatin1String("!_P_!") && str2 != QLatin1String("!_P_!")) { + result.replace(fpos, 2, QStringLiteral(" ")); + } else { + result.remove(fpos, 2); + } + fpos = result.indexOf(KCONTACTS_FMTTAG_condwhite, fpos); + } + + // remove purged: + result.remove(QStringLiteral("!_P_!")); + + return ret; +} + +class Q_DECL_HIDDEN Address::Private : public QSharedData +{ +public: + Private() + : mEmpty(true) + , mType(Q_NULLPTR) + { + mId = KRandom::randomString(10); + } + + Private(const Private &other) + : QSharedData(other) + { + mEmpty = other.mEmpty; + mId = other.mId; + mType = other.mType; + + mPostOfficeBox = other.mPostOfficeBox; + mExtended = other.mExtended; + mStreet = other.mStreet; + mLocality = other.mLocality; + mRegion = other.mRegion; + mPostalCode = other.mPostalCode; + mCountry = other.mCountry; + mLabel = other.mLabel; + } + + bool mEmpty; + QString mId; + Type mType; + + QString mPostOfficeBox; + QString mExtended; + QString mStreet; + QString mLocality; + QString mRegion; + QString mPostalCode; + QString mCountry; + QString mLabel; +}; + +Address::Address() + : d(new Private) +{ +} + +Address::Address(Type type) + : d(new Private) +{ + d->mType = type; +} + +Address::Address(const Address &other) + : d(other.d) +{ +} + +Address::~Address() +{ +} + +Address &Address::operator=(const Address &other) +{ + if (this != &other) { + d = other.d; + } + + return *this; +} + +bool Address::operator==(const Address &other) const +{ + if (d->mId != other.d->mId) { + return false; + } + if (d->mType != other.d->mType) { + return false; + } + if (d->mPostOfficeBox != other.d->mPostOfficeBox) { + return false; + } + if (d->mExtended != other.d->mExtended) { + return false; + } + if (d->mStreet != other.d->mStreet) { + return false; + } + if (d->mLocality != other.d->mLocality) { + return false; + } + if (d->mRegion != other.d->mRegion) { + return false; + } + if (d->mPostalCode != other.d->mPostalCode) { + return false; + } + if (d->mCountry != other.d->mCountry) { + return false; + } + if (d->mLabel != other.d->mLabel) { + return false; + } + + return true; +} + +bool Address::operator!=(const Address &a) const +{ + return !(a == *this); +} + +bool Address::isEmpty() const +{ + return d->mEmpty; +} + +void Address::clear() +{ + *this = Address(); +} + +void Address::setId(const QString &id) +{ + d->mEmpty = false; + d->mId = id; +} + +QString Address::id() const +{ + return d->mId; +} + +void Address::setType(Type type) +{ + d->mEmpty = false; + d->mType = type; +} + +Address::Type Address::type() const +{ + return d->mType; +} + +QString Address::typeLabel(Type type) +{ + QString label; + bool first = true; + const TypeList list = typeList(); + + TypeList::ConstIterator it; + TypeList::ConstIterator end(list.end()); + for (it = list.begin(); it != end; ++it) { + // these are actually flags + const TypeFlag flag = static_cast(static_cast(*it)); + if (type & flag) { + if (!first) { + label.append(QLatin1Char('/')); + } + + label.append(typeFlagLabel(flag)); + + if (first) { + first = false; + } + } + } + return label; +} + +QString Address::typeLabel() const +{ + QString label; + bool first = true; + + const TypeList list = typeList(); + + TypeList::ConstIterator it; + for (it = list.begin(); it != list.end(); ++it) { + if ((type() & (*it)) && ((*it) != Pref)) { + if (!first) { + label.append(QLatin1Char('/')); + } + label.append(typeLabel(*it)); + if (first) { + first = false; + } + } + } + + return label; +} + +void Address::setPostOfficeBox(const QString &postOfficeBox) +{ + d->mEmpty = false; + d->mPostOfficeBox = postOfficeBox; +} + +QString Address::postOfficeBox() const +{ + return d->mPostOfficeBox; +} + +QString Address::postOfficeBoxLabel() +{ + return i18n("Post Office Box"); +} + +void Address::setExtended(const QString &extended) +{ + d->mEmpty = false; + d->mExtended = extended; +} + +QString Address::extended() const +{ + return d->mExtended; +} + +QString Address::extendedLabel() +{ + return i18n("Extended Address Information"); +} + +void Address::setStreet(const QString &street) +{ + d->mEmpty = false; + d->mStreet = street; +} + +QString Address::street() const +{ + return d->mStreet; +} + +QString Address::streetLabel() +{ + return i18n("Street"); +} + +void Address::setLocality(const QString &locality) +{ + d->mEmpty = false; + d->mLocality = locality; +} + +QString Address::locality() const +{ + return d->mLocality; +} + +QString Address::localityLabel() +{ + return i18n("Locality"); +} + +void Address::setRegion(const QString ®ion) +{ + d->mEmpty = false; + d->mRegion = region; +} + +QString Address::region() const +{ + return d->mRegion; +} + +QString Address::regionLabel() +{ + return i18n("Region"); +} + +void Address::setPostalCode(const QString &postalCode) +{ + d->mEmpty = false; + d->mPostalCode = postalCode; +} + +QString Address::postalCode() const +{ + return d->mPostalCode; +} + +QString Address::postalCodeLabel() +{ + return i18n("Postal Code"); +} + +void Address::setCountry(const QString &country) +{ + d->mEmpty = false; + d->mCountry = country; +} + +QString Address::country() const +{ + return d->mCountry; +} + +QString Address::countryLabel() +{ + return i18n("Country"); +} + +void Address::setLabel(const QString &label) +{ + d->mEmpty = false; + d->mLabel = label; +} + +QString Address::label() const +{ + return d->mLabel; +} + +QString Address::labelLabel() +{ + return i18n("Delivery Label"); +} + +Address::TypeList Address::typeList() +{ + static TypeList list; + + if (list.isEmpty()) { + list << Dom << Intl << Postal << Parcel << Home << Work << Pref; + } + + return list; +} + +QString Address::typeFlagLabel(TypeFlag type) +{ + switch (type) { + case Dom: + return i18nc("Address is in home country", "Domestic"); + case Intl: + return i18nc("Address is not in home country", "International"); + case Postal: + return i18nc("Address for delivering letters", "Postal"); + case Parcel: + return i18nc("Address for delivering packages", "Parcel"); + case Home: + return i18nc("Home Address", "Home"); + case Work: + return i18nc("Work Address", "Work"); + case Pref: + return i18n("Preferred Address"); + default: + return i18nc("another type of address", "Other"); + } +} + +QString Address::toString() const +{ + QString str; + + str += QLatin1String("Address {\n"); + str += QStringLiteral(" IsEmpty: %1\n"). + arg(d->mEmpty ? QStringLiteral("true") : QStringLiteral("false")); + str += QStringLiteral(" Id: %1\n").arg(d->mId); + str += QStringLiteral(" Type: %1\n").arg(typeLabel(d->mType)); + str += QStringLiteral(" Post office box: %1\n").arg(d->mPostOfficeBox); + str += QStringLiteral(" Extended: %1\n").arg(d->mExtended); + str += QStringLiteral(" Street: %1\n").arg(d->mStreet); + str += QStringLiteral(" Locality: %1\n").arg(d->mLocality); + str += QStringLiteral(" Region: %1\n").arg(d->mRegion); + str += QStringLiteral(" Postal code: %1\n").arg(d->mPostalCode); + str += QStringLiteral(" Country: %1\n").arg(d->mCountry); + str += QStringLiteral(" Label: %1\n").arg(d->mLabel); + str += QLatin1String("}\n"); + + return str; +} + +QString Address::formattedAddress(const QString &realName, + const QString &orgaName) const +{ + QString ciso; + QString addrTemplate; + QString ret; + + // FIXME: first check for iso-country-field and prefer that one + if (!country().isEmpty()) { + ciso = countryToISO(country()); + } else { + // fall back to our own country + ciso = QLocale().bcp47Name(); + } + KConfig entry(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("kf5/locale/countries/") + ciso + QLatin1String("/country.desktop"))); + + KConfigGroup group = entry.group("KCM Locale"); + // decide whether this needs special business address formatting + if (orgaName.isEmpty()) { + addrTemplate = group.readEntry("AddressFormat"); + } else { + addrTemplate = group.readEntry("BusinessAddressFormat"); + if (addrTemplate.isEmpty()) { + addrTemplate = group.readEntry("AddressFormat"); + } + } + + // in the case there's no format found at all, default to what we've always + // used: + if (addrTemplate.isEmpty()) { + qCWarning(KCONTACTS_LOG) << "address format database incomplete" + << "(no format for locale" << ciso + << "found). Using default address formatting."; + addrTemplate = QStringLiteral("%0(%n\\n)%0(%cm\\n)%0(%s\\n)%0(PO BOX %p\\n)%0(%l%w%r)%,%z"); + } + + // scan + parseAddressTemplateSection(addrTemplate, ret, realName, orgaName, *this); + + // now add the country line if needed (formatting this time according to + // the rules of our own system country ) + if (!country().isEmpty()) { + KConfig entry(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("kf5/locale/countries/") + + QLocale().name() + + QLatin1String("/country.desktop"))); + KConfigGroup group = entry.group("KCM Locale"); + QString cpos = group.readEntry("AddressCountryPosition"); + if (QLatin1String("BELOW") == cpos || cpos.isEmpty()) { + ret = ret + QLatin1String("\n\n") + country().toUpper(); + } else if (QLatin1String("below") == cpos) { + ret = ret + QLatin1String("\n\n") + country(); + } else if (QLatin1String("ABOVE") == cpos) { + ret = country().toUpper() + QLatin1String("\n\n") + ret; + } else if (QLatin1String("above") == cpos) { + ret = country() + QLatin1String("\n\n") + ret; + } + } + + return ret; +} + +typedef QMap StringMap; +Q_GLOBAL_STATIC(StringMap, sISOMap) + +QString Address::countryToISO(const QString &cname) +{ + // we search a map file for translations from country names to + // iso codes, storing caching things in a QMap for faster future + // access. + + QMap::ConstIterator it; + it = sISOMap->constFind(cname); + if (it != sISOMap->constEnd()) { + return it.value(); + } + + QString mapfile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kf5/kcontacts/countrytransl.map")); + if (mapfile.isEmpty()) { + qWarning() << "Installation error, couldn't find the countrytransl.map file"; + } + + QFile file(mapfile); + if (file.open(QIODevice::ReadOnly)) { + QTextStream s(&file); + QString strbuf = s.readLine(); + while (!strbuf.isEmpty()) { + QStringList countryInfo = strbuf.split(QLatin1Char('\t'), QString::KeepEmptyParts); + if (countryInfo[0] == cname) { + file.close(); + sISOMap->insert(cname, countryInfo[1]); + return countryInfo[1]; + } + strbuf = s.readLine(); + } + file.close(); + } + + // fall back to system country + QString systemCountry = QLocale().bcp47Name(); + sISOMap->insert(cname, systemCountry); + return systemCountry; +} + +QString Address::ISOtoCountry(const QString &ISOname) +{ + // get country name from ISO country code (e.g. "no" -> i18n("Norway")) + if (ISOname.simplified().isEmpty()) { + return QString(); + } + + QString mapfile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kf5/kabc/countrytransl.map")); + + QFile file(mapfile); + if (file.open(QIODevice::ReadOnly)) { + QTextStream s(&file); + QString searchStr = QLatin1Char('\t') + ISOname.simplified().toLower(); + QString strbuf = s.readLine(); + int pos; + while (!strbuf.isEmpty()) { + if ((pos = strbuf.indexOf(searchStr)) != -1) { + file.close(); + return i18n(strbuf.left(pos).toUtf8().constData()); + } + strbuf = s.readLine(); + } + file.close(); + } + + return ISOname; +} + +QDataStream &KContacts::operator<<(QDataStream &s, const Address &addr) +{ + return s << addr.d->mId << (uint)addr.d->mType << addr.d->mPostOfficeBox + << addr.d->mExtended << addr.d->mStreet << addr.d->mLocality + << addr.d->mRegion << addr.d->mPostalCode << addr.d->mCountry + << addr.d->mLabel << addr.d->mEmpty; +} + +QDataStream &KContacts::operator>>(QDataStream &s, Address &addr) +{ + uint type; + s >> addr.d->mId >> type >> addr.d->mPostOfficeBox >> addr.d->mExtended + >> addr.d->mStreet >> addr.d->mLocality >> addr.d->mRegion + >> addr.d->mPostalCode >> addr.d->mCountry >> addr.d->mLabel + >> addr.d->mEmpty; + + addr.d->mType = Address::Type(type); + + return s; +} diff --git a/src/address.h b/src/address.h new file mode 100644 index 0000000..9784c5b --- /dev/null +++ b/src/address.h @@ -0,0 +1,343 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2001 Cornelius Schumacher + + 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 KCONTACTS_ADDRESS_H +#define KCONTACTS_ADDRESS_H + +#include +#include +#include + +#include "kcontacts_export.h" + +namespace KContacts +{ + +/** + @brief + Postal address information. + + This class represents information about a postal address. +*/ +class KCONTACTS_EXPORT Address +{ + friend KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &s, const Address &addr); + friend KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &s, Address &addr); + +public: + /** + List of addresses. + */ + typedef QVector
List; + + /** + Address types: + */ + enum TypeFlag { + Dom = 1, /**< domestic */ + Intl = 2, /**< international */ + Postal = 4, /**< postal */ + Parcel = 8, /**< parcel */ + Home = 16, /**< home address */ + Work = 32, /**< address at work */ + Pref = 64 /**< preferred address */ + }; + + Q_DECLARE_FLAGS(Type, TypeFlag) + + /** + List of address types. + */ + typedef QList TypeList; + + /** + Creates an empty address. + */ + Address(); + + /** + Creates an address of the given @p type. + */ + Address(Type type); + + /** + Copy constructor. + */ + Address(const Address &address); + + /** + Destroys the address. + */ + ~Address(); + + /** + Equality operator. + + @param addr the address to compare to + @return @c true if @c this and @p addr are equal, otherwise @c false + */ + bool operator==(const Address &other) const; + + /** + Not-equal operator. + + @param addr the address to compare to + @return @c true if @c this and @p addr are not equal, otherwise @c false + */ + bool operator!=(const Address &other) const; + + /** + Assignment operator. + + @param addr the address data to assign to @c this + @return a reference to @c this + */ + Address &operator=(const Address &other); + + /** + Returns true, if the address is empty. + */ + bool isEmpty() const; + + /** + Clears all entries of the address. + */ + void clear(); + + /** + Sets the unique @p identifier. + */ + void setId(const QString &identifier); + + /** + Returns the unique identifier. + */ + QString id() const; + + /** + Sets the type of address. See enum for definiton of types. + + @param type type, can be a bitwise or of multiple types. + */ + void setType(Type type); + + /** + Returns the type of address. Can be a bitwise or of multiple types. + */ + Type type() const; + + /** + Returns a translated string of all types the address has. + */ + QString typeLabel() const; + + /** + Sets the post office box. + */ + void setPostOfficeBox(const QString &postOfficeBox); + + /** + Returns the post office box. + */ + QString postOfficeBox() const; + + /** + Returns the translated label for post office box field. + */ + static QString postOfficeBoxLabel(); + + /** + Sets the @p extended address information. + */ + void setExtended(const QString &extended); + + /** + Returns the extended address information. + */ + QString extended() const; + + /** + Returns the translated label for extended field. + */ + static QString extendedLabel(); + + /** + Sets the @p street (including house number). + */ + void setStreet(const QString &street); + + /** + Returns the street. + */ + QString street() const; + + /** + Returns the translated label for street field. + */ + static QString streetLabel(); + + /** + Sets the @p locality, e.g. city. + + @param locality the locality of the address, e.g. city + */ + void setLocality(const QString &locality); + + /** + Returns the locality. + */ + QString locality() const; + + /** + Returns the translated label for locality field. + */ + static QString localityLabel(); + + /** + Sets the @p region, e.g. state. + + @param region the region the address falls into, e.g. state + */ + void setRegion(const QString ®ion); + + /** + Returns the region. + */ + QString region() const; + + /** + Returns the translated label for region field. + */ + static QString regionLabel(); + + /** + Sets the postal @p code. + */ + void setPostalCode(const QString &code); + + /** + Returns the postal code. + */ + QString postalCode() const; + + /** + Returns the translated label for postal code field. + */ + static QString postalCodeLabel(); + + /** + Sets the @p country. + */ + void setCountry(const QString &country); + + /** + Returns the country. + */ + QString country() const; + + /** + Returns the translated label for country field. + */ + static QString countryLabel(); + + /** + Sets the delivery @p label. This is the literal text to be used as label. + + @param label the string to use for delivery labels + */ + void setLabel(const QString &label); + + /** + Returns the delivery label. + */ + QString label() const; + + /** + Returns the translated label for delivery label field. + */ + static QString labelLabel(); + + /** + Returns the list of available types. + */ + static TypeList typeList(); + + /** + Returns the translated label for the given @p type. + */ + static QString typeLabel(Type type); + + /** + Returns a string representation of the address. + */ + QString toString() const; + + /** + Returns this address formatted according to the country-specific + address formatting rules. The formatting rules applied depend on + either the addresses {@link #country country} field, or (if the + latter is empty) on the system country setting. If companyName is + provided, an available business address format will be preferred. + + @param realName the formatted name of the contact + @param orgaName the name of the organization or company + @return the formatted address (containing newline characters) + */ + QString formattedAddress(const QString &realName = QString(), + const QString &orgaName = QString()) const; + + /** + Returns ISO code for a localized country name. Only localized country + names will be understood. This might be replaced by a KLocale method in + the future. + @param cname name of the country + @return two digit ISO code + */ + static QString countryToISO(const QString &cname); + + /** + Returns a localized country name for a ISO code. + This might be replaced by a KLocale method in the future. + @param ISOname two digit ISO code + @return localized name of the country + */ + static QString ISOtoCountry(const QString &ISOname); + + static QString typeFlagLabel(TypeFlag type); +private: + class Private; + QSharedDataPointer d; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(Address::Type) + +/** + Serializes the @p address object into the @p stream. +*/ +KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &stream, const Address &address); + +/** + Initializes the @p address object from the @p stream. +*/ +KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &stream, Address &address); + +} + +#endif diff --git a/src/addressee.cpp b/src/addressee.cpp new file mode 100644 index 0000000..1894e2a --- /dev/null +++ b/src/addressee.cpp @@ -0,0 +1,2381 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2001 Cornelius Schumacher + Copyright (c) 2003 Carsten Pfeiffer + Copyright (c) 2005 Ingo Kloecker + + 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 +#include +#include +#include + +#include "kcontacts_debug.h" +#include + +#include "addresseehelper.h" +#include "field.h" +#include "sortmode.h" + +#include "addressee.h" + +using namespace KContacts; + +static bool matchBinaryPattern(int value, int pattern); + +template +static bool listEquals(const QVector &list, const QVector &pattern); +static bool listEquals(const QStringList &list, const QStringList &pattern); + +class Q_DECL_HIDDEN Addressee::Private : public QSharedData +{ +public: + Private() + : mUid(QUuid::createUuid().toString().mid(1, 36)) + , mEmpty(true) + , mChanged(false) + { + //We avoid the curly braces so the string is RFC4122 compliant and can be used as urn + } + + Private(const Private &other) + : QSharedData(other) + { + mUid = other.mUid; + mName = other.mName; + mFormattedName = other.mFormattedName; + mFamilyName = other.mFamilyName; + mGivenName = other.mGivenName; + mAdditionalName = other.mAdditionalName; + mPrefix = other.mPrefix; + mSuffix = other.mSuffix; + mNickName = other.mNickName; + mBirthday = other.mBirthday; + mMailer = other.mMailer; + mTimeZone = other.mTimeZone; + mGeo = other.mGeo; + mTitle = other.mTitle; + mRole = other.mRole; + mOrganization = other.mOrganization; + mDepartment = other.mDepartment; + mNote = other.mNote; + mProductId = other.mProductId; + mRevision = other.mRevision; + mSortString = other.mSortString; + mSecrecy = other.mSecrecy; + mLogo = other.mLogo; + mPhoto = other.mPhoto; + mSound = other.mSound; + + mPhoneNumbers = other.mPhoneNumbers; + mAddresses = other.mAddresses; + mKeys = other.mKeys; + mLangs = other.mLangs; + mGender = other.mGender; + mEmails = other.mEmails; + mCategories = other.mCategories; + mCustomFields = other.mCustomFields; + mCalendarUrl = other.mCalendarUrl; + mSoundListExtra = other.mSoundListExtra; + mPhotoExtraList = other.mPhotoExtraList; + mLogoExtraList = other.mLogoExtraList; + mUrlExtraList = other.mUrlExtraList; + mMembers = other.mMembers; + mRelationShips = other.mRelationShips; + mSources = other.mSources; + mEmpty = other.mEmpty; + mImpps = other.mImpps; + mChanged = other.mChanged; + } + + ~Private() + { + } + + QString mUid; + QString mName; + QString mFormattedName; + QString mFamilyName; + QString mGivenName; + QString mAdditionalName; + QString mPrefix; + QString mSuffix; + QString mNickName; + QDateTime mBirthday; + QString mMailer; + TimeZone mTimeZone; + Geo mGeo; + QString mTitle; + QString mRole; + QString mOrganization; + QString mDepartment; + QString mNote; + QString mProductId; + QDateTime mRevision; + QString mSortString; + Secrecy mSecrecy; + Picture mLogo; + Picture mPhoto; + Sound mSound; + + PhoneNumber::List mPhoneNumbers; + Address::List mAddresses; + Key::List mKeys; + Email::List mEmails; + Lang::List mLangs; + Impp::List mImpps; + Gender mGender; + QString mKind; + QStringList mCategories; + QHash mCustomFields; + CalendarUrl::List mCalendarUrl; + Sound::List mSoundListExtra; + Picture::List mPhotoExtraList; + Picture::List mLogoExtraList; + ResourceLocatorUrl::List mUrlExtraList; + QVector mSources; + QStringList mMembers; + Related::List mRelationShips; + bool mEmpty : 1; + bool mChanged : 1; + + static KContacts::SortMode *mSortMode; +}; + +KContacts::SortMode *Addressee::Private::mSortMode = Q_NULLPTR; + +Addressee::Addressee() + : d(new Private) +{ +} + +Addressee::~Addressee() +{ +} + +Addressee::Addressee(const Addressee &other) + : d(other.d) +{ +} + +Addressee &Addressee::operator=(const Addressee &other) +{ + if (this != &other) { + d = other.d; + } + + return *this; +} + +bool Addressee::operator==(const Addressee &addressee) const +{ + if (d->mUid != addressee.d->mUid) { + qCDebug(KCONTACTS_LOG) << "uid differs"; + return false; + } + + if (d->mName != addressee.d->mName && + !(d->mName.isEmpty() && addressee.d->mName.isEmpty())) { + qCDebug(KCONTACTS_LOG) << "name differs"; + return false; + } + + if (d->mFormattedName != addressee.d->mFormattedName && + !(d->mFormattedName.isEmpty() && addressee.d->mFormattedName.isEmpty())) { + qCDebug(KCONTACTS_LOG) << "formattedName differs"; + return false; + } + + if (d->mFamilyName != addressee.d->mFamilyName && + !(d->mFamilyName.isEmpty() && addressee.d->mFamilyName.isEmpty())) { + qCDebug(KCONTACTS_LOG) << "familyName differs"; + return false; + } + + if (d->mGivenName != addressee.d->mGivenName && + !(d->mGivenName.isEmpty() && addressee.d->mGivenName.isEmpty())) { + qCDebug(KCONTACTS_LOG) << "givenName differs"; + return false; + } + + if (d->mAdditionalName != addressee.d->mAdditionalName && + !(d->mAdditionalName.isEmpty() && addressee.d->mAdditionalName.isEmpty())) { + qCDebug(KCONTACTS_LOG) << "additionalName differs"; + return false; + } + + if (d->mPrefix != addressee.d->mPrefix && + !(d->mPrefix.isEmpty() && addressee.d->mPrefix.isEmpty())) { + qCDebug(KCONTACTS_LOG) << "prefix differs"; + return false; + } + + if (d->mSuffix != addressee.d->mSuffix && + !(d->mSuffix.isEmpty() && addressee.d->mSuffix.isEmpty())) { + qCDebug(KCONTACTS_LOG) << "suffix differs"; + return false; + } + + if (d->mNickName != addressee.d->mNickName && + !(d->mNickName.isEmpty() && addressee.d->mNickName.isEmpty())) { + qCDebug(KCONTACTS_LOG) << "nickName differs"; + return false; + } + + if (d->mBirthday != addressee.d->mBirthday) { + qCDebug(KCONTACTS_LOG) << "birthday differs"; + return false; + } + + if (d->mMailer != addressee.d->mMailer && + !(d->mMailer.isEmpty() && addressee.d->mMailer.isEmpty())) { + qCDebug(KCONTACTS_LOG) << "mailer differs"; + return false; + } + + if (d->mTimeZone != addressee.d->mTimeZone) { + qCDebug(KCONTACTS_LOG) << "timeZone differs"; + return false; + } + + if (d->mGeo != addressee.d->mGeo) { + qCDebug(KCONTACTS_LOG) << "geo differs"; + return false; + } + + if (d->mTitle != addressee.d->mTitle && + !(d->mTitle.isEmpty() && addressee.d->mTitle.isEmpty())) { + qCDebug(KCONTACTS_LOG) << "title differs"; + return false; + } + + if (d->mRole != addressee.d->mRole && + !(d->mRole.isEmpty() && addressee.d->mRole.isEmpty())) { + qCDebug(KCONTACTS_LOG) << "role differs"; + return false; + } + + if (d->mOrganization != addressee.d->mOrganization && + !(d->mOrganization.isEmpty() && addressee.d->mOrganization.isEmpty())) { + qCDebug(KCONTACTS_LOG) << "organization differs"; + return false; + } + + if (d->mDepartment != addressee.d->mDepartment && + !(d->mDepartment.isEmpty() && addressee.d->mDepartment.isEmpty())) { + qCDebug(KCONTACTS_LOG) << "department differs"; + return false; + } + + if (d->mNote != addressee.d->mNote && + !(d->mNote.isEmpty() && addressee.d->mNote.isEmpty())) { + qCDebug(KCONTACTS_LOG) << "note differs"; + return false; + } + + if (d->mProductId != addressee.d->mProductId && + !(d->mProductId.isEmpty() && addressee.d->mProductId.isEmpty())) { + qCDebug(KCONTACTS_LOG) << "productId differs"; + return false; + } + + if (d->mSortString != addressee.d->mSortString && + !(d->mSortString.isEmpty() && addressee.d->mSortString.isEmpty())) { + qCDebug(KCONTACTS_LOG) << "sortString differs"; + return false; + } + + if (d->mSecrecy != addressee.d->mSecrecy) { + qCDebug(KCONTACTS_LOG) << "secrecy differs"; + return false; + } + + if (d->mLogo != addressee.d->mLogo) { + qCDebug(KCONTACTS_LOG) << "logo differs"; + return false; + } + + if (d->mPhoto != addressee.d->mPhoto) { + qCDebug(KCONTACTS_LOG) << "photo differs"; + return false; + } + + if (d->mSound != addressee.d->mSound) { + qCDebug(KCONTACTS_LOG) << "sound differs"; + return false; + } + + if (!listEquals(d->mPhoneNumbers, addressee.d->mPhoneNumbers)) { + qCDebug(KCONTACTS_LOG) << "phoneNumbers differs"; + return false; + } + + if (!listEquals(d->mAddresses, addressee.d->mAddresses)) { + qCDebug(KCONTACTS_LOG) << "addresses differs"; + return false; + } + + if (!listEquals(d->mKeys, addressee.d->mKeys)) { + qCDebug(KCONTACTS_LOG) << "keys differs"; + return false; + } + if (!listEquals(d->mEmails, addressee.d->mEmails)) { + qCDebug(KCONTACTS_LOG) << "emails differs"; + return false; + } + + if (!listEquals(d->mCategories, addressee.d->mCategories)) { + qCDebug(KCONTACTS_LOG) << "categories differs"; + return false; + } + + if (d->mCustomFields != addressee.d->mCustomFields) { + qCDebug(KCONTACTS_LOG) << "custom differs"; + return false; + } + if (d->mLangs != addressee.d->mLangs) { + qCDebug(KCONTACTS_LOG) << "langs differs"; + return false; + } + if (d->mImpps != addressee.d->mImpps) { + qCDebug(KCONTACTS_LOG) << "impps differs"; + return false; + } + if (d->mGender != addressee.d->mGender) { + qCDebug(KCONTACTS_LOG) << "gender differs"; + return false; + } + if (d->mKind != addressee.d->mKind) { + qCDebug(KCONTACTS_LOG) << "kind differs"; + return false; + } + if (!listEquals(d->mCalendarUrl, addressee.d->mCalendarUrl)) { + qCDebug(KCONTACTS_LOG) << "calendarUrl differs"; + return false; + } + if (!listEquals(d->mSoundListExtra, addressee.d->mSoundListExtra)) { + qCDebug(KCONTACTS_LOG) << "Extra sound differs"; + return false; + } + if (!listEquals(d->mPhotoExtraList, addressee.d->mPhotoExtraList)) { + qCDebug(KCONTACTS_LOG) << "Extra photo differs"; + return false; + } + if (!listEquals(d->mLogoExtraList, addressee.d->mLogoExtraList)) { + qCDebug(KCONTACTS_LOG) << "Extra logo differs"; + return false; + } + if (!listEquals(d->mUrlExtraList, addressee.d->mUrlExtraList)) { + qCDebug(KCONTACTS_LOG) << "Extra url differs"; + return false; + } + if (!listEquals(d->mMembers, addressee.d->mMembers)) { + qCDebug(KCONTACTS_LOG) << "Extra url differs"; + return false; + } + if (!listEquals(d->mRelationShips, addressee.d->mRelationShips)) { + qCDebug(KCONTACTS_LOG) << "RelationShips differs"; + return false; + } + if (!listEquals(d->mSources, addressee.d->mSources)) { + qCDebug(KCONTACTS_LOG) << "Sources differs"; + return false; + } + + return true; +} + +bool Addressee::operator!=(const Addressee &a) const +{ + return !(a == *this); +} + +bool Addressee::isEmpty() const +{ + return d->mEmpty; +} + +void Addressee::setUid(const QString &id) +{ + if (id == d->mUid) { + return; + } + + d->mEmpty = false; + d->mUid = id; +} + +QString Addressee::uid() const +{ + return d->mUid; +} + +QString Addressee::uidLabel() +{ + return i18n("Unique Identifier"); +} + +void Addressee::setName(const QString &name) +{ + if (name == d->mName) { + return; + } + + d->mEmpty = false; + d->mName = name; +} + +QString Addressee::name() const +{ + return d->mName; +} + +QString Addressee::nameLabel() +{ + return i18n("Name"); +} + +void Addressee::setKind(const QString &kind) +{ + if (kind == d->mKind) { + return; + } + + d->mEmpty = false; + d->mKind = kind; +} + +QString Addressee::kind() const +{ + return d->mKind; +} + +void Addressee::insertExtraSound(const Sound &sound) +{ + d->mEmpty = false; + d->mSoundListExtra.append(sound); +} + +Sound::List Addressee::extraSoundList() const +{ + return d->mSoundListExtra; +} + +void Addressee::insertExtraPhoto(const Picture &picture) +{ + d->mEmpty = false; + d->mPhotoExtraList.append(picture); +} + +Picture::List Addressee::extraPhotoList() const +{ + return d->mPhotoExtraList; +} + +void Addressee::insertExtraLogo(const Picture &logo) +{ + d->mEmpty = false; + d->mLogoExtraList.append(logo); +} + +Picture::List Addressee::extraLogoList() const +{ + return d->mLogoExtraList; +} + +void Addressee::setExtraSoundList(const Sound::List &soundList) +{ + d->mEmpty = false; + d->mSoundListExtra = soundList; +} + +void Addressee::setExtraPhotoList(const Picture::List &pictureList) +{ + d->mEmpty = false; + d->mPhotoExtraList = pictureList; +} + +void Addressee::setExtraLogoList(const Picture::List &logoList) +{ + d->mEmpty = false; + d->mLogoExtraList = logoList; +} + +void Addressee::insertExtraUrl(const ResourceLocatorUrl &url) +{ + if (url.isValid()) { + d->mEmpty = false; + d->mUrlExtraList.append(url); + } +} + +void Addressee::setExtraUrlList(const ResourceLocatorUrl::List &urlList) +{ + d->mEmpty = false; + d->mUrlExtraList = urlList; +} + +ResourceLocatorUrl::List Addressee::extraUrlList() const +{ + return d->mUrlExtraList; +} + +void Addressee::insertSourceUrl(const QUrl &url) +{ + d->mEmpty = false; + d->mSources.append(url); +} + +void Addressee::setSourcesUrlList(const QVector &urlList) +{ + d->mEmpty = false; + d->mSources = urlList; +} + +QVector Addressee::sourcesUrlList() const +{ + return d->mSources; +} + +void Addressee::insertImpp(const Impp &impp) +{ + if (impp.isValid()) { + d->mEmpty = false; + //Don't duplicate ? + d->mImpps.append(impp); + } +} + +void Addressee::setImppList(const Impp::List &imppList) +{ + d->mEmpty = false; + d->mImpps = imppList; +} + +Impp::List Addressee::imppList() const +{ + return d->mImpps; +} + +void Addressee::insertCalendarUrl(const CalendarUrl &calendarUrl) +{ + d->mEmpty = false; + //TODO verify that there is not same calendarurl + if (calendarUrl.isValid()) { + d->mCalendarUrl.append(calendarUrl); + } +} + +CalendarUrl::List Addressee::calendarUrlList() const +{ + return d->mCalendarUrl; +} + +void Addressee::setFormattedName(const QString &formattedName) +{ + if (formattedName == d->mFormattedName) { + return; + } + + d->mEmpty = false; + d->mFormattedName = formattedName; +} + +QString Addressee::formattedName() const +{ + return d->mFormattedName; +} + +QString Addressee::formattedNameLabel() +{ + return i18n("Formatted Name"); +} + +void Addressee::setFamilyName(const QString &familyName) +{ + if (familyName == d->mFamilyName) { + return; + } + + d->mEmpty = false; + d->mFamilyName = familyName; +} + +QString Addressee::familyName() const +{ + return d->mFamilyName; +} + +QString Addressee::familyNameLabel() +{ + return i18n("Family Name"); +} + +void Addressee::setGivenName(const QString &givenName) +{ + if (givenName == d->mGivenName) { + return; + } + + d->mEmpty = false; + d->mGivenName = givenName; +} + +QString Addressee::givenName() const +{ + return d->mGivenName; +} + +QString Addressee::givenNameLabel() +{ + return i18n("Given Name"); +} + +void Addressee::setAdditionalName(const QString &additionalName) +{ + if (additionalName == d->mAdditionalName) { + return; + } + + d->mEmpty = false; + d->mAdditionalName = additionalName; +} + +QString Addressee::additionalName() const +{ + return d->mAdditionalName; +} + +QString Addressee::additionalNameLabel() +{ + return i18n("Additional Names"); +} + +void Addressee::setPrefix(const QString &prefix) +{ + if (prefix == d->mPrefix) { + return; + } + + d->mEmpty = false; + d->mPrefix = prefix; +} + +QString Addressee::prefix() const +{ + return d->mPrefix; +} + +QString Addressee::prefixLabel() +{ + return i18n("Honorific Prefixes"); +} + +void Addressee::setSuffix(const QString &suffix) +{ + if (suffix == d->mSuffix) { + return; + } + + d->mEmpty = false; + d->mSuffix = suffix; +} + +QString Addressee::suffix() const +{ + return d->mSuffix; +} + +QString Addressee::suffixLabel() +{ + return i18n("Honorific Suffixes"); +} + +void Addressee::setNickName(const QString &nickName) +{ + if (nickName == d->mNickName) { + return; + } + + d->mEmpty = false; + d->mNickName = nickName; +} + +QString Addressee::nickName() const +{ + return d->mNickName; +} + +QString Addressee::nickNameLabel() +{ + return i18n("Nick Name"); +} + +void Addressee::setBirthday(const QDateTime &birthday) +{ + if (birthday == d->mBirthday) { + return; + } + + d->mEmpty = false; + d->mBirthday = birthday; +} + +QDateTime Addressee::birthday() const +{ + return d->mBirthday; +} + +QString Addressee::birthdayLabel() +{ + return i18n("Birthday"); +} + +QString Addressee::homeAddressStreetLabel() +{ + return i18n("Home Address Street"); +} + +QString Addressee::homeAddressPostOfficeBoxLabel() +{ + return i18n("Home Address Post Office Box"); +} + +QString Addressee::homeAddressLocalityLabel() +{ + return i18n("Home Address City"); +} + +QString Addressee::homeAddressRegionLabel() +{ + return i18n("Home Address State"); +} + +QString Addressee::homeAddressPostalCodeLabel() +{ + return i18n("Home Address Zip Code"); +} + +QString Addressee::homeAddressCountryLabel() +{ + return i18n("Home Address Country"); +} + +QString Addressee::homeAddressLabelLabel() +{ + return i18n("Home Address Label"); +} + +QString Addressee::businessAddressStreetLabel() +{ + return i18n("Business Address Street"); +} + +QString Addressee::businessAddressPostOfficeBoxLabel() +{ + return i18n("Business Address Post Office Box"); +} + +QString Addressee::businessAddressLocalityLabel() +{ + return i18n("Business Address City"); +} + +QString Addressee::businessAddressRegionLabel() +{ + return i18n("Business Address State"); +} + +QString Addressee::businessAddressPostalCodeLabel() +{ + return i18n("Business Address Zip Code"); +} + +QString Addressee::businessAddressCountryLabel() +{ + return i18n("Business Address Country"); +} + +QString Addressee::businessAddressLabelLabel() +{ + return i18n("Business Address Label"); +} + +QString Addressee::homePhoneLabel() +{ + return i18n("Home Phone"); +} + +QString Addressee::businessPhoneLabel() +{ + return i18n("Business Phone"); +} + +QString Addressee::mobilePhoneLabel() +{ + return i18n("Mobile Phone"); +} + +QString Addressee::homeFaxLabel() +{ + return i18n("Home Fax"); +} + +QString Addressee::businessFaxLabel() +{ + return i18n("Business Fax"); +} + +QString Addressee::carPhoneLabel() +{ + return i18n("Car Phone"); +} + +QString Addressee::isdnLabel() +{ + return i18n("ISDN"); +} + +QString Addressee::pagerLabel() +{ + return i18n("Pager"); +} + +QString Addressee::emailLabel() +{ + return i18n("Email Address"); +} + +void Addressee::setMailer(const QString &mailer) +{ + if (mailer == d->mMailer) { + return; + } + + d->mEmpty = false; + d->mMailer = mailer; +} + +QString Addressee::mailer() const +{ + return d->mMailer; +} + +QString Addressee::mailerLabel() +{ + return i18n("Mail Client"); +} + +void Addressee::setTimeZone(const TimeZone &timeZone) +{ + if (timeZone == d->mTimeZone) { + return; + } + + d->mEmpty = false; + d->mTimeZone = timeZone; +} + +TimeZone Addressee::timeZone() const +{ + return d->mTimeZone; +} + +QString Addressee::timeZoneLabel() +{ + return i18n("Time Zone"); +} + +void Addressee::setGeo(const Geo &geo) +{ + if (geo == d->mGeo) { + return; + } + + d->mEmpty = false; + d->mGeo = geo; +} + +Geo Addressee::geo() const +{ + return d->mGeo; +} + +QString Addressee::geoLabel() +{ + return i18n("Geographic Position"); +} + +void Addressee::setTitle(const QString &title) +{ + if (title == d->mTitle) { + return; + } + + d->mEmpty = false; + d->mTitle = title; +} + +QString Addressee::title() const +{ + return d->mTitle; +} + +QString Addressee::titleLabel() +{ + return i18nc("a person's title", "Title"); +} + +void Addressee::setRole(const QString &role) +{ + if (role == d->mRole) { + return; + } + + d->mEmpty = false; + d->mRole = role; +} + +QString Addressee::role() const +{ + return d->mRole; +} + +QString Addressee::roleLabel() +{ + return i18nc("of a person in an organization", "Role"); +} + +void Addressee::setOrganization(const QString &organization) +{ + if (organization == d->mOrganization) { + return; + } + + d->mEmpty = false; + d->mOrganization = organization; +} + +QString Addressee::organization() const +{ + return d->mOrganization; +} + +QString Addressee::organizationLabel() +{ + return i18n("Organization"); +} + +void Addressee::setDepartment(const QString &department) +{ + if (department == d->mDepartment) { + return; + } + + d->mEmpty = false; + d->mDepartment = department; +} + +QString Addressee::department() const +{ + return d->mDepartment; +} + +QString Addressee::departmentLabel() +{ + return i18n("Department"); +} + +void Addressee::setNote(const QString ¬e) +{ + if (note == d->mNote) { + return; + } + + d->mEmpty = false; + d->mNote = note; +} + +QString Addressee::note() const +{ + return d->mNote; +} + +QString Addressee::noteLabel() +{ + return i18n("Note"); +} + +void Addressee::setProductId(const QString &productId) +{ + if (productId == d->mProductId) { + return; + } + + d->mEmpty = false; + d->mProductId = productId; +} + +QString Addressee::productId() const +{ + return d->mProductId; +} + +QString Addressee::productIdLabel() +{ + return i18n("Product Identifier"); +} + +void Addressee::setRevision(const QDateTime &revision) +{ + if (revision == d->mRevision) { + return; + } + + d->mEmpty = false; + d->mRevision = revision; +} + +QDateTime Addressee::revision() const +{ + return d->mRevision; +} + +QString Addressee::revisionLabel() +{ + return i18n("Revision Date"); +} + +void Addressee::setSortString(const QString &sortString) +{ + if (sortString == d->mSortString) { + return; + } + + d->mEmpty = false; + d->mSortString = sortString; +} + +QString Addressee::sortString() const +{ + return d->mSortString; +} + +QString Addressee::sortStringLabel() +{ + return i18n("Sort String"); +} + +void Addressee::setUrl(const QUrl &url) +{ + KContacts::ResourceLocatorUrl resourceLocator; + resourceLocator.setUrl(url); + insertExtraUrl(resourceLocator); +} + +void Addressee::setUrl(const ResourceLocatorUrl &url) +{ + insertExtraUrl(url); +} + +ResourceLocatorUrl Addressee::url() const +{ + if (d->mUrlExtraList.isEmpty()) { + return ResourceLocatorUrl(); + } else { + return d->mUrlExtraList.at(0); + } +} + +QString Addressee::urlLabel() +{ + return i18n("Homepage"); +} + +void Addressee::setSecrecy(const Secrecy &secrecy) +{ + if (secrecy == d->mSecrecy) { + return; + } + + d->mEmpty = false; + d->mSecrecy = secrecy; +} + +Secrecy Addressee::secrecy() const +{ + return d->mSecrecy; +} + +QString Addressee::secrecyLabel() +{ + return i18n("Security Class"); +} + +void Addressee::setLogo(const Picture &logo) +{ + if (logo == d->mLogo) { + return; + } + + d->mEmpty = false; + d->mLogo = logo; +} + +Picture Addressee::logo() const +{ + return d->mLogo; +} + +QString Addressee::logoLabel() +{ + return i18n("Logo"); +} + +void Addressee::setPhoto(const Picture &photo) +{ + if (photo == d->mPhoto) { + return; + } + + d->mEmpty = false; + d->mPhoto = photo; +} + +Picture Addressee::photo() const +{ + return d->mPhoto; +} + +QString Addressee::photoLabel() +{ + return i18n("Photo"); +} + +void Addressee::setSound(const Sound &sound) +{ + if (sound == d->mSound) { + return; + } + + d->mEmpty = false; + d->mSound = sound; +} + +Sound Addressee::sound() const +{ + return d->mSound; +} + +QString Addressee::soundLabel() +{ + return i18n("Sound"); +} + +void Addressee::setNameFromString(const QString &s) +{ + QString str = s; + //remove enclosing quotes from string + if (str.length() > 1 && + s[0] == QLatin1Char('"') && + s[s.length() - 1] == QLatin1Char('"')) { + str = s.mid(1, s.length() - 2); + } + + setFormattedName(str); + setName(str); + + // clear all name parts + setPrefix(QString()); + setGivenName(QString()); + setAdditionalName(QString()); + setFamilyName(QString()); + setSuffix(QString()); + + if (str.isEmpty()) { + return; + } + + static QString spaceStr = QStringLiteral(" "); + static QString emptyStr = QStringLiteral(""); + AddresseeHelper *helper = AddresseeHelper::self(); + + int i = str.indexOf(QLatin1Char(',')); + if (i < 0) { + QStringList parts = str.split(spaceStr); + int leftOffset = 0; + int rightOffset = parts.count() - 1; + + QString suffix; + while (rightOffset >= 0) { + if (helper->containsSuffix(parts[rightOffset])) { + suffix.prepend(parts[rightOffset] + (suffix.isEmpty() ? emptyStr : spaceStr)); + rightOffset--; + } else { + break; + } + } + setSuffix(suffix); + + if (rightOffset < 0) { + return; + } + + if (rightOffset - 1 >= 0 && helper->containsPrefix(parts[rightOffset - 1].toLower())) { + setFamilyName(parts[rightOffset - 1] + spaceStr + parts[rightOffset]); + rightOffset--; + } else { + if (helper->tradeAsFamilyName()) { + setFamilyName(parts[rightOffset]); + } else { + setGivenName(parts[rightOffset]); + } + } + + QString prefix; + while (leftOffset < rightOffset) { + if (helper->containsTitle(parts[leftOffset])) { + prefix.append((prefix.isEmpty() ? emptyStr : spaceStr) + parts[leftOffset]); + leftOffset++; + } else { + break; + } + } + setPrefix(prefix); + + if (leftOffset < rightOffset) { + setGivenName(parts[leftOffset]); + leftOffset++; + } + + QString additionalName; + while (leftOffset < rightOffset) { + additionalName.append((additionalName.isEmpty() ? emptyStr : spaceStr) + parts[leftOffset]); + leftOffset++; + } + setAdditionalName(additionalName); + } else { + QString part1 = str.left(i); + QString part2 = str.mid(i + 1); + + QStringList parts = part1.split(spaceStr); + int leftOffset = 0; + int rightOffset = parts.count() - 1; + + if (parts.count() > 0) { + + QString suffix; + while (rightOffset >= 0) { + if (helper->containsSuffix(parts[rightOffset])) { + suffix.prepend(parts[rightOffset] + (suffix.isEmpty() ? emptyStr : spaceStr)); + rightOffset--; + } else { + break; + } + } + setSuffix(suffix); + + if (rightOffset - 1 >= 0 && helper->containsPrefix(parts[rightOffset - 1].toLower())) { + setFamilyName(parts[rightOffset - 1] + spaceStr + parts[rightOffset]); + rightOffset--; + } else { + setFamilyName(parts[rightOffset]); + } + + QString prefix; + while (leftOffset < rightOffset) { + if (helper->containsTitle(parts[leftOffset])) { + prefix.append((prefix.isEmpty() ? emptyStr : spaceStr) + parts[leftOffset]); + leftOffset++; + } else { + break; + } + } + } else { + setPrefix(QString()); + setFamilyName(QString()); + setSuffix(QString()); + } + + parts = part2.split(spaceStr); + + leftOffset = 0; + rightOffset = parts.count(); + + if (parts.count() > 0) { + + QString prefix; + while (leftOffset < rightOffset) { + if (helper->containsTitle(parts[leftOffset])) { + prefix.append((prefix.isEmpty() ? emptyStr : spaceStr) + parts[leftOffset]); + leftOffset++; + } else { + break; + } + } + setPrefix(prefix); + + if (leftOffset < rightOffset) { + setGivenName(parts[leftOffset]); + leftOffset++; + } + + QString additionalName; + while (leftOffset < rightOffset) { + additionalName.append((additionalName.isEmpty() ? emptyStr : spaceStr) + parts[leftOffset]); + leftOffset++; + } + setAdditionalName(additionalName); + } else { + setGivenName(QString()); + setAdditionalName(QString()); + } + } +} + +QString Addressee::realName() const +{ + QString n(formattedName()); + if (!n.isEmpty()) { + return n; + } + + n = assembledName(); + if (!n.isEmpty()) { + return n; + } + + n = name(); + if (!n.isEmpty()) { + return n; + } + + return organization(); +} + +QString Addressee::assembledName() const +{ + const QString name = prefix() + QLatin1Char(' ') + + givenName() + QLatin1Char(' ') + + additionalName() + QLatin1Char(' ') + + familyName() + QLatin1Char(' ') + + suffix(); + + return name.simplified(); +} + +QString Addressee::fullEmail(const QString &email) const +{ + QString e; + if (email.isNull()) { + e = preferredEmail(); + } else { + e = email; + } + if (e.isEmpty()) { + return QString(); + } + + QString text; + if (realName().isEmpty()) { + text = e; + } else { + QRegExp needQuotes(QStringLiteral("[^ 0-9A-Za-z\\x0080-\\xFFFF]")); + if (realName().indexOf(needQuotes) != -1) { + QString name = realName(); + name.replace(QLatin1String("\""), QLatin1String("\\\"")); + text = QLatin1String("\"") + name + QLatin1String("\" <") + e + QLatin1Char('>'); + } else { + text = realName() + QLatin1String(" <") + e + QLatin1Char('>'); + } + } + + return text; +} +void Addressee::insertEmail(const QString &email, bool preferred, const QMap ¶m) +{ + if (email.simplified().isEmpty()) { + return; + } + + for (int i = 0; i < d->mEmails.size(); ++i) { + if (d->mEmails.at(i).mail() == email) { + if (!preferred || i == 0) { + return; + } + Email tempMail = d->mEmails.takeAt(i); + d->mEmails.prepend(tempMail); + return; + } + } + + Email mail(email); + mail.setParameters(param); + d->mEmpty = false; + if (preferred) { + d->mEmails.prepend(mail); + } else { + d->mEmails.append(mail); + } +} + +void Addressee::removeEmail(const QString &email) +{ + for (int i = 0; i < d->mEmails.size(); ++i) { + if (d->mEmails.at(i).mail() == email) { + d->mEmails.removeAt(i); + } + } +} + +QString Addressee::preferredEmail() const +{ + if (d->mEmails.count() == 0) { + return QString(); + } else { + return d->mEmails.first().mail(); + } +} + +QStringList Addressee::emails() const +{ + QStringList list; + const int numberOfEmail = d->mEmails.size(); + list.reserve(numberOfEmail); + for (int i = 0; i < numberOfEmail; ++i) { + list << d->mEmails.at(i).mail(); + } + + return list; +} + +Email::List Addressee::emailList() const +{ + return d->mEmails; +} + +void Addressee::setEmails(const QStringList &emails) +{ + d->mEmails.clear(); + const int numEmails = emails.size(); + d->mEmails.reserve(numEmails); + for (int i = 0; i < numEmails; ++i) { + d->mEmails.append(Email(emails.at(i))); + } + d->mEmpty = false; +} + +void Addressee::setEmailList(const Email::List &list) +{ + d->mEmails = list; + d->mEmpty = false; +} + +void Addressee::removeLang(const QString &language) +{ + for (int i = 0; i < d->mLangs.size(); ++i) { + if (d->mLangs.at(i).language() == language) { + d->mLangs.removeAt(i); + } + } +} + +void Addressee::setLangs(const Lang::List &langs) +{ + d->mLangs = langs; + d->mEmpty = false; +} + +void Addressee::insertLang(const Lang &language) +{ + const QString languageStr = language.language(); + if (languageStr.simplified().isEmpty()) { + return; + } + d->mEmpty = false; + + Lang::List::Iterator it; + Lang::List::Iterator end(d->mLangs.end()); + for (it = d->mLangs.begin(); it != end; ++it) { + if ((*it).language() == languageStr) { + (*it).setParameters(language.parameters()); + return; + } + } + d->mLangs.append(language); +} + +Lang::List Addressee::langs() const +{ + return d->mLangs; +} + +void Addressee::setGender(const Gender &gender) +{ + if (gender == d->mGender) { + return; + } + + d->mEmpty = false; + d->mGender = gender; +} + +Gender Addressee::gender() const +{ + return d->mGender; +} + +void Addressee::insertPhoneNumber(const PhoneNumber &phoneNumber) +{ + d->mEmpty = false; + + PhoneNumber::List::Iterator it; + for (it = d->mPhoneNumbers.begin(); it != d->mPhoneNumbers.end(); ++it) { + if ((*it).id() == phoneNumber.id()) { + *it = phoneNumber; + return; + } + } + if (!phoneNumber.number().simplified().isEmpty()) { + d->mPhoneNumbers.append(phoneNumber); + } +} + +void Addressee::removePhoneNumber(const PhoneNumber &phoneNumber) +{ + PhoneNumber::List::Iterator it; + for (it = d->mPhoneNumbers.begin(); it != d->mPhoneNumbers.end(); ++it) { + if ((*it).id() == phoneNumber.id()) { + d->mPhoneNumbers.erase(it); + return; + } + } +} + +PhoneNumber Addressee::phoneNumber(PhoneNumber::Type type) const +{ + PhoneNumber phoneNumber(QString(), type); + PhoneNumber::List::ConstIterator it; + for (it = d->mPhoneNumbers.constBegin(); it != d->mPhoneNumbers.constEnd(); ++it) { + if (matchBinaryPattern((*it).type(), type)) { + if ((*it).type() & PhoneNumber::Pref) { + return (*it); + } else if (phoneNumber.number().isEmpty()) { + phoneNumber = (*it); + } + } + } + + return phoneNumber; +} + +PhoneNumber::List Addressee::phoneNumbers() const +{ + return d->mPhoneNumbers; +} + +void Addressee::setPhoneNumbers(const PhoneNumber::List &phoneNumbers) +{ + d->mEmpty = false; + d->mPhoneNumbers.clear(); + d->mPhoneNumbers = phoneNumbers; +} + +PhoneNumber::List Addressee::phoneNumbers(PhoneNumber::Type type) const +{ + PhoneNumber::List list; + + PhoneNumber::List::ConstIterator it; + PhoneNumber::List::ConstIterator end(d->mPhoneNumbers.constEnd()); + for (it = d->mPhoneNumbers.constBegin(); it != end; ++it) { + if (matchBinaryPattern((*it).type(), type)) { + list.append(*it); + } + } + return list; +} + +PhoneNumber Addressee::findPhoneNumber(const QString &id) const +{ + PhoneNumber::List::ConstIterator it; + PhoneNumber::List::ConstIterator end(d->mPhoneNumbers.constEnd()); + for (it = d->mPhoneNumbers.constBegin(); it != end; ++it) { + if ((*it).id() == id) { + return *it; + } + } + return PhoneNumber(); +} + +void Addressee::insertKey(const Key &key) +{ + d->mEmpty = false; + + Key::List::Iterator it; + for (it = d->mKeys.begin(); it != d->mKeys.end(); ++it) { + if ((*it).id() == key.id()) { + *it = key; + return; + } + } + d->mKeys.append(key); +} + +void vectorRemoveAll(Key::List &t, const Key &key) +{ + t.removeAll(key); +} + +void Addressee::removeKey(const Key &key) +{ + Key::List::Iterator it; + for (it = d->mKeys.begin(); it != d->mKeys.end(); ++it) { + if ((*it).id() == key.id()) { + //Just use d->mKeys.removeAll(key) when depending on Qt 5.4 + vectorRemoveAll(d->mKeys, key); + return; + } + } +} + +Key Addressee::key(Key::Type type, const QString &customTypeString) const +{ + Key::List::ConstIterator it; + Key::List::ConstIterator end(d->mKeys.constEnd()); + for (it = d->mKeys.constBegin(); it != end; ++it) { + if ((*it).type() == type) { + if (type == Key::Custom) { + if (customTypeString.isEmpty()) { + return *it; + } else { + if ((*it).customTypeString() == customTypeString) { + return (*it); + } + } + } else { + return *it; + } + } + } + return Key(QString(), type); +} + +void Addressee::setKeys(const Key::List &list) +{ + d->mKeys = list; + d->mEmpty = false; +} + +Key::List Addressee::keys() const +{ + return d->mKeys; +} + +Key::List Addressee::keys(Key::Type type, const QString &customTypeString) const +{ + Key::List list; + + Key::List::ConstIterator it; + Key::List::ConstIterator end(d->mKeys.constEnd()); + for (it = d->mKeys.constBegin(); it != end; ++it) { + if ((*it).type() == type) { + if (type == Key::Custom) { + if (customTypeString.isEmpty()) { + list.append(*it); + } else { + if ((*it).customTypeString() == customTypeString) { + list.append(*it); + } + } + } else { + list.append(*it); + } + } + } + return list; +} + +Key Addressee::findKey(const QString &id) const +{ + Key::List::ConstIterator it; + Key::List::ConstIterator end(d->mKeys.constEnd()); + for (it = d->mKeys.constBegin(); it != end; ++it) { + if ((*it).id() == id) { + return *it; + } + } + return Key(); +} + +QString Addressee::toString() const +{ + QString str; + + str += QLatin1String("Addressee {\n"); + str += QStringLiteral(" Uid: %1\n").arg(uid()); + + str += QStringLiteral(" Name: %1\n").arg(name()); + str += QStringLiteral(" FormattedName: %1\n").arg(formattedName()); + str += QStringLiteral(" FamilyName: %1\n").arg(familyName()); + str += QStringLiteral(" GivenName: %1\n").arg(givenName()); + str += QStringLiteral(" AdditionalName: %1\n").arg(additionalName()); + str += QStringLiteral(" Prefix: %1\n").arg(prefix()); + str += QStringLiteral(" Suffix: %1\n").arg(suffix()); + str += QStringLiteral(" NickName: %1\n").arg(nickName()); + str += QStringLiteral(" Birthday: %1\n").arg(birthday().toString()); + str += QStringLiteral(" Mailer: %1\n").arg(mailer()); + str += QStringLiteral(" TimeZone: %1\n").arg(timeZone().toString()); + str += QStringLiteral(" Geo: %1\n").arg(geo().toString()); + str += QStringLiteral(" Title: %1\n").arg(title()); + str += QStringLiteral(" Role: %1\n").arg(role()); + str += QStringLiteral(" Organization: %1\n").arg(organization()); + str += QStringLiteral(" Department: %1\n").arg(department()); + str += QStringLiteral(" Note: %1\n").arg(note()); + str += QStringLiteral(" ProductId: %1\n").arg(productId()); + str += QStringLiteral(" Revision: %1\n").arg(revision().toString()); + str += QStringLiteral(" SortString: %1\n").arg(sortString()); + str += QStringLiteral(" Url: %1\n").arg(url().url().url()); + str += QStringLiteral(" Secrecy: %1\n").arg(secrecy().toString()); + str += QStringLiteral(" Logo: %1\n").arg(logo().toString()); + str += QStringLiteral(" Photo: %1\n").arg(photo().toString()); + str += QStringLiteral(" Sound: %1\n").arg(sound().toString()); + str += QStringLiteral(" Gender: %1\n").arg(gender().toString()); + str += QStringLiteral(" Kind: %1\n").arg(kind()); + + str += QLatin1String(" Emails {\n"); + const Email::List listEmail = d->mEmails; + Email::List::ConstIterator it5; + for (it5 = listEmail.begin(); it5 != listEmail.end(); ++it5) { + str += (*it5).toString(); + } + str += QLatin1String(" }\n"); + + str += QLatin1String(" Langs {\n"); + const Lang::List listLang = d->mLangs; + Lang::List::ConstIterator it6; + for (it6 = listLang.begin(); it6 != listLang.end(); ++it6) { + str += (*it6).toString(); + } + str += QLatin1String(" }\n"); + + str += QLatin1String(" PhoneNumbers {\n"); + const PhoneNumber::List p = phoneNumbers(); + PhoneNumber::List::ConstIterator it2; + for (it2 = p.begin(); it2 != p.end(); ++it2) { + str += (*it2).toString(); + } + str += QLatin1String(" }\n"); + + str += QLatin1String(" Addresses {\n"); + const Address::List a = addresses(); + Address::List::ConstIterator it3; + for (it3 = a.begin(); it3 != a.end(); ++it3) { + str += (*it3).toString(); + } + str += QLatin1String(" }\n"); + + str += QLatin1String(" Keys {\n"); + const Key::List k = keys(); + Key::List::ConstIterator it4; + for (it4 = k.begin(); it4 != k.end(); ++it4) { + str += (*it4).toString(); + } + str += QLatin1String(" }\n"); + + str += QLatin1String("}\n"); + + return str; +} + +void Addressee::insertAddress(const Address &address) +{ + if (address.isEmpty()) { + return; + } + + d->mEmpty = false; + + Address::List::Iterator it; + for (it = d->mAddresses.begin(); it != d->mAddresses.end(); ++it) { + if ((*it).id() == address.id()) { + *it = address; + return; + } + } + + d->mAddresses.append(address); +} + +void Addressee::removeAddress(const Address &address) +{ + Address::List::Iterator it; + for (it = d->mAddresses.begin(); it != d->mAddresses.end(); ++it) { + if ((*it).id() == address.id()) { + d->mAddresses.erase(it); + return; + } + } +} + +Address Addressee::address(Address::Type type) const +{ + Address address(type); + Address::List::ConstIterator it; + Address::List::ConstIterator end(d->mAddresses.constEnd()); + for (it = d->mAddresses.constBegin(); it != end; ++it) { + if (matchBinaryPattern((*it).type(), type)) { + if ((*it).type() & Address::Pref) { + return (*it); + } else if (address.isEmpty()) { + address = (*it); + } + } + } + + return address; +} + +Address::List Addressee::addresses() const +{ + return d->mAddresses; +} + +Address::List Addressee::addresses(Address::Type type) const +{ + Address::List list; + + Address::List::ConstIterator it; + Address::List::ConstIterator end(d->mAddresses.constEnd()); + for (it = d->mAddresses.constBegin(); it != end; ++it) { + if (matchBinaryPattern((*it).type(), type)) { + list.append(*it); + } + } + + return list; +} + +Address Addressee::findAddress(const QString &id) const +{ + Address::List::ConstIterator it; + Address::List::ConstIterator end(d->mAddresses.constEnd()); + for (it = d->mAddresses.constBegin(); it != end; ++it) { + if ((*it).id() == id) { + return *it; + } + } + return Address(); +} + +void Addressee::insertCategory(const QString &c) +{ + d->mEmpty = false; + + if (d->mCategories.contains(c)) { + return; + } + + d->mCategories.append(c); +} + +void Addressee::removeCategory(const QString &category) +{ + if (d->mCategories.contains(category)) { + d->mCategories.removeAll(category); + } +} + +bool Addressee::hasCategory(const QString &category) const +{ + return d->mCategories.contains(category); +} + +void Addressee::setCategories(const QStringList &c) +{ + d->mEmpty = false; + + d->mCategories = c; +} + +QStringList Addressee::categories() const +{ + return d->mCategories; +} + +void Addressee::insertMember(const QString &member) +{ + d->mEmpty = false; + + if (d->mMembers.contains(member)) { + return; + } + + d->mMembers.append(member); +} + +void Addressee::setMembers(const QStringList &m) +{ + d->mEmpty = false; + d->mMembers = m; +} + +QStringList Addressee::members() const +{ + return d->mMembers; +} + +void Addressee::insertRelationShip(const Related &relation) +{ + d->mEmpty = false; + + if (d->mRelationShips.contains(relation)) { + return; + } + + d->mRelationShips.append(relation); +} + +void Addressee::setRelationShips(const Related::List &c) +{ + d->mEmpty = false; + d->mRelationShips = c; +} + +Related::List Addressee::relationShips() const +{ + return d->mRelationShips; +} + +void Addressee::insertCustom(const QString &app, const QString &name, + const QString &value) +{ + if (value.isEmpty() || name.isEmpty() || app.isEmpty()) { + return; + } + + d->mEmpty = false; + + const QString qualifiedName = app + QLatin1Char('-') + name; + + d->mCustomFields.insert(qualifiedName, value); +} + +void Addressee::removeCustom(const QString &app, const QString &name) +{ + const QString qualifiedName = app + QLatin1Char('-') + name; + + d->mCustomFields.remove(qualifiedName); +} + +QString Addressee::custom(const QString &app, const QString &name) const +{ + const QString qualifiedName = app + QLatin1Char('-') + name; + + return d->mCustomFields.value(qualifiedName); +} + +void Addressee::setCustoms(const QStringList &customs) +{ + d->mEmpty = false; + + d->mCustomFields.clear(); + + foreach (const QString &custom, customs) { + const int index = custom.indexOf(QLatin1Char(':')); + if (index == -1) { + continue; + } + + const QString qualifiedName = custom.left(index); + const QString value = custom.mid(index + 1); + + d->mCustomFields.insert(qualifiedName, value); + } +} + +QStringList Addressee::customs() const +{ + QStringList result; + + QHashIterator it(d->mCustomFields); + result.reserve(d->mCustomFields.count()); + while (it.hasNext()) { + it.next(); + result << it.key() + QLatin1Char(':') + it.value(); + } + + return result; +} + +void Addressee::parseEmailAddress(const QString &rawEmail, QString &fullName, + QString &email) +{ + // This is a simplified version of KPIM::splitAddress(). + + fullName.clear(); + email.clear(); + if (rawEmail.isEmpty()) { + return; // KPIM::AddressEmpty; + } + + // The code works on 8-bit strings, so convert the input to UTF-8. + QByteArray address = rawEmail.toUtf8(); + + QByteArray displayName; + QByteArray addrSpec; + QByteArray comment; + + // The following is a primitive parser for a mailbox-list (cf. RFC 2822). + // The purpose is to extract a displayable string from the mailboxes. + // Comments in the addr-spec are not handled. No error checking is done. + + enum sourceLevel { + TopLevel, + InComment, + InAngleAddress + }; + sourceLevel context = TopLevel; + bool inQuotedString = false; + int commentLevel = 0; + bool stop = false; + + for (char *p = address.data(); *p && !stop; ++p) { + switch (context) { + case TopLevel : { + switch (*p) { + case '"': + inQuotedString = !inQuotedString; + displayName += *p; + break; + case '(': + if (!inQuotedString) { + context = InComment; + commentLevel = 1; + } else { + displayName += *p; + } + break; + case '<': + if (!inQuotedString) { + context = InAngleAddress; + } else { + displayName += *p; + } + break; + case '\\': // quoted character + displayName += *p; + ++p; // skip the '\' + if (*p) { + displayName += *p; + } else { + //return KPIM::UnexpectedEnd; + goto ABORT_PARSING; + } + break; + case ',': + if (!inQuotedString) { + //if ( allowMultipleAddresses ) + // stop = true; + //else + // return KPIM::UnexpectedComma; + goto ABORT_PARSING; + } else { + displayName += *p; + } + break; + default: + displayName += *p; + } + break; + } + case InComment: { + switch (*p) { + case '(': + ++commentLevel; + comment += *p; + break; + case ')': + --commentLevel; + if (commentLevel == 0) { + context = TopLevel; + comment += ' '; // separate the text of several comments + } else { + comment += *p; + } + break; + case '\\': // quoted character + comment += *p; + ++p; // skip the '\' + if (*p) { + comment += *p; + } else { + //return KPIM::UnexpectedEnd; + goto ABORT_PARSING; + } + break; + default: + comment += *p; + } + break; + } + case InAngleAddress: { + switch (*p) { + case '"': + inQuotedString = !inQuotedString; + addrSpec += *p; + break; + case '>': + if (!inQuotedString) { + context = TopLevel; + } else { + addrSpec += *p; + } + break; + case '\\': // quoted character + addrSpec += *p; + ++p; // skip the '\' + if (*p) { + addrSpec += *p; + } else { + //return KPIM::UnexpectedEnd; + goto ABORT_PARSING; + } + break; + default: + addrSpec += *p; + } + break; + } + } // switch ( context ) + } + +ABORT_PARSING: + displayName = displayName.trimmed(); + comment = comment.trimmed(); + addrSpec = addrSpec.trimmed(); + fullName = QString::fromUtf8(displayName); + email = QString::fromUtf8(addrSpec); // check for errors + if (inQuotedString) { + return; // KPIM::UnbalancedQuote; + } + if (context == InComment) { + return; // KPIM::UnbalancedParens; + } + if (context == InAngleAddress) { + return; // KPIM::UnclosedAngleAddr; + } + + if (addrSpec.isEmpty()) { + if (displayName.isEmpty()) { + return; // KPIM::NoAddressSpec; + } else { + //addrSpec = displayName; + //displayName.truncate( 0 ); + // Address of the form "foo@bar" or "foo@bar (Name)". + email = fullName; + fullName = QString::fromUtf8(comment); + } + } + + email = email.toLower(); + // Check that we do not have any extra characters on the end of the + // strings + unsigned int len = fullName.length(); + if (fullName[0] == QLatin1Char('"') && fullName[len - 1] == QLatin1Char('"')) { + fullName = fullName.mid(1, len - 2); + } +} + +void Addressee::setChanged(bool value) +{ + d->mChanged = value; +} + +bool Addressee::changed() const +{ + return d->mChanged; +} + +void Addressee::setSortMode(KContacts::SortMode *mode) +{ + Private::mSortMode = mode; +} + +bool Addressee::operator<(const Addressee &addr) const +{ + if (!Private::mSortMode) { + return false; + } else { + return Private::mSortMode->lesser(*this, addr); + } +} + +QString Addressee::mimeType() +{ + return QStringLiteral("text/directory"); +} + +QDataStream &KContacts::operator<<(QDataStream &s, const Addressee &a) +{ + s << a.d->mUid; + + s << a.d->mName; + s << a.d->mFormattedName; + s << a.d->mFamilyName; + s << a.d->mGivenName; + s << a.d->mAdditionalName; + s << a.d->mPrefix; + s << a.d->mSuffix; + s << a.d->mNickName; + s << a.d->mBirthday; + s << a.d->mMailer; + s << a.d->mTimeZone; + s << a.d->mGeo; + s << a.d->mTitle; + s << a.d->mRole; + s << a.d->mOrganization; + s << a.d->mDepartment; + s << a.d->mNote; + s << a.d->mProductId; + s << a.d->mRevision; + s << a.d->mSortString; + s << a.d->mSecrecy; + s << a.d->mLogo; + s << a.d->mPhoto; + s << a.d->mSound; + s << a.d->mPhoneNumbers; + s << a.d->mAddresses; + s << a.d->mEmails; + s << a.d->mCategories; + s << a.customs(); + s << a.d->mKeys; + s << a.d->mLangs; + s << a.d->mGender; + s << a.d->mKind; + s << a.d->mCalendarUrl; + s << a.d->mSoundListExtra; + s << a.d->mPhotoExtraList; + s << a.d->mLogoExtraList; + s << a.d->mUrlExtraList; + s << a.d->mMembers; + s << a.d->mRelationShips; + s << a.d->mSources; + s << a.d->mImpps; + + return s; +} + +QDataStream &KContacts::operator>>(QDataStream &s, Addressee &a) +{ + s >> a.d->mUid; + + s >> a.d->mName; + s >> a.d->mFormattedName; + s >> a.d->mFamilyName; + s >> a.d->mGivenName; + s >> a.d->mAdditionalName; + s >> a.d->mPrefix; + s >> a.d->mSuffix; + s >> a.d->mNickName; + s >> a.d->mBirthday; + s >> a.d->mMailer; + s >> a.d->mTimeZone; + s >> a.d->mGeo; + s >> a.d->mTitle; + s >> a.d->mRole; + s >> a.d->mOrganization; + s >> a.d->mDepartment; + s >> a.d->mNote; + s >> a.d->mProductId; + s >> a.d->mRevision; + s >> a.d->mSortString; + s >> a.d->mSecrecy; + s >> a.d->mLogo; + s >> a.d->mPhoto; + s >> a.d->mSound; + s >> a.d->mPhoneNumbers; + s >> a.d->mAddresses; + s >> a.d->mEmails; + s >> a.d->mCategories; + QStringList customFields; + s >> customFields; + a.setCustoms(customFields); + s >> a.d->mKeys; + s >> a.d->mLangs; + s >> a.d->mGender; + s >> a.d->mKind; + s >> a.d->mCalendarUrl; + s >> a.d->mSoundListExtra; + s >> a.d->mPhotoExtraList; + s >> a.d->mLogoExtraList; + s >> a.d->mUrlExtraList; + s >> a.d->mMembers; + s >> a.d->mRelationShips; + s >> a.d->mSources; + s >> a.d->mImpps; + a.d->mEmpty = false; + + return s; +} + +bool matchBinaryPattern(int value, int pattern) +{ + /** + We want to match all telephonnumbers/addresses which have the bits in the + pattern set. More are allowed. + if pattern == 0 we have a special handling, then we want only those with + exactly no bit set. + */ + if (pattern == 0) { + return (value == 0); + } else { + return (pattern == (pattern & value)); + } +} + +template +bool listEquals(const QVector &list, const QVector &pattern) +{ + if (list.count() != pattern.count()) { + return false; + } + const int numberOfElement(list.count()); + for (int i = 0; i < numberOfElement; ++i) { + if (!pattern.contains(list[i])) { + return false; + } + } + + return true; +} + +bool listEquals(const QStringList &list, const QStringList &pattern) +{ + if (list.count() != pattern.count()) { + return false; + } + + const int numberOfElement(list.count()); + for (int i = 0; i < numberOfElement; ++i) { + if (!pattern.contains(list[i])) { + return false; + } + } + + return true; +} diff --git a/src/addressee.h b/src/addressee.h new file mode 100644 index 0000000..6de9ed3 --- /dev/null +++ b/src/addressee.h @@ -0,0 +1,1053 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2001 Cornelius Schumacher + 2013 Tobias Koenig + + 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 KCONTACTS_ADDRESSEE_H +#define KCONTACTS_ADDRESSEE_H + +#include +#include +#include +#include +#include + +#include "address.h" +#include "geo.h" +#include "key.h" +#include "email.h" +#include "lang.h" +#include "gender.h" +#include "phonenumber.h" +#include "picture.h" +#include "secrecy.h" +#include "sound.h" +#include "impp.h" +#include "timezone.h" +#include "calendarurl.h" +#include "related.h" +#include "addresseelist.h" +#include "resourcelocatorurl.h" + +namespace KContacts +{ + +class SortMode; + +/** + @short address book entry + + This class represents an entry in the address book. + + The data of this class is implicitly shared. You can pass this class by value. + + If you need the name of a field for presenting it to the user you should use + the functions ending in Label(). They return a translated string which can be + used as label for the corresponding field. + + About the name fields: + + givenName() is the first name and familyName() the last name. In some + countries the family name comes first, that's the reason for the + naming. formattedName() is the full name with the correct formatting. + It is used as an override, when the correct formatting can't be generated + from the other name fields automatically. + + realName() returns a fully formatted name(). It uses formattedName, if set, + otherwise it constucts the name from the name fields. As fallback, if + nothing else is set it uses name(). + + name() is the NAME type of RFC2426. It can be used as internal name for the + data enty, but shouldn't be used for displaying the data to the user. + */ +class KCONTACTS_EXPORT Addressee +{ + friend KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &, const Addressee &); + friend KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &, Addressee &); + +public: + /** + A list of addressee objects + */ + typedef AddresseeList List; + /** + A map from unique identifier to addressee. + + @see uid() + */ + typedef QHash Map; + + /** + Construct an empty address book entry. + */ + Addressee(); + + /** + Destroys the address book entry. + */ + ~Addressee(); + + /** + Copy constructor. + */ + Addressee(const Addressee &other); + + /** + Assignment operator. + + @return a reference to @c this + */ + Addressee &operator=(const Addressee &other); + + /** + Equality operator. + + @return @c true if @c this and the given addressee are equal, + otherwise @c false + */ + bool operator==(const Addressee &other) const; + + /** + Not-equal operator. + + @return @c true if @c this and the given addressee are not equal, + otherwise @c false + */ + bool operator!=(const Addressee &other) const; + + /** + Return if the address book entry is empty. + */ + bool isEmpty() const; + + /** + Set unique identifier. + + @param uid the KABC unique identifier + */ + void setUid(const QString &uid); + + /** + Return unique identifier. + */ + QString uid() const; + + /** + Return translated label for uid field. + */ + static QString uidLabel(); + + /** + Set name. + */ + void setName(const QString &name); + + /** + Return name. + */ + QString name() const; + + /** + Return translated label for name field. + */ + static QString nameLabel(); + + /** + Set formatted name. + */ + void setFormattedName(const QString &formattedName); + + /** + Return formatted name. + */ + QString formattedName() const; + + /** + Return translated label for formattedName field. + */ + static QString formattedNameLabel(); + + /** + Set family name. + */ + void setFamilyName(const QString &familyName); + + /** + Return family name. + */ + QString familyName() const; + + /** + Return translated label for familyName field. + */ + static QString familyNameLabel(); + + /** + Set given name. + */ + void setGivenName(const QString &givenName); + + /** + Return given name. + */ + QString givenName() const; + + /** + Return translated label for givenName field. + */ + static QString givenNameLabel(); + + /** + Set additional names. + */ + void setAdditionalName(const QString &additionalName); + + /** + Return additional names. + */ + QString additionalName() const; + + /** + Return translated label for additionalName field. + */ + static QString additionalNameLabel(); + + /** + Set honorific prefixes. + */ + void setPrefix(const QString &prefix); + + /** + Return honorific prefixes. + */ + QString prefix() const; + + /** + Return translated label for prefix field. + */ + static QString prefixLabel(); + + /** + Set honorific suffixes. + */ + void setSuffix(const QString &suffix); + + /** + Return honorific suffixes. + */ + QString suffix() const; + + /** + Return translated label for suffix field. + */ + static QString suffixLabel(); + + /** + Set nick name. + */ + void setNickName(const QString &nickName); + + /** + Return nick name. + */ + QString nickName() const; + + /** + Return translated label for nickName field. + */ + static QString nickNameLabel(); + + /** + Set birthday. + */ + void setBirthday(const QDateTime &birthday); + + /** + Return birthday. + */ + QDateTime birthday() const; + + /** + Return translated label for birthday field. + */ + static QString birthdayLabel(); + + /** + Return translated label for homeAddressStreet field. + */ + static QString homeAddressStreetLabel(); + + /** + Return translated label for homeAddressPostOfficeBox field. + */ + static QString homeAddressPostOfficeBoxLabel(); + + /** + Return translated label for homeAddressLocality field. + */ + static QString homeAddressLocalityLabel(); + + /** + Return translated label for homeAddressRegion field. + */ + static QString homeAddressRegionLabel(); + + /** + Return translated label for homeAddressPostalCode field. + */ + static QString homeAddressPostalCodeLabel(); + + /** + Return translated label for homeAddressCountry field. + */ + static QString homeAddressCountryLabel(); + + /** + Return translated label for homeAddressLabel field. + */ + static QString homeAddressLabelLabel(); + + /** + Return translated label for businessAddressStreet field. + */ + static QString businessAddressStreetLabel(); + + /** + Return translated label for businessAddressPostOfficeBox field. + */ + static QString businessAddressPostOfficeBoxLabel(); + + /** + Return translated label for businessAddressLocality field. + */ + static QString businessAddressLocalityLabel(); + + /** + Return translated label for businessAddressRegion field. + */ + static QString businessAddressRegionLabel(); + + /** + Return translated label for businessAddressPostalCode field. + */ + static QString businessAddressPostalCodeLabel(); + + /** + Return translated label for businessAddressCountry field. + */ + static QString businessAddressCountryLabel(); + + /** + Return translated label for businessAddressLabel field. + */ + static QString businessAddressLabelLabel(); + + /** + Return translated label for homePhone field. + */ + static QString homePhoneLabel(); + + /** + Return translated label for businessPhone field. + */ + static QString businessPhoneLabel(); + + /** + Return translated label for mobilePhone field. + */ + static QString mobilePhoneLabel(); + + /** + Return translated label for homeFax field. + */ + static QString homeFaxLabel(); + + /** + Return translated label for businessFax field. + */ + static QString businessFaxLabel(); + + /** + Return translated label for carPhone field. + */ + static QString carPhoneLabel(); + + /** + Return translated label for isdn field. + */ + static QString isdnLabel(); + + /** + Return translated label for pager field. + */ + static QString pagerLabel(); + + /** + Return translated label for email field. + */ + static QString emailLabel(); + + /** + Set mail client. + */ + void setMailer(const QString &mailer); + + /** + Return mail client. + */ + QString mailer() const; + + /** + Return translated label for mailer field. + */ + static QString mailerLabel(); + + /** + Set time zone. + */ + void setTimeZone(const TimeZone &timeZone); + + /** + Return time zone. + */ + TimeZone timeZone() const; + + /** + Return translated label for timeZone field. + */ + static QString timeZoneLabel(); + + /** + Set geographic position. + */ + void setGeo(const Geo &geo); + + /** + Return geographic position. + */ + Geo geo() const; + + /** + Return translated label for geo field. + */ + static QString geoLabel(); + + /** + Set title. + */ + void setTitle(const QString &title); + + /** + Return title. + */ + QString title() const; + + /** + Return translated label for title field. + */ + static QString titleLabel(); + + /** + Set role. + */ + void setRole(const QString &role); + + /** + Return role. + */ + QString role() const; + + /** + Return translated label for role field. + */ + static QString roleLabel(); + + /** + Set organization. + */ + void setOrganization(const QString &organization); + + /** + Return organization. + */ + QString organization() const; + + /** + Return translated label for organization field. + */ + static QString organizationLabel(); + + /** + Set department. + */ + void setDepartment(const QString &department); + + /** + Return department. + */ + QString department() const; + + /** + Return translated label for department field. + */ + static QString departmentLabel(); + + /** + Set note. + */ + void setNote(const QString ¬e); + + /** + Return note. + */ + QString note() const; + + /** + Return translated label for note field. + */ + static QString noteLabel(); + + /** + Set product identifier. + */ + void setProductId(const QString &productId); + + /** + Return product identifier. + */ + QString productId() const; + + /** + Return translated label for productId field. + */ + static QString productIdLabel(); + + /** + Set revision date. + */ + void setRevision(const QDateTime &revision); + + /** + Return revision date. + */ + QDateTime revision() const; + + /** + Return translated label for revision field. + */ + static QString revisionLabel(); + + /** + Set sort string. + */ + void setSortString(const QString &sortString); + + /** + Return sort string. + */ + QString sortString() const; + + /** + Return translated label for sortString field. + */ + static QString sortStringLabel(); + + /** + Set homepage. + */ + void setUrl(const ResourceLocatorUrl &url); + void setUrl(const QUrl &url); + + /** + Return homepage. + */ + ResourceLocatorUrl url() const; + + /** + Return translated label for url field. + */ + static QString urlLabel(); + + /** + Set security class. + */ + void setSecrecy(const Secrecy &secrecy); + + /** + Return security class. + */ + Secrecy secrecy() const; + + /** + Return translated label for secrecy field. + */ + static QString secrecyLabel(); + + /** + Set logo. + */ + void setLogo(const Picture &logo); + + /** + Return logo. + */ + Picture logo() const; + + /** + Return translated label for logo field. + */ + static QString logoLabel(); + + /** + Set photo. + */ + void setPhoto(const Picture &photo); + + /** + Return photo. + */ + Picture photo() const; + + /** + Return translated label for photo field. + */ + static QString photoLabel(); + + /** + Set sound. + */ + void setSound(const Sound &sound); + + /** + Return sound. + */ + Sound sound() const; + + /** + Return translated label for sound field. + */ + static QString soundLabel(); + + /** + Set name fields by parsing the given string and trying to associate the + parts of the string with according fields. This function should probably + be a bit more clever. + */ + void setNameFromString(const QString &s); + + /** + Return the name of the addressee. This is calculated from all the name + fields. + */ + QString realName() const; + + /** + Return the name that consists of all name parts. + */ + QString assembledName() const; + + /** + Return email address including real name. + + @param email Email address to be used to construct the full email string. + If this is QString() the preferred email address is used. + */ + QString fullEmail(const QString &email = QString()) const; + + /** + Insert an email address. If the email address already exists in this + addressee it is not duplicated. + + @param email Email address + @param preferred Set to true, if this is the preferred email address of + the addressee. + */ + void insertEmail(const QString &email, bool preferred = false, const QMap ¶m = QMap()); + + /** + Remove email address. If the email address doesn't exist, nothing happens. + + @param email Email address to remove + */ + void removeEmail(const QString &email); + + /** + Return preferred email address. This is the first email address or the + last one added with insertEmail() with a set preferred parameter. + */ + QString preferredEmail() const; + + /** + Return list of all email addresses. + */ + QStringList emails() const; + + /** + Set the emails to @p list. + The first email address gets the preferred one! + @param list The list of email addresses. + */ + void setEmails(const QStringList &list); + + /** + Insert a phone number. If a phone number with the same id already exists + in this addressee it is not duplicated. + + @param phoneNumber The telephone number to insert to the addressee + */ + void insertPhoneNumber(const PhoneNumber &phoneNumber); + + /** + Remove phone number. If no phone number with the given id exists for this + addresse nothing happens. + + @param phoneNumber The telephone number to remove from the addressee + */ + void removePhoneNumber(const PhoneNumber &phoneNumber); + + /** + Return phone number, which matches the given type. + + @param type The type of phone number to get + */ + PhoneNumber phoneNumber(PhoneNumber::Type type) const; + + /** + Return list of all phone numbers. + */ + PhoneNumber::List phoneNumbers() const; + + void setPhoneNumbers(const PhoneNumber::List &phoneNumbers); + + /** + Return list of phone numbers with a special type. + + @param type The type of phone number to get + */ + PhoneNumber::List phoneNumbers(PhoneNumber::Type type) const; + + /** + Return phone number with the given id. + + @param id The identifier of the phone number to look for. + See PhoneNumber::id() + */ + PhoneNumber findPhoneNumber(const QString &id) const; + + /** + Insert a key. If a key with the same id already exists + in this addressee it is not duplicated. + + @param key The key to insert + */ + void insertKey(const Key &key); + + /** + Remove a key. If no key with the given id exists for this + addresse nothing happens. + + @param key The key to remove + */ + void removeKey(const Key &key); + + /** + Return key, which matches the given type. + If @p type == Key::Custom you can specify a string + that should match. If you leave the string empty, the first + key with a custom value is returned. + + @param type The type of key to look for + @param customTypeString A string to match custom keys against when + @p type is @c Key::Custom + */ + Key key(Key::Type type, const QString &customTypeString = QString()) const; + + /** + Return list of all keys. + */ + Key::List keys() const; + + /** + Set the list of keys + @param keys The keys to be set. + */ + void setKeys(const Key::List &keys); + + /** + Return list of keys with a special type. + If @p type == Key::Custom you can specify a string + that should match. If you leave the string empty, all custom + keys will be returned. + + @param type The type of key to look for + @param customTypeString A string to match custom keys against when + @p type is @c Key::Custom + */ + Key::List keys(Key::Type type, const QString &customTypeString = QString()) const; + + /** + Return key with the given id. + + @param id The identifier of the key to look for. See Key::id() + */ + Key findKey(const QString &id) const; + + /** + Insert an address. If an address with the same id already exists + in this addressee it is not duplicated. + + @param address The address to insert + */ + void insertAddress(const Address &address); + + /** + Remove address. If no address with the given id exists for this + addresse nothing happens. + + @param address The address to remove + */ + void removeAddress(const Address &address); + + /** + Return address, which matches the given type. + + @param type The type of address to look for + */ + Address address(Address::Type type) const; + + /** + Return list of all addresses. + */ + Address::List addresses() const; + + /** + Return list of addresses with a special type. + + @param type The type of addresses to look for + */ + Address::List addresses(Address::Type type) const; + + /** + Return address with the given id. + + @param id The identifier of the address to look for. See Address::id() + */ + Address findAddress(const QString &id) const; + + /** + Insert category. If the category already exists it is not duplicated. + */ + void insertCategory(const QString &category); + + /** + Remove category. + */ + void removeCategory(const QString &category); + + /** + Return, if addressee has the given category. + */ + bool hasCategory(const QString &category) const; + + /** + Set categories to given value. + */ + void setCategories(const QStringList &category); + + /** + Return list of all set categories. + */ + QStringList categories() const; + + /** + Insert custom entry. The entry is identified by the name of the inserting + application and a unique name. If an entry with the given app and name + already exists its value is replaced with the new given value. + + An empty value isn't allowed (nothing happens if this is called with + any of the three arguments being empty) + + @param app Name of the application inserting this custom entry + @param name Name of this application specific custom entry + @param value Value of this application specific custom entry + */ + void insertCustom(const QString &app, const QString &name, + const QString &value); + + /** + Remove custom entry. + + @param app Name of the application which has inserted this custom entry + @param name Name of this application specific custom entry + */ + void removeCustom(const QString &app, const QString &name); + + /** + Return value of custom entry, identified by app and entry name. + + @param app Name of the application which has inserted this custom entry + @param name Name of this application specific custom entry + */ + QString custom(const QString &app, const QString &name) const; + + /** + Set all custom entries. + */ + void setCustoms(const QStringList &customs); + + /** + Return list of all custom entries. + + The format of the custom entries is 'app-key:value' and the list is sorted + alphabetically by 'app-key'. + */ + QStringList customs() const; + + /** + Parse full email address. The result is given back in fullName and email. + + @param rawEmail The input string to parse for name and email + @param fullName The name part of the @p rawEmail input, if it contained one + @param email The email part of the @p rawEmail input, if it contained one + */ + static void parseEmailAddress(const QString &rawEmail, QString &fullName, + QString &email); + + /** + Returns string representation of the addressee. + */ + QString toString() const; + + /** + Mark addressee as changed. + + @param value Sets the status indicating changed data + */ + void setChanged(bool value); + + /** + Return whether the addressee is changed. + */ + bool changed() const; + + /** + Sets the sort mode implementation. + + Comparing to addressee objects is delegated to an instance + of a subclass of KContacts::SortMode. + + @param mode The sort mode implementator to use + */ + static void setSortMode(KContacts::SortMode *mode); + + /** + Return whether this addressee is "less-than" a given one + + @param addr The addressee object to compare with + + @see setSortMode() + */ + bool operator<(const Addressee &addr) const; + + /** + Returns the MIME type used for Addressees + */ + static QString mimeType(); + + KContacts::Email::List emailList() const; + void setEmailList(const Email::List &list); + + /** + * Remove Language + * @brief removeLang + * @param language + */ + void removeLang(const QString &language); + /** + * Insert Language + * @brief insertLang + * @param language + */ + void insertLang(const Lang &language); + /** + * @brief langs + * @return List of lang + */ + Lang::List langs() const; + void setLangs(const Lang::List &langs); + + void setGender(const Gender &gender); + Gender gender() const; + + QString kind() const; + void setKind(const QString &kind); + + void insertCalendarUrl(const CalendarUrl &calendarUrl); + CalendarUrl::List calendarUrlList() const; + + void insertExtraSound(const Sound &sound); + void setExtraSoundList(const Sound::List &soundList); + Sound::List extraSoundList() const; + + void insertExtraPhoto(const Picture &picture); + void setExtraPhotoList(const Picture::List &pictureList); + Picture::List extraPhotoList() const; + + void insertExtraLogo(const Picture &logo); + void setExtraLogoList(const Picture::List &logoList); + Picture::List extraLogoList() const; + + ResourceLocatorUrl::List extraUrlList() const; + void setExtraUrlList(const ResourceLocatorUrl::List &urlList); + void insertExtraUrl(const ResourceLocatorUrl &url); + + //Member + void insertMember(const QString &member); + void setMembers(const QStringList &c); + QStringList members() const; + + //Relation + void insertRelationShip(const Related &related); + void setRelationShips(const Related::List &c); + Related::List relationShips() const; + + //Source + void insertSourceUrl(const QUrl &url); + void setSourcesUrlList(const QVector &urlList); + QVector sourcesUrlList() const; + + //Impp + Impp::List imppList() const; + void setImppList(const Impp::List &imppList); + void insertImpp(const Impp &impp); + +private: + class Private; + QSharedDataPointer d; +}; + +KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &, const Addressee &); +KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &, Addressee &); + +} + +#define KCONTACTS_ADDRESSEE_METATYPE_DEFINED 1 +Q_DECLARE_METATYPE(KContacts::Addressee) + +#endif diff --git a/src/addresseehelper.cpp b/src/addresseehelper.cpp new file mode 100644 index 0000000..d695d08 --- /dev/null +++ b/src/addresseehelper.cpp @@ -0,0 +1,119 @@ +/* + This file is part of the KDE libraries + Copyright (C) 2003 Carsten Pfeiffer + + 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, version 2. + + 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 "addresseehelper.h" + +#include +#include +#include + +#include + +using namespace KContacts; + +class Q_DECL_HIDDEN KContacts::AddresseeHelperPrivate +{ +public: + QSet mTitles; + QSet mPrefixes; + QSet mSuffixes; + bool mTradeAsFamilyName; +}; + +Q_GLOBAL_STATIC(AddresseeHelper, s_self) + +// static +AddresseeHelper *AddresseeHelper::self() +{ + return s_self; +} + +AddresseeHelper::AddresseeHelper() + : QObject() + , d(new AddresseeHelperPrivate) +{ + initSettings(); +} + +AddresseeHelper::~AddresseeHelper() +{ +} + +static void addToSet(const QStringList &list, QSet &container) +{ + QStringList::ConstIterator it; + QStringList::ConstIterator end(list.end()); + for (it = list.begin(); it != end; ++it) { + if (!(*it).isEmpty()) { + container.insert(*it); + } + } +} + +void AddresseeHelper::initSettings() +{ + d->mTitles.clear(); + d->mSuffixes.clear(); + d->mPrefixes.clear(); + + d->mTitles.insert(i18n("Dr.")); + d->mTitles.insert(i18n("Miss")); + d->mTitles.insert(i18n("Mr.")); + d->mTitles.insert(i18n("Mrs.")); + d->mTitles.insert(i18n("Ms.")); + d->mTitles.insert(i18n("Prof.")); + + d->mSuffixes.insert(i18n("I")); + d->mSuffixes.insert(i18n("II")); + d->mSuffixes.insert(i18n("III")); + d->mSuffixes.insert(i18n("Jr.")); + d->mSuffixes.insert(i18n("Sr.")); + + d->mPrefixes.insert(QStringLiteral("van")); + d->mPrefixes.insert(QStringLiteral("von")); + d->mPrefixes.insert(QStringLiteral("de")); + + KConfig _config(QStringLiteral("kabcrc"), KConfig::NoGlobals); + KConfigGroup config(&_config, "General"); + + addToSet(config.readEntry("Prefixes", QStringList()), d->mTitles); + addToSet(config.readEntry("Inclusions", QStringList()), d->mPrefixes); + addToSet(config.readEntry("Suffixes", QStringList()), d->mSuffixes); + d->mTradeAsFamilyName = config.readEntry("TradeAsFamilyName", true); +} + +bool AddresseeHelper::containsTitle(const QString &title) const +{ + return d->mTitles.contains(title); +} + +bool AddresseeHelper::containsPrefix(const QString &prefix) const +{ + return d->mPrefixes.contains(prefix); +} + +bool AddresseeHelper::containsSuffix(const QString &suffix) const +{ + return d->mSuffixes.contains(suffix); +} + +bool AddresseeHelper::tradeAsFamilyName() const +{ + return d->mTradeAsFamilyName; +} diff --git a/src/addresseehelper.h b/src/addresseehelper.h new file mode 100644 index 0000000..3621045 --- /dev/null +++ b/src/addresseehelper.h @@ -0,0 +1,121 @@ +/* + This file is part of the KDE libraries + Copyright (C) 2003 Carsten Pfeiffer + + 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, version 2. + + 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 KCONTACTS_ADDRESSEEHELPER_H +#define KCONTACTS_ADDRESSEEHELPER_H + +#include "kcontacts_export.h" + +#include +#include +#include + +namespace KContacts +{ +class AddresseeHelperPrivate; + +/** + * This singleton class stores static data, which is shared + * by all Addressee objects. It maintains three lists of + * strings, which can be queried using this class: + * + * - a list of honoric prefixes, like "Mrs.", "Prof." etc, + * see containsTitle() + * - a list of inclusions, such as "van" or "de", see + * containsPrefix() + * - a list of honoric suffixes, such as "I" or "Jr.", see + * containsSuffix() + * + * All of these lists have a hardcoded and a configurable + * part. The configurable part is found in @c kabcrc, group + * @c General, fields @c Prefixes, @c Inclusions, and + * @c Suffixes. + * + * In addition to the above, this class stores one conveniece + * setting: it stores whether or not a single name component + * should be interpreted as a family name (see + * tradeAsFamilyName()). The corresponding configuration + * field is @c TradeAsFamilyName. + */ +class KCONTACTS_EXPORT AddresseeHelper : public QObject +{ + Q_OBJECT + +public: + /** + * Singleton interface to this class + * + * @return a pointer to the unique instance of this class. + */ + static AddresseeHelper *self(); + + /** + * Queries the list of honoric prefixes. + * + * @param title the honoric prefix to search for + * @return @c true, if @p title was found in the list, + * @c false otherwise + */ + bool containsTitle(const QString &title) const; + + /** + * Queries the list of inclusions. + * + * @param prefix the inclusion to search for + * @return @c true, if @p prefix was found in the list, + * @c false otherwise + */ + bool containsPrefix(const QString &prefix) const; + + /** + * Queries the list of honoric suffixes. + * + * @param suffix the honoric suffix to search for + * @return @c true, if @p suffix was found in the list, + * @c false otherwise + */ + bool containsSuffix(const QString &suffix) const; + + /** + * Returns whether or not a single name component should + * be interpreted as a family name. + * + * @return @c true if single name component is a family name, + * @c false otherwise. + */ + bool tradeAsFamilyName() const; + + /** @internal */ + AddresseeHelper(); + + ~AddresseeHelper(); + +public Q_SLOTS: + /** + * Recreates the static data and reparses the configuration. + */ + void initSettings(); + +private: + QScopedPointer d; +}; + +} + +#endif diff --git a/src/addresseelist.cpp b/src/addresseelist.cpp new file mode 100644 index 0000000..b62bc02 --- /dev/null +++ b/src/addresseelist.cpp @@ -0,0 +1,363 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2002 Jost Schenck + 2003 Tobias Koenig + + 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 "addresseelist.h" +#include "field.h" +#include "sortmode.h" +#include "kcontacts_debug.h" + +#include + +using namespace KContacts; + +// +// +// Traits +// +// + +SortingTraits::Uid::Uid() + : d(Q_NULLPTR) +{ +} + +SortingTraits::Uid::~Uid() +{ +} + +bool SortingTraits::Uid::eq(const Addressee &a1, const Addressee &a2) +{ + // locale awareness doesn't make sense sorting ids + return QString::compare(a1.uid(), a2.uid()) == 0; +} + +bool SortingTraits::Uid::lt(const Addressee &a1, const Addressee &a2) +{ + // locale awareness doesn't make sense sorting ids + return QString::compare(a1.uid(), a2.uid()) < 0; +} + +SortingTraits::Name::Name() + : d(Q_NULLPTR) +{ +} + +SortingTraits::Name::~Name() +{ +} + +bool SortingTraits::Name::eq(const Addressee &a1, const Addressee &a2) +{ + return QString::localeAwareCompare(a1.name(), a2.name()) == 0; +} + +bool SortingTraits::Name::lt(const Addressee &a1, const Addressee &a2) +{ + return QString::localeAwareCompare(a1.name(), a2.name()) < 0; +} + +SortingTraits::FormattedName::FormattedName() + : d(Q_NULLPTR) +{ +} + +SortingTraits::FormattedName::~FormattedName() +{ +} + +bool SortingTraits::FormattedName::eq(const Addressee &a1, const Addressee &a2) +{ + return QString::localeAwareCompare(a1.formattedName(), a2.formattedName()) == 0; +} + +bool SortingTraits::FormattedName::lt(const Addressee &a1, const Addressee &a2) +{ + return QString::localeAwareCompare(a1.formattedName(), a2.formattedName()) < 0; +} + +SortingTraits::FamilyName::FamilyName() + : d(Q_NULLPTR) +{ +} + +SortingTraits::FamilyName::~FamilyName() +{ +} + +bool SortingTraits::FamilyName::eq(const Addressee &a1, const Addressee &a2) +{ + return + QString::localeAwareCompare(a1.familyName(), a2.familyName()) == 0 && + QString::localeAwareCompare(a1.givenName(), a2.givenName()) == 0; +} + +bool SortingTraits::FamilyName::lt(const Addressee &a1, const Addressee &a2) +{ + int family = QString::localeAwareCompare(a1.familyName(), a2.familyName()); + if (0 == family) { + return QString::localeAwareCompare(a1.givenName(), a2.givenName()) < 0; + } else { + return family < 0; + } +} + +SortingTraits::GivenName::GivenName() + : d(Q_NULLPTR) +{ +} + +SortingTraits::GivenName::~GivenName() +{ +} + +bool SortingTraits::GivenName::eq(const Addressee &a1, const Addressee &a2) +{ + return + QString::localeAwareCompare(a1.givenName(), a2.givenName()) == 0 && + QString::localeAwareCompare(a1.familyName(), a2.familyName()) == 0; +} + +bool SortingTraits::GivenName::lt(const Addressee &a1, const Addressee &a2) +{ + int given = QString::localeAwareCompare(a1.givenName(), a2.givenName()); + if (0 == given) { + return QString::localeAwareCompare(a1.familyName(), a2.familyName()) < 0; + } else { + return given < 0; + } +} + +// +// +// AddresseeList +// +// + +static Field *sActiveField = Q_NULLPTR; + +class Q_DECL_HIDDEN AddresseeList::Private : public QSharedData +{ +public: + Private() + : mReverseSorting(false) + , mActiveSortingCriterion(FormattedName) + { + } + + Private(const Private &other) + : QSharedData(other) + { + mReverseSorting = other.mReverseSorting; + mActiveSortingCriterion = other.mActiveSortingCriterion; + } + + bool mReverseSorting; + SortingCriterion mActiveSortingCriterion; +}; + +AddresseeList::AddresseeList() + : QVector() + , d(new Private) +{ +} + +AddresseeList::~AddresseeList() +{ +} + +AddresseeList::AddresseeList(const AddresseeList &other) + : QVector(other) + , d(other.d) +{ +} + +AddresseeList::AddresseeList(const QVector &list) + : QVector(list) + , d(new Private) +{ +} + +AddresseeList &AddresseeList::operator=(const AddresseeList &other) +{ + if (this != &other) { + QVector::operator=(other); + d = other.d; + } + + return *this; +} + +QString AddresseeList::toString() const +{ + QString str; + + str += QLatin1String("AddresseeList {\n"); + str += QStringLiteral(" Reverse Order: %1\n").arg(d->mReverseSorting ? + QStringLiteral("true") : + QStringLiteral("false")); + + QString crit; + switch (d->mActiveSortingCriterion) { + case Uid: + crit = QStringLiteral("Uid"); + break; + case Name: + crit = QStringLiteral("Name"); + break; + case FormattedName: + crit = QStringLiteral("FormattedName"); + break; + case FamilyName: + crit = QStringLiteral("FamilyName"); + break; + case GivenName: + crit = QStringLiteral("GivenName"); + break; + default: + crit = QStringLiteral("unknown -- update dump method"); + break; + } + + str += QStringLiteral(" Sorting criterion: %1\n").arg(crit); +#if 0 //code commented in loop => comment it too + for (const_iterator it = begin(); it != end(); ++it) { +// str += (*it).toString(); + } +#endif + + str += QLatin1String("}\n"); + + return str; +} + +void AddresseeList::setReverseSorting(bool reverseSorting) +{ + d->mReverseSorting = reverseSorting; +} + +bool AddresseeList::reverseSorting() const +{ + return d->mReverseSorting; +} + +void AddresseeList::sortBy(SortingCriterion c) +{ + d->mActiveSortingCriterion = c; + if (Uid == c) { + sortByTrait(); + } else if (Name == c) { + sortByTrait(); + } else if (FormattedName == c) { + sortByTrait(); + } else if (FamilyName == c) { + sortByTrait(); + } else if (GivenName == c) { + sortByTrait(); + } else { + qCCritical(KCONTACTS_LOG) << "AddresseeList sorting criterion passed for which a trait is not known." + << "No sorting done."; + } +} + +void AddresseeList::sort() +{ + sortBy(d->mActiveSortingCriterion); +} + +template +void AddresseeList::sortByTrait() +{ + // FIXME: better sorting algorithm, bubblesort is not acceptable for larger lists. + // + // for i := 1 to n - 1 + // do for j := 1 to n - i + // do if A[j] > A[j+1] + // then temp := A[j] + // A[j] := A[j + 1] + // A[j + 1 ] := temp + + iterator i1 = begin(); + iterator endIt = end(); + --endIt; + if (i1 == endIt) { // don't need sorting + return; + } + + iterator i2 = endIt; + while (i1 != endIt) { + iterator j1 = begin(); + iterator j2 = j1; + ++j2; + while (j1 != i2) { + if ((!d->mReverseSorting && Trait::lt(*j2, *j1)) || + (d->mReverseSorting && Trait::lt(*j1, *j2))) { + qSwap(*j1, *j2); + } + ++j1; + ++j2; + } + ++i1; + --i2; + } +} + +void AddresseeList::sortByField(Field *field) +{ + if (!field) { + qCWarning(KCONTACTS_LOG) << "sortByField called with no active sort field"; + return; + } + + sActiveField = field; + + if (count() == 0) { + return; + } + + KContacts::FieldSortMode *mode = new KContacts::FieldSortMode(sActiveField, !d->mReverseSorting); + + KContacts::Addressee::setSortMode(mode); + qSort(*this); + KContacts::Addressee::setSortMode(Q_NULLPTR); + + delete mode; +} + +void AddresseeList::sortByMode(SortMode *mode) +{ + if (count() == 0) { + return; + } + + KContacts::Addressee::setSortMode(mode); + qSort(*this); + KContacts::Addressee::setSortMode(Q_NULLPTR); +} + +SortingCriterion AddresseeList::sortingCriterion() const +{ + return d->mActiveSortingCriterion; +} + +Field *AddresseeList::sortingField() const +{ + return sActiveField; +} diff --git a/src/addresseelist.h b/src/addresseelist.h new file mode 100644 index 0000000..acd7776 --- /dev/null +++ b/src/addresseelist.h @@ -0,0 +1,426 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2002 Jost Schenck + 2003 Tobias Koenig + + 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 KCONTACTS_ADDRESSEELIST_H +#define KCONTACTS_ADDRESSEELIST_H + +#include "kcontacts_export.h" +#include +#include + +namespace KContacts +{ + +class Field; +class SortMode; +class Addressee; + +/** + * Each trait must implement one static function for equality, one for "less + * than". Class name should be the field name. A trait does not necessarily + * have to stick to just one field: a trait sorting by family name can e.g. + * sort addressees with equal family name by given name. + * + * If you want to implement reverse sorting, you do not have to write another + * trait, as AddresseeList takes care of that. + */ +namespace SortingTraits +{ + +class KCONTACTS_EXPORT Uid +{ +public: + /** + * Creates an instance. + */ + Uid(); + + /** + * Destroys the instance. + */ + ~Uid(); + + /** + * "Equal" compare method + * + * @return @c true if the first parameter is equal to the second + * when comparing the uid attribute. + * + * @see Addressee::uid() + * @see QString::compare() + */ + static bool eq(const Addressee &a1, const Addressee &a2); + + /** + * "Less-Than" compare method + * + * @return @c true if the first parameter is "less-than" the second + * when comparing the uid attribute. + * + * @see Addressee::uid() + * @see QString::compare() + */ + static bool lt(const Addressee &a1, const Addressee &a2); + +private: + Q_DISABLE_COPY(Uid) + class Private; + Private *const d; +}; + +class KCONTACTS_EXPORT Name +{ +public: + /** + * Creates an instance. + */ + Name(); + + /** + * Destroys the instance. + */ + ~Name(); + + /** + * "Equal" compare method + * + * @return @c true if the first parameter is equal to the second + * when comparing the name attribute. + * + * @see Addressee::name() + * @see QString::localeAwareCompare() + */ + static bool eq(const Addressee &a1, const Addressee &a2); + + /** + * "Less-Than" compare method + * + * @return @c true if the first parameter is "less-than" the second + * when comparing the name attribute. + * + * @see Addressee::name() + * @see QString::localeAwareCompare() + */ + static bool lt(const Addressee &a1, const Addressee &a2); + +private: + Q_DISABLE_COPY(Name) + class Private; + Private *const d; +}; + +class KCONTACTS_EXPORT FormattedName +{ +public: + /** + * Creates an instance. + */ + FormattedName(); + + /** + * Destroys the instance. + */ + ~FormattedName(); + + /** + * "Equal" compare method + * + * @return @c true if the first parameter is equal to the second + * when comparing the formatted name attribute. + * + * @see Addressee::formattedName() + * @see QString::localeAwareCompare() + */ + static bool eq(const Addressee &a1, const Addressee &a2); + + /** + * "Less-Than" compare method + * + * @return @c true if the first parameter is "less-than" the second + * when comparing the formatted name attribute. + * + * @see Addressee::formattedName() + * @see QString::localeAwareCompare() + */ + static bool lt(const Addressee &a1, const Addressee &a2); + +private: + Q_DISABLE_COPY(FormattedName) + class Private; + Private *const d; +}; + +class KCONTACTS_EXPORT FamilyName // fallback to given name +{ +public: + /** + * Creates an instance. + */ + FamilyName(); + + /** + * Destroys the instance. + */ + ~FamilyName(); + + /** + * "Equal" compare method + * + * @return @c true if the first parameter is equal to the second + * when comparing the family name and given name attributes. + * + * @see Addressee::familyName() + * @see Addressee::givenName() + * @see QString::localeAwareCompare() + */ + static bool eq(const Addressee &a1, const Addressee &a2); + + /** + * "Less-Than" compare method + * + * Falls back to comparing given name if equal + * + * @return @c true if the first parameter is "less-than" the second + * when comparing the family name attribute. + * + * @see Addressee::familyName() + * @see QString::localeAwareCompare() + */ + static bool lt(const Addressee &a1, const Addressee &a2); + +private: + Q_DISABLE_COPY(FamilyName) + class Private; + Private *const d; +}; + +class KCONTACTS_EXPORT GivenName // fallback to family name +{ +public: + /** + * Creates an instance. + */ + GivenName(); + + /** + * Destroys the instance. + */ + ~GivenName(); + + /** + * "Equal" compare method + * + * @return @c true if the first parameter is equal to the second + * when comparing the given name and family name attributes. + * + * @see Addressee::givenName() + * @see Addressee::familyName() + * @see QString::localeAwareCompare() + */ + static bool eq(const Addressee &a1, const Addressee &a2); + + /** + * "Less-Than" compare method + * + * Falls back to comparing family name if equal + * + * @return @c true if the first parameter is "less-than" the second + * when comparing the given name attribute. + * + * @see Addressee::givenName() + * @see QString::localeAwareCompare() + */ + static bool lt(const Addressee &a1, const Addressee &a2); + +private: + Q_DISABLE_COPY(GivenName) + class Private; + Private *const d; +}; + +} + +/** + * Addressee attribute used for sorting. + */ +typedef enum { + Uid, + Name, + FormattedName, + FamilyName, + GivenName +} SortingCriterion; + +/** + * @short a QValueList of Addressee, with sorting functionality + * + * This class extends the functionality of QValueList with + * sorting methods specific to the Addressee class. It can be used + * just like any other QValueList but is no template class. + * + * An AddresseeList does not automatically keep sorted when addressees + * are added or removed or the sorting order is changed, as this would + * slow down larger operations by sorting after every step. So after + * such operations you have to call {@link #sort} or {@link #sortBy} to + * create a defined order again. + * + * Iterator usage is inherited from QVector and extensively documented + * there. Please remember that the state of an iterator is undefined + * after any sorting operation. + * + * For the enumeration Type SortingCriterion, which specifies the + * field by the collection will be sorted, the following values exist: + * Uid, Name, FormattedName, FamilyName, GivenName. + * + * @author Jost Schenck jost@schenck.de + */ +class KCONTACTS_EXPORT AddresseeList : public QVector +{ +public: + /** + * Creates a new addressee list. + */ + AddresseeList(); + + /** + * Creates a new addressee list. + */ + AddresseeList(const AddresseeList &other); + + /** + * Creates a new addressee list. + */ + AddresseeList(const QVector &list); + + /** + * Destroys the addressee list. + */ + ~AddresseeList(); + + /** + * Assignment operator. + * + * @param other the list to assign from + * @return a reference to @c this + */ + AddresseeList &operator=(const AddresseeList &other); + + /** + * Determines the direction of sorting. On change, the list + * will not automatically be resorted. + * @param reverseSorting true if sorting should be done reverse, + * false otherwise + */ + void setReverseSorting(bool reverseSorting = true); + + /** + * Returns the direction of sorting. + * @return true if sorting is done reverse, false otherwise + */ + bool reverseSorting() const; + + /** + * Sorts this list by a specific criterion. + * @param c the criterion by which should be sorted + */ + void sortBy(SortingCriterion c); + + /** + * Sorts this list by a specific field. If no parameter is given, the + * last used Field object will be used. + * @param field pointer to the Field object to be sorted by + */ + void sortByField(Field *field = Q_NULLPTR); + + /** + * Sorts this list by a specific sorting mode. + * @param mode pointer to the sorting mode object to be sorted by + */ + void sortByMode(SortMode *mode = Q_NULLPTR); + + /** + * Sorts this list by its active sorting criterion. This normally is the + * criterion of the last sortBy operation or FormattedName if up + * to now there has been no sortBy operation. + * + * Please note that the sorting trait of the last {@link #sortByTrait} + * method call is not remembered and thus the action can not be repeated + * by this method. + */ + void sort(); + + /** + * Templated sort function. You normally will not want to use this but + * {@link #sortBy} and {@link #sort} instead as the existing sorting + * criteria completely suffice for most cases. + * + * However, if you do want to use some special sorting criterion, you can + * write a trait class that will be provided to this templated method. + * This trait class has to have a class declaration like the following: + * \code + * class MySortingTrait { + * public: + * // eq returns true if a1 and a2 are equal + * static bool eq(KContacts::Addressee a1, KContacts::Addressee a2); + * // lt returns true is a1 is "less than" a2 + * static bool lt(KContacts::Addressee a1, KContacts::Addressee a2); + * }; + * \endcode + * You can then pass this class to the sortByTrait method like this: + * \code + * myAddresseelist.sortByTrait<MySortingTrait>(); + * \endcode + * Please note that the {@link #sort} method can not be used to repeat the + * sorting of the last sortByTrait action. + * + * Right now this method uses the bubble sort algorithm. This should be + * replaced for a better one when I have time. + */ + template void sortByTrait(); + + /** + * Returns the active sorting criterion, ie the sorting criterion that + * will be used by a {@link #sort} call. + */ + SortingCriterion sortingCriterion() const; + + /** + * Returns the active sorting field, ie a pointer to the Field object + * which was used for the last {@link #sortByField} operation. + * This function returns the last GLOBAL sorting field, not + * the class specific one. + * You're a lot better off by keeping track of this locally. + */ + Field *sortingField() const; + + /** + * Returns a string representation of the addressee list. + */ + QString toString() const; + +private: + class Private; + QSharedDataPointer d; +}; + +} + +#endif diff --git a/src/calendarurl.cpp b/src/calendarurl.cpp new file mode 100644 index 0000000..ba6938d --- /dev/null +++ b/src/calendarurl.cpp @@ -0,0 +1,179 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2015 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 "calendarurl.h" + +#include +#include +#include +#include + +using namespace KContacts; + +class Q_DECL_HIDDEN CalendarUrl::Private : public QSharedData +{ +public: + Private() + { + } + + Private(const Private &other) + : QSharedData(other) + { + parameters = other.parameters; + type = other.type; + url = other.url; + } + static QString typeToString(CalendarUrl::CalendarType type); + QMap parameters; + QUrl url; + CalendarUrl::CalendarType type; + +}; + +QString CalendarUrl::Private::typeToString(CalendarUrl::CalendarType type) +{ + QString ret; + switch (type) { + case Unknown: + case EndCalendarType: + ret = QStringLiteral("Unknown"); + break; + case FBUrl: + ret = QStringLiteral("FreeBusy"); + break; + case CALUri: + ret = QStringLiteral("CalUri"); + break; + case CALADRUri: + ret = QStringLiteral("Caladruri"); + break; + } + return ret; +} + +CalendarUrl::CalendarUrl() + : d(new Private) +{ + d->type = Unknown; +} + +CalendarUrl::CalendarUrl(CalendarUrl::CalendarType type) + : d(new Private) +{ + d->type = type; +} + +CalendarUrl::CalendarUrl(const CalendarUrl &other) + : d(other.d) +{ +} + +CalendarUrl::~CalendarUrl() +{ + +} + +QMap CalendarUrl::parameters() const +{ + return d->parameters; +} + +bool CalendarUrl::operator==(const CalendarUrl &other) const +{ + return (d->parameters == other.parameters()) && (d->type == other.type()) && (d->url == other.url()); +} + +bool CalendarUrl::operator!=(const CalendarUrl &other) const +{ + return !(other == *this); +} + +CalendarUrl &CalendarUrl::operator=(const CalendarUrl &other) +{ + if (this != &other) { + d = other.d; + } + + return *this; +} + +QString CalendarUrl::toString() const +{ + QString str; + str += QLatin1String("CalendarUrl {\n"); + str += QStringLiteral(" url: %1\n").arg(d->url.toString()); + str += QStringLiteral(" type: %1\n").arg(CalendarUrl::Private::typeToString(d->type)); + if (!d->parameters.isEmpty()) { + QMapIterator i(d->parameters); + QString param; + while (i.hasNext()) { + i.next(); + param += QStringLiteral("%1 %2").arg(i.key(), i.value().join(QStringLiteral(","))); + } + str += QStringLiteral(" parameters: %1\n").arg(param); + } + str += QLatin1String("}\n"); + return str; +} + +void CalendarUrl::setParameters(const QMap ¶ms) +{ + d->parameters = params; +} + +bool CalendarUrl::isValid() const +{ + return (d->type != Unknown) && (d->url.isValid()); +} + +void CalendarUrl::setType(CalendarUrl::CalendarType type) +{ + d->type = type; +} + +CalendarUrl::CalendarType CalendarUrl::type() const +{ + return d->type; +} + +void CalendarUrl::setUrl(const QUrl &url) +{ + d->url = url; +} + +QUrl CalendarUrl::url() const +{ + return d->url; +} + +QDataStream &KContacts::operator<<(QDataStream &s, const CalendarUrl &calUrl) +{ + return s << calUrl.d->parameters << (uint)calUrl.d->type << calUrl.d->url; +} + +QDataStream &KContacts::operator>>(QDataStream &s, CalendarUrl &calUrl) +{ + uint type; + s >> calUrl.d->parameters >> type >> calUrl.d->url; + calUrl.d->type = static_cast(type); + return s; +} + diff --git a/src/calendarurl.h b/src/calendarurl.h new file mode 100644 index 0000000..45e4698 --- /dev/null +++ b/src/calendarurl.h @@ -0,0 +1,85 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2015 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 CALENDARURL_H +#define CALENDARURL_H +#include "kcontacts_export.h" + +#include +#include +#include +class QUrl; +/** @short Class that holds a Calendar Url (FBURL/CALADRURI/CALURI) + * @since 4.14.6 + */ + +namespace KContacts +{ + +class KCONTACTS_EXPORT CalendarUrl +{ + friend KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &, const CalendarUrl &); + friend KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &, CalendarUrl &); +public: + enum CalendarType { + Unknown = 0, + FBUrl, + CALUri, + CALADRUri, + EndCalendarType + }; + + CalendarUrl(); + CalendarUrl(CalendarUrl::CalendarType type); + CalendarUrl(const CalendarUrl &other); + + ~CalendarUrl(); + + typedef QVector List; + + bool isValid() const; + + void setType(CalendarUrl::CalendarType type); + CalendarUrl::CalendarType type() const; + + void setUrl(const QUrl &url); + QUrl url() const; + + void setParameters(const QMap ¶ms); + QMap parameters() const; + + bool operator==(const CalendarUrl &other) const; + bool operator!=(const CalendarUrl &other) const; + + CalendarUrl &operator=(const CalendarUrl &other); + + QString toString() const; +private: + class Private; + QSharedDataPointer d; +}; + +KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &stream, const CalendarUrl &object); + +KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &stream, CalendarUrl &object); + +} +Q_DECLARE_TYPEINFO(KContacts::CalendarUrl, Q_MOVABLE_TYPE); +#endif // CALENDARURL_H diff --git a/src/contactgroup.cpp b/src/contactgroup.cpp new file mode 100644 index 0000000..eed4e97 --- /dev/null +++ b/src/contactgroup.cpp @@ -0,0 +1,507 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2008 Tobias Koenig + + 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 "contactgroup.h" + +#include +#include +#include +#include + +using namespace KContacts; + +class Q_DECL_HIDDEN ContactGroup::ContactReference::ContactReferencePrivate : public QSharedData +{ +public: + ContactReferencePrivate() + : QSharedData() + { + } + + ContactReferencePrivate(const ContactReferencePrivate &other) + : QSharedData(other) + { + mUid = other.mUid; + mPreferredEmail = other.mPreferredEmail; + mCustoms = other.mCustoms; + } + + QString mUid; + QString mGid; + QString mPreferredEmail; + QMap mCustoms; +}; + +ContactGroup::ContactReference::ContactReference() + : d(new ContactReferencePrivate) +{ +} + +ContactGroup::ContactReference::ContactReference(const ContactReference &other) + : d(other.d) +{ +} + +ContactGroup::ContactReference::ContactReference(const QString &uid) + : d(new ContactReferencePrivate) +{ + d->mUid = uid; +} + +ContactGroup::ContactReference::~ContactReference() +{ +} + +void ContactGroup::ContactReference::setUid(const QString &uid) +{ + d->mUid = uid; +} + +QString ContactGroup::ContactReference::uid() const +{ + return d->mUid; +} + +void ContactGroup::ContactReference::setGid(const QString &gid) +{ + d->mGid = gid; +} + +QString ContactGroup::ContactReference::gid() const +{ + return d->mGid; +} + +void ContactGroup::ContactReference::setPreferredEmail(const QString &email) +{ + d->mPreferredEmail = email; +} + +QString ContactGroup::ContactReference::preferredEmail() const +{ + return d->mPreferredEmail; +} + +void ContactGroup::ContactReference::insertCustom(const QString &key, const QString &value) +{ + d->mCustoms.insert(key, value); +} + +void ContactGroup::ContactReference::removeCustom(const QString &key) +{ + d->mCustoms.remove(key); +} + +QString ContactGroup::ContactReference::custom(const QString &key) const +{ + return d->mCustoms.value(key); +} + +ContactGroup::ContactReference &ContactGroup::ContactReference::operator=( + const ContactGroup::ContactReference &other) +{ + if (this != &other) { + d = other.d; + } + + return *this; +} + +bool ContactGroup::ContactReference::operator==(const ContactReference &other) const +{ + return d->mUid == other.d->mUid && + d->mPreferredEmail == other.d->mPreferredEmail && + d->mCustoms == other.d->mCustoms; +} + +class Q_DECL_HIDDEN ContactGroup::ContactGroupReference::ContactGroupReferencePrivate : public QSharedData +{ +public: + ContactGroupReferencePrivate() + : QSharedData() + { + } + + ContactGroupReferencePrivate(const ContactGroupReferencePrivate &other) + : QSharedData(other) + { + mUid = other.mUid; + mCustoms = other.mCustoms; + } + + QString mUid; + QMap mCustoms; +}; + +ContactGroup::ContactGroupReference::ContactGroupReference() + : d(new ContactGroupReferencePrivate) +{ +} + +ContactGroup::ContactGroupReference::ContactGroupReference(const ContactGroupReference &other) + : d(other.d) +{ +} + +ContactGroup::ContactGroupReference::ContactGroupReference(const QString &uid) + : d(new ContactGroupReferencePrivate) +{ + d->mUid = uid; +} + +ContactGroup::ContactGroupReference::~ContactGroupReference() +{ +} + +void ContactGroup::ContactGroupReference::setUid(const QString &uid) +{ + d->mUid = uid; +} + +QString ContactGroup::ContactGroupReference::uid() const +{ + return d->mUid; +} + +void ContactGroup::ContactGroupReference::insertCustom(const QString &key, const QString &value) +{ + d->mCustoms.insert(key, value); +} + +void ContactGroup::ContactGroupReference::removeCustom(const QString &key) +{ + d->mCustoms.remove(key); +} + +QString ContactGroup::ContactGroupReference::custom(const QString &key) const +{ + return d->mCustoms.value(key); +} + +ContactGroup::ContactGroupReference &ContactGroup::ContactGroupReference::operator=( + const ContactGroup::ContactGroupReference &other) +{ + if (this != &other) { + d = other.d; + } + + return *this; +} + +bool ContactGroup::ContactGroupReference::operator==(const ContactGroupReference &other) const +{ + return d->mUid == other.d->mUid && + d->mCustoms == other.d->mCustoms; +} + +class Q_DECL_HIDDEN ContactGroup::Data::DataPrivate : public QSharedData +{ +public: + DataPrivate() + : QSharedData() + { + } + + DataPrivate(const DataPrivate &other) + : QSharedData(other) + { + mName = other.mName; + mEmail = other.mEmail; + mCustoms = other.mCustoms; + } + + QString mName; + QString mEmail; + QMap mCustoms; +}; + +ContactGroup::Data::Data() + : d(new DataPrivate) +{ +} + +ContactGroup::Data::Data(const Data &other) + : d(other.d) +{ +} + +ContactGroup::Data::Data(const QString &name, const QString &email) + : d(new DataPrivate) +{ + d->mName = name; + d->mEmail = email; +} + +ContactGroup::Data::~Data() +{ +} + +void ContactGroup::Data::setName(const QString &name) +{ + d->mName = name; +} + +QString ContactGroup::Data::name() const +{ + return d->mName; +} + +void ContactGroup::Data::setEmail(const QString &email) +{ + d->mEmail = email; +} + +QString ContactGroup::Data::email() const +{ + return d->mEmail; +} + +void ContactGroup::Data::insertCustom(const QString &key, const QString &value) +{ + d->mCustoms.insert(key, value); +} + +void ContactGroup::Data::removeCustom(const QString &key) +{ + d->mCustoms.remove(key); +} + +QString ContactGroup::Data::custom(const QString &key) const +{ + return d->mCustoms.value(key); +} + +ContactGroup::Data &ContactGroup::Data::operator=(const ContactGroup::Data &other) +{ + if (this != &other) { + d = other.d; + } + + return *this; +} + +bool ContactGroup::Data::operator==(const Data &other) const +{ + return d->mName == other.d->mName && + d->mEmail == other.d->mEmail && + d->mCustoms == other.d->mCustoms; +} + +class Q_DECL_HIDDEN ContactGroup::Private : public QSharedData +{ +public: + Private() + : QSharedData() + , mIdentifier(QUuid::createUuid().toString().mid(1, 36)) //We avoid the curly braces so the string is RFC4122 compliant and can be used as urn + { + } + + Private(const Private &other) + : QSharedData(other) + { + mIdentifier = other.mIdentifier; + mName = other.mName; + mContactReferences = other.mContactReferences; + mContactGroupReferences = other.mContactGroupReferences; + mDataObjects = other.mDataObjects; + } + + QString mIdentifier; + QString mName; + ContactGroup::ContactReference::List mContactReferences; + ContactGroup::ContactGroupReference::List mContactGroupReferences; + ContactGroup::Data::List mDataObjects; +}; + +ContactGroup::ContactGroup() + : d(new Private) +{ +} + +ContactGroup::ContactGroup(const ContactGroup &other) + : d(other.d) +{ +} + +ContactGroup::ContactGroup(const QString &name) + : d(new Private) +{ + d->mName = name; +} + +ContactGroup::~ContactGroup() +{ +} + +void ContactGroup::setName(const QString &name) +{ + d->mName = name; +} + +QString ContactGroup::name() const +{ + return d->mName; +} + +void ContactGroup::setId(const QString &id) +{ + d->mIdentifier = id; +} + +QString ContactGroup::id() const +{ + return d->mIdentifier; +} + +unsigned int ContactGroup::count() const +{ + return d->mContactReferences.count() + d->mDataObjects.count(); +} + +unsigned int ContactGroup::contactReferenceCount() const +{ + return d->mContactReferences.count(); +} + +unsigned int ContactGroup::contactGroupReferenceCount() const +{ + return d->mContactGroupReferences.count(); +} + +unsigned int ContactGroup::dataCount() const +{ + return d->mDataObjects.count(); +} + +ContactGroup::ContactReference &ContactGroup::contactReference(unsigned int index) +{ + Q_ASSERT_X(index < (unsigned int)d->mContactReferences.count(), + "contactReference()", "index out of range"); + + return d->mContactReferences[index]; +} + +const ContactGroup::ContactReference &ContactGroup::contactReference(unsigned int index) const +{ + Q_ASSERT_X(index < (unsigned int)d->mContactReferences.count(), + "contactReference()", "index out of range"); + + return d->mContactReferences[index]; +} + +ContactGroup::ContactGroupReference &ContactGroup::contactGroupReference(unsigned int index) +{ + Q_ASSERT_X(index < (unsigned int)d->mContactGroupReferences.count(), + "contactGroupReference()", "index out of range"); + + return d->mContactGroupReferences[index]; +} + +const ContactGroup::ContactGroupReference &ContactGroup::contactGroupReference( + unsigned int index) const +{ + Q_ASSERT_X(index < (unsigned int)d->mContactGroupReferences.count(), + "contactGroupReference()", "index out of range"); + + return d->mContactGroupReferences[index]; +} + +ContactGroup::Data &ContactGroup::data(unsigned int index) +{ + Q_ASSERT_X(index < (unsigned int)d->mDataObjects.count(), "data()", "index out of range"); + + return d->mDataObjects[index]; +} + +const ContactGroup::Data &ContactGroup::data(unsigned int index) const +{ + Q_ASSERT_X(index < (unsigned int)d->mDataObjects.count(), "data()", "index out of range"); + + return d->mDataObjects[index]; +} + +void ContactGroup::append(const ContactReference &reference) +{ + d->mContactReferences.append(reference); +} + +void ContactGroup::append(const ContactGroupReference &reference) +{ + d->mContactGroupReferences.append(reference); +} + +void ContactGroup::append(const Data &data) +{ + d->mDataObjects.append(data); +} + +void ContactGroup::remove(const ContactReference &reference) +{ + d->mContactReferences.removeOne(reference); +} + +void ContactGroup::remove(const ContactGroupReference &reference) +{ + d->mContactGroupReferences.removeOne(reference); +} + +void ContactGroup::remove(const Data &data) +{ + d->mDataObjects.removeOne(data); +} + +void ContactGroup::removeAllContactReferences() +{ + d->mContactReferences.clear(); +} + +void ContactGroup::removeAllContactGroupReferences() +{ + d->mContactGroupReferences.clear(); +} + +void ContactGroup::removeAllContactData() +{ + d->mDataObjects.clear(); +} + +ContactGroup &ContactGroup::operator=(const ContactGroup &other) +{ + if (this != &other) { + d = other.d; + } + + return *this; +} + +bool ContactGroup::operator==(const ContactGroup &other) const +{ + return d->mIdentifier == other.d->mIdentifier && + d->mName == other.d->mName && + d->mContactReferences == other.d->mContactReferences && + d->mContactGroupReferences == other.d->mContactGroupReferences && + d->mDataObjects == other.d->mDataObjects; +} + +QString ContactGroup::mimeType() +{ + return QStringLiteral("application/x-vnd.kde.contactgroup"); +} diff --git a/src/contactgroup.h b/src/contactgroup.h new file mode 100644 index 0000000..b43c716 --- /dev/null +++ b/src/contactgroup.h @@ -0,0 +1,490 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2008 Tobias Koenig + + 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 KCONTACTS_CONTACTGROUP_H +#define KCONTACTS_CONTACTGROUP_H + +#include +#include +#include + +#include "kcontacts_export.h" + +class QString; + +namespace KContacts +{ + +/** + * @short This class represents a group of contacts. + * + * It can contain two types of contacts, either a reference + * or data. + * The reference entry is just an unique identifier which + * identifies the real contact in the system. + * The data entry contains a name and an email address. + * + * @author Tobias Koenig + * @since 4.3 + */ +class KCONTACTS_EXPORT ContactGroup +{ +public: + + /** + * This class represents a contact reference + */ + class KCONTACTS_EXPORT ContactReference + { + public: + /** + * A list of contact references. + */ + typedef QVector List; + + /** + * Creates an empty contact reference. + */ + ContactReference(); + + /** + * Creates a contact reference from an @p other reference. + */ + ContactReference(const ContactReference &other); + + /** + * Creates a contact reference for the given contact @p uid. + */ + ContactReference(const QString &uid); + + /** + * Destroys the contact reference. + */ + ~ContactReference(); + + /** + * Sets the contact uid of the contact reference. + * @param uid identifier of the contact to reference + * @note That is the Akonadi Item ID of the contact that + * is referenced here. + */ + void setUid(const QString &uid); + + /** + * Returns the contact uid of the contact reference. + * + * @note That is the Akonadi Item ID of the contact that + * is referenced here. + */ + QString uid() const; + + /** + * Sets the contact gid of the contact reference. + * @param gid globally unique identifier of the contact to reference + * @since 4.12 + */ + void setGid(const QString &gid); + + /** + * Returns the contact GID of the contact reference. + * @since 4.12 + */ + QString gid() const; + + /** + * Sets the preferred email address. + */ + void setPreferredEmail(const QString &email); + + /** + * Returns the preferred email address, or an empty string + * if no preferred email address is set. + */ + QString preferredEmail() const; + + /** + * Inserts a custom entry. + * If an entry with the same @p key already exists, it is + * overwritten. + * + * @param key The unique key. + * @param value The value. + */ + void insertCustom(const QString &key, const QString &value); + + /** + * Removes the custom entry with the given @p key. + */ + void removeCustom(const QString &key); + + /** + * Returns the value for the given @p key, or an empty string + * if the entry for that key does not exists. + */ + QString custom(const QString &key) const; + + /** + * @internal + */ + ContactReference &operator=(const ContactReference &other); + + /** + * @internal + */ + bool operator==(const ContactReference &other) const; + + private: + class ContactReferencePrivate; + QSharedDataPointer d; + }; + + /** + * This class represents a contact group reference + */ + class KCONTACTS_EXPORT ContactGroupReference + { + public: + /** + * A list of contact group references. + */ + typedef QVector List; + + /** + * Creates an empty contact group reference. + */ + ContactGroupReference(); + + /** + * Creates a contact group reference from an @p other reference. + */ + ContactGroupReference(const ContactGroupReference &other); + + /** + * Creates a contact group reference for the given contact group @p uid. + */ + ContactGroupReference(const QString &uid); + + /** + * Destroys the contact group reference. + */ + ~ContactGroupReference(); + + /** + * Sets the contact group uid of the contact group reference. + */ + void setUid(const QString &uid); + + /** + * Returns the contact group uid of the contact group reference. + */ + QString uid() const; + + /** + * Inserts a custom entry. + * If an entry with the same @p key already exists, it is + * overwritten. + * + * @param key The unique key. + * @param value The value. + */ + void insertCustom(const QString &key, const QString &value); + + /** + * Removes the custom entry with the given @p key. + */ + void removeCustom(const QString &key); + + /** + * Returns the value for the given @p key, or an empty string + * if the entry for that key does not exists. + */ + QString custom(const QString &key) const; + + /** + * @internal + */ + ContactGroupReference &operator=(const ContactGroupReference &other); + + /** + * @internal + */ + bool operator==(const ContactGroupReference &other) const; + + private: + class ContactGroupReferencePrivate; + QSharedDataPointer d; + }; + + /** + * This class represents a contact data object + */ + class KCONTACTS_EXPORT Data + { + public: + /** + * A list of contact data. + */ + typedef QVector List; + + /** + * Creates an empty contact data object. + */ + Data(); + + /** + * Creates a contact data object from an @p other data object. + */ + Data(const Data &other); + + /** + * Creates a contact data object with the given @p name and @p email address. + */ + Data(const QString &name, const QString &email); + + /** + * Destroys the contact data object. + */ + ~Data(); + + /** + * Sets the @p name of the contact data object. + */ + void setName(const QString &name); + + /** + * Returns the name of the contact data object. + */ + QString name() const; + + /** + * Sets the @p email address of the contact data object. + */ + void setEmail(const QString &email); + + /** + * Returns the email address of the contact data object. + */ + QString email() const; + + /** + * Inserts a custom entry. + * If an entry with the same @p key already exists, it is + * overwritten. + * + * @param key The unique key. + * @param value The value. + */ + void insertCustom(const QString &key, const QString &value); + + /** + * Removes the custom entry with the given @p key. + */ + void removeCustom(const QString &key); + + /** + * Returns the value for the given @p key, or an empty string + * if the entry for that key does not exists. + */ + QString custom(const QString &key) const; + + /** + * @internal + */ + Data &operator=(const Data &other); + + /** + * @internal + */ + bool operator==(const Data &other) const; + + private: + class DataPrivate; + QSharedDataPointer d; + }; + + /** + * A list of contact groups. + */ + typedef QVector List; + + /** + * Creates an empty contact group. + */ + ContactGroup(); + + /** + * Creates a contact group from an @p other group. + */ + ContactGroup(const ContactGroup &other); + + /** + * Creates a contact group with the given name. + */ + ContactGroup(const QString &name); + + /** + * Destroys the contact group. + */ + ~ContactGroup(); + + /** + * Sets the unique @p id of the contact group. + */ + void setId(const QString &id); + + /** + * Returns the unique id of the contact group. + */ + QString id() const; + + /** + * Sets the i18n'd @p name of the contact group. + */ + void setName(const QString &name); + + /** + * Returns the i18n'd name of the contact group. + */ + QString name() const; + + /** + * Returns the number of contacts in this group. + * That includes the contact references and contact data. + */ + unsigned int count() const; + + /** + * Returns the number of contact references in this group. + */ + unsigned int contactReferenceCount() const; + + /** + * Returns the number of group references in this group. + */ + unsigned int contactGroupReferenceCount() const; + + /** + * Returns the number of contact data objects in this group. + */ + unsigned int dataCount() const; + + /** + * Returns the contact reference at the given @p index. + */ + ContactReference &contactReference(unsigned int index); + + /** + * Returns the contact reference at the given @p index. + */ + const ContactReference &contactReference(unsigned int index) const; + + /** + * Returns the contact group reference at the given @p index. + */ + ContactGroupReference &contactGroupReference(unsigned int index); + + /** + * Returns the contact group reference at the given @p index. + */ + const ContactGroupReference &contactGroupReference(unsigned int index) const; + + /** + * Returns the contact data object at the given @p index. + */ + Data &data(unsigned int index); + + /** + * Returns the contact data object at the given @p index. + */ + const Data &data(unsigned int index) const; + + /** + * Appends a new contact @p reference to the contact group. + */ + void append(const ContactReference &reference); + + /** + * Appends a new contact group @p reference to the contact group. + */ + void append(const ContactGroupReference &reference); + + /** + * Appends a new contact @p data object to the contact group. + */ + void append(const Data &data); + + /** + * Removes the given contact @p reference from the contact group. + */ + void remove(const ContactReference &reference); + + /** + * Removes the given contact group @p reference from the contact group. + */ + void remove(const ContactGroupReference &reference); + + /** + * Removes the given contact @p data object from the contact group. + */ + void remove(const Data &data); + + /** + * Removes all contact references from the contact group. + */ + void removeAllContactReferences(); + + /** + * Removes all contact group references from the contact group. + */ + void removeAllContactGroupReferences(); + + /** + * Removes all contact data from the contact group. + */ + void removeAllContactData(); + + /** + * @internal + */ + ContactGroup &operator=(const ContactGroup &other); + + /** + * @internal + */ + bool operator==(const ContactGroup &other) const; + + /** + * Returns the MIME type used for Contact Groups + */ + static QString mimeType(); + +private: + class Private; + QSharedDataPointer d; +}; + +} +Q_DECLARE_TYPEINFO(KContacts::ContactGroup::ContactGroupReference, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(KContacts::ContactGroup::ContactReference, Q_MOVABLE_TYPE); + +#define KCONTACTS_CONTACTGROUP_METATYPE_DEFINED +Q_DECLARE_METATYPE(KContacts::ContactGroup) + +#endif diff --git a/src/contactgroup.xsd b/src/contactgroup.xsd new file mode 100644 index 0000000..ba486b6 --- /dev/null +++ b/src/contactgroup.xsd @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/contactgrouptool.cpp b/src/contactgrouptool.cpp new file mode 100644 index 0000000..0f70df9 --- /dev/null +++ b/src/contactgrouptool.cpp @@ -0,0 +1,370 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2008 Tobias Koenig + Copyright (c) 2008 Kevin Krammer + + 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 "contactgrouptool.h" +#include "contactgroup.h" + +#include +#include +#include + +#include +#include + +using namespace KContacts; + +class XmlContactGroupWriter : public QXmlStreamWriter +{ +public: + XmlContactGroupWriter(); + + void write(const ContactGroup &group, QIODevice *device); + void write(const QVector &groupLis, QIODevice *device); + +private: + void writeGroup(const ContactGroup &group); + void writeContactReference(const ContactGroup::ContactReference &reference); + void writeContactGroupReference(const ContactGroup::ContactGroupReference &reference); + void writeData(const ContactGroup::Data &data); +}; + +XmlContactGroupWriter::XmlContactGroupWriter() +{ + setAutoFormatting(true); +} + +void XmlContactGroupWriter::write(const ContactGroup &group, QIODevice *device) +{ + setDevice(device); + + writeStartDocument(); + + writeGroup(group); + + writeEndDocument(); +} + +void XmlContactGroupWriter::write(const QVector &groupList, QIODevice *device) +{ + setDevice(device); + + writeStartDocument(); + + writeStartElement(QStringLiteral("contactGroupList")); + + foreach (const ContactGroup &group, groupList) { + writeGroup(group); + } + + writeEndElement(); + + writeEndDocument(); +} + +void XmlContactGroupWriter::writeGroup(const ContactGroup &group) +{ + writeStartElement(QStringLiteral("contactGroup")); + writeAttribute(QStringLiteral("uid"), group.id()); + writeAttribute(QStringLiteral("name"), group.name()); + + for (uint i = 0; i < group.contactReferenceCount(); ++i) { + writeContactReference(group.contactReference(i)); + } + + for (uint i = 0; i < group.contactGroupReferenceCount(); ++i) { + writeContactGroupReference(group.contactGroupReference(i)); + } + + for (uint i = 0; i < group.dataCount(); ++i) { + writeData(group.data(i)); + } + + writeEndElement(); +} + +void XmlContactGroupWriter::writeContactReference(const ContactGroup::ContactReference &reference) +{ + writeStartElement(QStringLiteral("contactReference")); + writeAttribute(QStringLiteral("uid"), reference.uid()); + writeAttribute(QStringLiteral("gid"), reference.gid()); + if (!reference.preferredEmail().isEmpty()) { + writeAttribute(QStringLiteral("preferredEmail"), reference.preferredEmail()); + } + + // TODO: customs + + writeEndElement(); +} + +void XmlContactGroupWriter::writeContactGroupReference( + const ContactGroup::ContactGroupReference &reference) +{ + writeStartElement(QStringLiteral("contactGroupReference")); + writeAttribute(QStringLiteral("uid"), reference.uid()); + + // TODO: customs + + writeEndElement(); +} + +void XmlContactGroupWriter::writeData(const ContactGroup::Data &data) +{ + writeStartElement(QStringLiteral("contactData")); + writeAttribute(QStringLiteral("name"), data.name()); + writeAttribute(QStringLiteral("email"), data.email()); + + // TODO: customs + + writeEndElement(); +} + +class XmlContactGroupReader : public QXmlStreamReader +{ +public: + XmlContactGroupReader(); + + bool read(QIODevice *device, ContactGroup &group); + bool read(QIODevice *device, QVector &groupList); + +private: + bool readGroup(ContactGroup &group); + bool readContactReference(ContactGroup::ContactReference &reference); + bool readContactGroupReference(ContactGroup::ContactGroupReference &reference); + bool readData(ContactGroup::Data &data); +}; + +XmlContactGroupReader::XmlContactGroupReader() +{ +} + +bool XmlContactGroupReader::read(QIODevice *device, ContactGroup &group) +{ + setDevice(device); + + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("contactGroup")) { + return readGroup(group); + } else { + raiseError(QStringLiteral("The document does not describe a ContactGroup")); + } + } + } + + return error() == NoError; +} + +bool XmlContactGroupReader::read(QIODevice *device, QVector &groupList) +{ + setDevice(device); + + int depth = 0; + + while (!atEnd()) { + readNext(); + if (isStartElement()) { + ++depth; + if (depth == 1) { + if (name() == QLatin1String("contactGroupList")) { + continue; + } else { + raiseError(QStringLiteral("The document does not describe a list of ContactGroup")); + } + } else if (depth == 2) { + if (name() == QLatin1String("contactGroup")) { + ContactGroup group; + if (!readGroup(group)) { + return false; + } + + groupList.append(group); + } else { + raiseError(QStringLiteral("The document does not describe a list of ContactGroup")); + } + } + } + + if (isEndElement()) { + --depth; + } + } + + return error() == NoError; +} + +bool XmlContactGroupReader::readGroup(ContactGroup &group) +{ + const QXmlStreamAttributes elementAttributes = attributes(); + const QStringRef uid = elementAttributes.value(QLatin1String("uid")); + if (uid.isEmpty()) { + raiseError(QStringLiteral("ContactGroup is missing a uid")); + return false; + } + + const QStringRef groupName = elementAttributes.value(QLatin1String("name")); + if (groupName.isEmpty()) { + raiseError(QStringLiteral("ContactGroup is missing a name")); + return false; + } + + group.setId(uid.toString()); + group.setName(groupName.toString()); + + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("contactData")) { + ContactGroup::Data data; + if (!readData(data)) { + return false; + } + group.append(data); + } else if (name() == QLatin1String("contactReference")) { + ContactGroup::ContactReference reference; + if (!readContactReference(reference)) { + return false; + } + group.append(reference); + } else if (name() == QLatin1String("contactGroupReference")) { + ContactGroup::ContactGroupReference reference; + if (!readContactGroupReference(reference)) { + return false; + } + group.append(reference); + } else { + raiseError(QStringLiteral("The document does not describe a ContactGroup")); + } + } + + if (isEndElement()) { + if (name() == QLatin1String("contactGroup")) { + return true; + } + } + } + + return false; +} + +bool XmlContactGroupReader::readData(ContactGroup::Data &data) +{ + const QXmlStreamAttributes elementAttributes = attributes(); + const QStringRef email = elementAttributes.value(QLatin1String("email")); + if (email.isEmpty()) { + raiseError(QStringLiteral("ContactData is missing an email address")); + return false; + } + + const QStringRef name = elementAttributes.value(QLatin1String("name")); + + data.setName(name.toString()); + data.setEmail(email.toString()); + + return true; +} + +bool XmlContactGroupReader::readContactReference(ContactGroup::ContactReference &reference) +{ + const QXmlStreamAttributes elementAttributes = attributes(); + const QStringRef uid = elementAttributes.value(QLatin1String("uid")); + const QStringRef gid = elementAttributes.value(QLatin1String("gid")); + if (uid.isEmpty() && gid.isEmpty()) { + raiseError(QStringLiteral("ContactReference is missing both uid and gid")); + return false; + } + const QStringRef preferredEmail = elementAttributes.value(QLatin1String("preferredEmail")); + + reference.setUid(uid.toString()); + reference.setGid(gid.toString()); + reference.setPreferredEmail(preferredEmail.toString()); + + return true; +} + +bool XmlContactGroupReader::readContactGroupReference( + ContactGroup::ContactGroupReference &reference) +{ + const QXmlStreamAttributes elementAttributes = attributes(); + const QStringRef uid = elementAttributes.value(QLatin1String("uid")); + if (uid.isEmpty()) { + raiseError(QStringLiteral("ContactGroupReference is missing a uid")); + return false; + } + + reference.setUid(uid.toString()); + + return true; +} + +bool ContactGroupTool::convertFromXml(QIODevice *device, ContactGroup &group, + QString *errorMessage) +{ + Q_UNUSED(errorMessage); + + XmlContactGroupReader reader; + + bool ok = reader.read(device, group); + + if (!ok && errorMessage != Q_NULLPTR) { + *errorMessage = reader.errorString(); + } + + return ok; +} + +bool ContactGroupTool::convertToXml(const ContactGroup &group, QIODevice *device, + QString *errorMessage) +{ + Q_UNUSED(errorMessage); + + XmlContactGroupWriter writer; + writer.write(group, device); + + return true; +} + +bool ContactGroupTool::convertFromXml(QIODevice *device, QVector &groupList, + QString *errorMessage) +{ + Q_UNUSED(errorMessage); + + XmlContactGroupReader reader; + + bool ok = reader.read(device, groupList); + + if (!ok && errorMessage != Q_NULLPTR) { + *errorMessage = reader.errorString(); + } + + return ok; +} + +bool ContactGroupTool::convertToXml(const QVector &groupList, + QIODevice *device, QString *errorMessage) +{ + Q_UNUSED(errorMessage); + + XmlContactGroupWriter writer; + writer.write(groupList, device); + + return true; +} diff --git a/src/contactgrouptool.h b/src/contactgrouptool.h new file mode 100644 index 0000000..0b9a66b --- /dev/null +++ b/src/contactgrouptool.h @@ -0,0 +1,77 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2008 Tobias Koenig + Copyright (c) 2008 Kevin Krammer + + 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 KCONTACTS_CONTACTGROUPTOOL_H +#define KCONTACTS_CONTACTGROUPTOOL_H + +#include "kcontacts_export.h" +#include +class QIODevice; + +template class QList; + +namespace KContacts +{ + +class ContactGroup; + +/** + * Static methods for converting ContactGroup to XML format and vice versa. + * + * @author Kevin Krammer + * @since 4.3 + */ +namespace ContactGroupTool +{ + +/** + * Converts XML data coming from a @p device into a contact @p group. + * If an error occurs, @c false is returned and @p errorMessage is set. + */ +KCONTACTS_EXPORT bool convertFromXml(QIODevice *device, ContactGroup &group, + QString *errorMessage = Q_NULLPTR); + +/** + * Converts a contact @p group into XML data and writes them to a @p device. + * If an error occurs, @c false is returned and @p errorMessage is set. + */ +KCONTACTS_EXPORT bool convertToXml(const ContactGroup &group, QIODevice *device, + QString *errorMessage = Q_NULLPTR); + +/** + * Converts XML data coming from a @p device into a @p list of contact groups. + * If an error occurs, @c false is returned and @p errorMessage is set. + */ +KCONTACTS_EXPORT bool convertFromXml(QIODevice *device, + QVector &list, + QString *errorMessage = Q_NULLPTR); + +/** + * Converts a @p list of contact groups into XML data and writes them to a @p device. + * If an error occurs, @c false is returned and @p errorMessage is set. + */ +KCONTACTS_EXPORT bool convertToXml(const QVector &list, + QIODevice *device, QString *errorMessage = Q_NULLPTR); +} + +} + +#endif diff --git a/src/converter/CMakeLists.txt b/src/converter/CMakeLists.txt new file mode 100644 index 0000000..6d07969 --- /dev/null +++ b/src/converter/CMakeLists.txt @@ -0,0 +1,22 @@ +ecm_generate_headers(KContacts_CamelCase_Converter_HEADERS + HEADER_NAMES + LDIFConverter + VCardConverter + PREFIX KContacts + REQUIRED_HEADERS KContacts_Converter_HEADERS +) + +install(FILES + ${KContacts_CamelCase_Converter_HEADERS} + DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KContacts/KContacts + COMPONENT Devel +) + + +install(FILES + ${KContacts_Converter_HEADERS} + DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KContacts/kcontacts + COMPONENT Devel +) + + diff --git a/src/converter/ldifconverter.cpp b/src/converter/ldifconverter.cpp new file mode 100644 index 0000000..d1fee94 --- /dev/null +++ b/src/converter/ldifconverter.cpp @@ -0,0 +1,643 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2003 Helge Deller + + 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. +*/ + +/* + Useful links: + - http://tldp.org/HOWTO/LDAP-Implementation-HOWTO/schemas.html + - http://www.faqs.org/rfcs/rfc2849.html + + Not yet handled items: + - objectclass microsoftaddressbook + - info, + - initials, + - otherfacsimiletelephonenumber, + - otherpager, + - physicaldeliveryofficename, +*/ + +#include "ldifconverter.h" +#include "vcardconverter.h" +#include "address.h" +#include "addressee.h" +#include "kcontacts_debug.h" + +#include "ldif_p.h" + +#include + +#include +#include +#include + +using namespace KContacts; + +/* internal functions - do not use !! */ + +namespace KContacts +{ +/** + @internal + + Evaluates @p fieldname and sets the @p value at the addressee or the address + objects when appropriate. + + @param a The addressee to store information into + @param homeAddr The home address to store respective information into + @param workAddr The work address to store respective information into + @param fieldname LDIF field name to evaluate + @param value The value of the field addressed by @p fieldname +*/ +void evaluatePair(Addressee &a, Address &homeAddr, + Address &workAddr, + QString &fieldname, QString &value, + int &birthday, int &birthmonth, int &birthyear, ContactGroup &contactGroup); +} + +/* generate LDIF stream */ + +static void ldif_out(QTextStream &t, const QString &formatStr, + const QString &value) +{ + if (value.isEmpty()) { + return; + } + + const QByteArray txt = Ldif::assembleLine(formatStr, value, 72); + + // write the string + t << QString::fromUtf8(txt) << "\n"; +} + +bool LDIFConverter::addresseeAndContactGroupToLDIF(const AddresseeList &addrList, const ContactGroup::List &contactGroupList, QString &str) +{ + bool result = addresseeToLDIF(addrList, str); + if (!contactGroupList.isEmpty()) { + result = contactGroupToLDIF(contactGroupList, str); + } + return result; +} + +bool LDIFConverter::contactGroupToLDIF(const ContactGroup &contactGroup, QString &str) +{ + if (contactGroup.dataCount() <= 0) { + return false; + } + QTextStream t(&str, QIODevice::WriteOnly | QIODevice::Append); + t.setCodec(QTextCodec::codecForName("UTF-8")); + t << "objectclass: top\n"; + t << "objectclass: groupOfNames\n"; + + for (unsigned int i = 0; i < contactGroup.dataCount(); ++i) { + ContactGroup::Data data = contactGroup.data(i); + const QString value = QStringLiteral("cn=%1,mail=%2").arg(data.name(), data.email()); + ldif_out(t, QStringLiteral("member"), value); + } + + t << "\n"; + return true; +} + +bool LDIFConverter::contactGroupToLDIF(const ContactGroup::List &contactGroupList, QString &str) +{ + ContactGroup::List::ConstIterator it; + ContactGroup::List::ConstIterator end(contactGroupList.constEnd()); + for (it = contactGroupList.constBegin(); it != end; ++it) { + contactGroupToLDIF(*it, str); + } + return true; +} + +bool LDIFConverter::addresseeToLDIF(const AddresseeList &addrList, QString &str) +{ + AddresseeList::ConstIterator it; + AddresseeList::ConstIterator end(addrList.constEnd()); + for (it = addrList.constBegin(); it != end; ++it) { + addresseeToLDIF(*it, str); + } + return true; +} + +bool LDIFConverter::addresseeToLDIF(const Addressee &addr, QString &str) +{ + if (addr.isEmpty()) { + return false; + } + + QTextStream t(&str, QIODevice::WriteOnly | QIODevice::Append); + t.setCodec(QTextCodec::codecForName("UTF-8")); + + const Address homeAddr = addr.address(Address::Home); + const Address workAddr = addr.address(Address::Work); + + ldif_out(t, QStringLiteral("dn"), QStringLiteral("cn=%1,mail=%2"). + arg(addr.formattedName().simplified(), addr.preferredEmail())); + t << "objectclass: top\n"; + t << "objectclass: person\n"; + t << "objectclass: organizationalPerson\n"; + + ldif_out(t, QStringLiteral("givenname"), addr.givenName()); + ldif_out(t, QStringLiteral("sn"), addr.familyName()); + ldif_out(t, QStringLiteral("cn"), addr.formattedName().simplified()); + ldif_out(t, QStringLiteral("uid"), addr.uid()); + ldif_out(t, QStringLiteral("nickname"), addr.nickName()); + ldif_out(t, QStringLiteral("xmozillanickname"), addr.nickName()); + ldif_out(t, QStringLiteral("mozillanickname"), addr.nickName()); + + ldif_out(t, QStringLiteral("mail"), addr.preferredEmail()); + const QStringList emails = addr.emails(); + const int numEmails = emails.count(); + for (int i = 1; i < numEmails; ++i) { + if (i == 0) { + //nothing + } else if (i == 1) { + ldif_out(t, QStringLiteral("mozillasecondemail"), emails[1]); + } else { + ldif_out(t, QStringLiteral("othermailbox"), emails[i]); + } + } + //ldif_out( t, "mozilla_AIMScreenName: %1\n", "screen_name" ); + + ldif_out(t, QStringLiteral("telephonenumber"), + addr.phoneNumber(PhoneNumber::Work).number()); + ldif_out(t, QStringLiteral("facsimiletelephonenumber"), + addr.phoneNumber(PhoneNumber::Fax).number()); + ldif_out(t, QStringLiteral("homephone"), + addr.phoneNumber(PhoneNumber::Home).number()); + ldif_out(t, QStringLiteral("mobile"), + addr.phoneNumber(PhoneNumber::Cell).number()); // Netscape 7 + ldif_out(t, QStringLiteral("cellphone"), + addr.phoneNumber(PhoneNumber::Cell).number()); // Netscape 4.x + ldif_out(t, QStringLiteral("pager"), + addr.phoneNumber(PhoneNumber::Pager).number()); + ldif_out(t, QStringLiteral("pagerphone"), + addr.phoneNumber(PhoneNumber::Pager).number()); + + ldif_out(t, QStringLiteral("streethomeaddress"), homeAddr.street()); + ldif_out(t, QStringLiteral("postalcode"), workAddr.postalCode()); + ldif_out(t, QStringLiteral("postofficebox"), workAddr.postOfficeBox()); + + QStringList streets = homeAddr.street().split(QLatin1Char('\n')); + const int numberOfStreets(streets.count()); + if (numberOfStreets > 0) { + ldif_out(t, QStringLiteral("homepostaladdress"), streets.at(0)); // Netscape 7 + } + if (numberOfStreets > 1) { + ldif_out(t, QStringLiteral("mozillahomepostaladdress2"), streets.at(1)); // Netscape 7 + } + ldif_out(t, QStringLiteral("mozillahomelocalityname"), homeAddr.locality()); // Netscape 7 + ldif_out(t, QStringLiteral("mozillahomestate"), homeAddr.region()); + ldif_out(t, QStringLiteral("mozillahomepostalcode"), homeAddr.postalCode()); + ldif_out(t, QStringLiteral("mozillahomecountryname"), + Address::ISOtoCountry(homeAddr.country())); + ldif_out(t, QStringLiteral("locality"), workAddr.locality()); + ldif_out(t, QStringLiteral("streetaddress"), workAddr.street()); // Netscape 4.x + + streets = workAddr.street().split(QLatin1Char('\n')); + if (streets.count() > 0) { + ldif_out(t, QStringLiteral("street"), streets.at(0)); + } + if (streets.count() > 1) { + ldif_out(t, QStringLiteral("mozillaworkstreet2"), streets.at(1)); + } + ldif_out(t, QStringLiteral("countryname"), Address::ISOtoCountry(workAddr.country())); + ldif_out(t, QStringLiteral("l"), workAddr.locality()); + ldif_out(t, QStringLiteral("c"), Address::ISOtoCountry(workAddr.country())); + ldif_out(t, QStringLiteral("st"), workAddr.region()); + + ldif_out(t, QStringLiteral("title"), addr.title()); + ldif_out(t, QStringLiteral("vocation"), addr.prefix()); + ldif_out(t, QStringLiteral("ou"), addr.role()); + ldif_out(t, QStringLiteral("o"), addr.organization()); + ldif_out(t, QStringLiteral("organization"), addr.organization()); + ldif_out(t, QStringLiteral("organizationname"), addr.organization()); + + // Compatibility with older kabc versions. + if (!addr.department().isEmpty()) { + ldif_out(t, QStringLiteral("department"), addr.department()); + } else { + ldif_out(t, QStringLiteral("department"), addr.custom(QStringLiteral("KADDRESSBOOK"), + QStringLiteral("X-Department"))); + } + + ldif_out(t, QStringLiteral("workurl"), addr.url().url().toDisplayString()); + ldif_out(t, QStringLiteral("homeurl"), addr.url().url().toDisplayString()); + ldif_out(t, QStringLiteral("mozillahomeurl"), addr.url().url().toDisplayString()); + + ldif_out(t, QStringLiteral("description"), addr.note()); + if (addr.revision().isValid()) { + ldif_out(t, QStringLiteral("modifytimestamp"), dateToVCardString(addr.revision())); + } + + const QDateTime birthday = addr.birthday(); + if (birthday.date().isValid()) { + const QDate date = birthday.date(); + ldif_out(t, QStringLiteral("birthyear"), QString::number(date.year())); + ldif_out(t, QStringLiteral("birthmonth"), QString::number(date.month())); + ldif_out(t, QStringLiteral("birthday"), QString::number(date.day())); + } + + t << "\n"; + + return true; +} + +/* convert from LDIF stream */ +bool LDIFConverter::LDIFToAddressee(const QString &str, AddresseeList &addrList, ContactGroup::List &contactGroupList, + const QDateTime &dt) +{ + if (str.isEmpty()) { + return true; + } + + bool endldif = false, end = false; + Ldif ldif; + Ldif::ParseValue ret; + Addressee a; + Address homeAddr, workAddr; + int birthday = -1; + int birthmonth = -1; + int birthyear = -1; + ContactGroup contactGroup; + ldif.setLdif(str.toLatin1()); + QDateTime qdt = dt; + if (!qdt.isValid()) { + qdt = QDateTime::currentDateTime(); + } + a.setRevision(qdt); + homeAddr = Address(Address::Home); + workAddr = Address(Address::Work); + + do { + ret = ldif.nextItem(); + switch (ret) { + case Ldif::Item: { + QString fieldname = ldif.attr().toLower(); + QString value = QString::fromUtf8(ldif.value()); + evaluatePair(a, homeAddr, workAddr, fieldname, value, birthday, birthmonth, birthyear, contactGroup); + break; + } + case Ldif::EndEntry: { + if (contactGroup.count() == 0) { + // if the new address is not empty, append it + QDateTime birthDate(QDate(birthyear, birthmonth, birthday)); + if (birthDate.isValid()) { + a.setBirthday(birthDate); + } + + if (!a.formattedName().isEmpty() || !a.name().isEmpty() || + !a.familyName().isEmpty()) { + if (!homeAddr.isEmpty()) { + a.insertAddress(homeAddr); + } + if (!workAddr.isEmpty()) { + a.insertAddress(workAddr); + } + addrList.append(a); + } + } else { + contactGroupList.append(contactGroup); + } + a = Addressee(); + contactGroup = ContactGroup(); + a.setRevision(qdt); + homeAddr = Address(Address::Home); + workAddr = Address(Address::Work); + } + break; + case Ldif::MoreData: { + if (endldif) { + end = true; + } else { + ldif.endLdif(); + endldif = true; + break; + } + } + default: + break; + } + } while (!end); + + return true; +} + +void KContacts::evaluatePair(Addressee &a, Address &homeAddr, + Address &workAddr, + QString &fieldname, QString &value, + int &birthday, int &birthmonth, int &birthyear, ContactGroup &contactGroup) +{ + if (fieldname == QLatin1String("dn")) { // ignore + return; + } + + if (fieldname.startsWith(QLatin1Char('#'))) { + return; + } + + if (fieldname.isEmpty() && !a.note().isEmpty()) { + // some LDIF export filters are borken and add additional + // comments on stand-alone lines. Just add them to the notes for now. + a.setNote(a.note() + QLatin1Char('\n') + value); + return; + } + + if (fieldname == QLatin1String("givenname")) { + a.setGivenName(value); + return; + } + + if (fieldname == QLatin1String("xmozillanickname") || + fieldname == QLatin1String("nickname") || + fieldname == QLatin1String("mozillanickname")) { + a.setNickName(value); + return; + } + + if (fieldname == QLatin1String("sn")) { + a.setFamilyName(value); + return; + } + + if (fieldname == QLatin1String("uid")) { + a.setUid(value); + return; + } + if (fieldname == QLatin1String("mail") || + fieldname == QLatin1String("mozillasecondemail") /* mozilla */ || + fieldname == QLatin1String("othermailbox") /*TheBat!*/) { + if (a.emails().indexOf(value) == -1) { + a.insertEmail(value); + } + return; + } + + if (fieldname == QLatin1String("title")) { + a.setTitle(value); + return; + } + + if (fieldname == QLatin1String("vocation")) { + a.setPrefix(value); + return; + } + + if (fieldname == QLatin1String("cn")) { + a.setFormattedName(value); + return; + } + + if (fieldname == QLatin1String("o") || + fieldname == QLatin1String("organization") || // Exchange + fieldname == QLatin1String("organizationname")) { // Exchange + a.setOrganization(value); + return; + } + + if (fieldname == QLatin1String("description") || + fieldname == QLatin1String("mozillacustom1") || + fieldname == QLatin1String("mozillacustom2") || + fieldname == QLatin1String("mozillacustom3") || + fieldname == QLatin1String("mozillacustom4") || + fieldname == QLatin1String("custom1") || + fieldname == QLatin1String("custom2") || + fieldname == QLatin1String("custom3") || + fieldname == QLatin1String("custom4")) { + if (!a.note().isEmpty()) { + a.setNote(a.note() + QLatin1Char('\n')); + } + a.setNote(a.note() + value); + return; + } + + if (fieldname == QLatin1String("homeurl") || + fieldname == QLatin1String("workurl") || + fieldname == QLatin1String("mozillahomeurl")) { + if (a.url().url().isEmpty()) { + ResourceLocatorUrl url; + url.setUrl(QUrl(value)); + a.setUrl(url); + return; + } + if (a.url().url().toDisplayString() == QUrl(value).toDisplayString()) { + return; + } + // TODO: current version of kabc only supports one URL. + // TODO: change this with KDE 4 + } + + if (fieldname == QLatin1String("homephone")) { + a.insertPhoneNumber(PhoneNumber(value, PhoneNumber::Home)); + return; + } + + if (fieldname == QLatin1String("telephonenumber")) { + a.insertPhoneNumber(PhoneNumber(value, PhoneNumber::Work)); + return; + } + if (fieldname == QLatin1String("mobile") || /* mozilla/Netscape 7 */ + fieldname == QLatin1String("cellphone")) { + a.insertPhoneNumber(PhoneNumber(value, PhoneNumber::Cell)); + return; + } + + if (fieldname == QLatin1String("pager") || // mozilla + fieldname == QLatin1String("pagerphone")) { // mozilla + a.insertPhoneNumber(PhoneNumber(value, PhoneNumber::Pager)); + return; + } + + if (fieldname == QLatin1String("facsimiletelephonenumber")) { + a.insertPhoneNumber(PhoneNumber(value, PhoneNumber::Fax)); + return; + } + + if (fieldname == QLatin1String("xmozillaanyphone")) { // mozilla + a.insertPhoneNumber(PhoneNumber(value, PhoneNumber::Work)); + return; + } + + if (fieldname == QLatin1String("streethomeaddress") || + fieldname == QLatin1String("mozillahomestreet")) { // thunderbird + homeAddr.setStreet(value); + return; + } + + if (fieldname == QLatin1String("street") || + fieldname == QLatin1String("postaladdress")) { // mozilla + workAddr.setStreet(value); + return; + } + if (fieldname == QLatin1String("mozillapostaladdress2") || + fieldname == QLatin1String("mozillaworkstreet2")) { // mozilla + workAddr.setStreet(workAddr.street() + QLatin1String("\n") + value); + return; + } + + if (fieldname == QLatin1String("postalcode")) { + workAddr.setPostalCode(value); + return; + } + + if (fieldname == QLatin1String("postofficebox")) { + workAddr.setPostOfficeBox(value); + return; + } + + if (fieldname == QLatin1String("homepostaladdress")) { // Netscape 7 + homeAddr.setStreet(value); + return; + } + + if (fieldname == QLatin1String("mozillahomepostaladdress2")) { // mozilla + homeAddr.setStreet(homeAddr.street() + QLatin1String("\n") + value); + return; + } + + if (fieldname == QLatin1String("mozillahomelocalityname")) { // mozilla + homeAddr.setLocality(value); + return; + } + + if (fieldname == QLatin1String("mozillahomestate")) { // mozilla + homeAddr.setRegion(value); + return; + } + + if (fieldname == QLatin1String("mozillahomepostalcode")) { // mozilla + homeAddr.setPostalCode(value); + return; + } + + if (fieldname == QLatin1String("mozillahomecountryname")) { // mozilla + if (value.length() <= 2) { + value = Address::ISOtoCountry(value); + } + homeAddr.setCountry(value); + return; + } + + if (fieldname == QLatin1String("locality")) { + workAddr.setLocality(value); + return; + } + + if (fieldname == QLatin1String("streetaddress")) { // Netscape 4.x + workAddr.setStreet(value); + return; + } + + if (fieldname == QLatin1String("countryname") || + fieldname == QLatin1String("c")) { // mozilla + if (value.length() <= 2) { + value = Address::ISOtoCountry(value); + } + workAddr.setCountry(value); + return; + } + + if (fieldname == QLatin1String("l")) { // mozilla + workAddr.setLocality(value); + return; + } + + if (fieldname == QLatin1String("st")) { + workAddr.setRegion(value); + return; + } + + if (fieldname == QLatin1String("ou")) { + a.setRole(value); + return; + } + + if (fieldname == QLatin1String("department")) { + a.setDepartment(value); + return; + } + + if (fieldname == QLatin1String("member")) { + // this is a mozilla list member (cn=xxx, mail=yyy) + QStringList list = value.split(QLatin1Char(',')); + QString name, email; + + QStringList::ConstIterator it; + QStringList::ConstIterator end(list.constEnd()); + for (it = list.constBegin(); it != end; ++it) { + if ((*it).startsWith(QLatin1String("cn="))) { + name = (*it).mid(3).trimmed(); + } + if ((*it).startsWith(QLatin1String("mail="))) { + email = (*it).mid(5).trimmed(); + } + } + if (!name.isEmpty() && !email.isEmpty()) { + email = QLatin1String(" <") + email + QLatin1Char('>'); + } + ContactGroup::Data data; + data.setEmail(email); + data.setName(name); + contactGroup.append(data); + return; + } + + if (fieldname == QLatin1String("modifytimestamp")) { + if (value == QLatin1String("0Z")) { // ignore + return; + } + QDateTime dt = VCardStringToDate(value); + if (dt.isValid()) { + a.setRevision(dt); + return; + } + } + + if (fieldname == QLatin1String("display-name")) { + contactGroup.setName(value); + return; + } + + if (fieldname == QLatin1String("objectclass")) { // ignore + return; + } + + if (fieldname == QLatin1String("birthyear")) { + birthyear = value.toInt(); + return; + } + if (fieldname == QLatin1String("birthmonth")) { + birthmonth = value.toInt(); + return; + } + if (fieldname == QLatin1String("birthday")) { + birthday = value.toInt(); + return; + } + if (fieldname == QLatin1String("xbatbirthday")) { + QDate dt = QDate::fromString(value, QStringLiteral("yyyyMMdd")); + if (dt.isValid()) { + a.setBirthday(QDateTime(dt)); + } + return; + } + qCWarning(KCONTACTS_LOG) << QStringLiteral("LDIFConverter: Unknown field for '%1': '%2=%3'\n"). + arg(a.formattedName(), fieldname, value); + + return; +} diff --git a/src/converter/ldifconverter.h b/src/converter/ldifconverter.h new file mode 100644 index 0000000..d6ebd91 --- /dev/null +++ b/src/converter/ldifconverter.h @@ -0,0 +1,96 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2003 Helge Deller + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 only as published by the Free Software Foundation. + + 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 KCONTACTS_LDIFCONVERTER_H +#define KCONTACTS_LDIFCONVERTER_H + +#include "addressee.h" +#include "contactgroup.h" + +#include +#include + +namespace KContacts +{ + +/** + A set of functions to convert a string with LDIF information to addressees + and vice versa. It is useful for addressbook import- and exportfilters + and might be used to read and write Mozilla and Netscape addresssbooks. +*/ + +namespace LDIFConverter +{ + +/** + Converts a LDIF string to a list of addressees. + + @param str The vcard string. + @param addrList The addresseelist. + @param contactGroupList the contactGroupList + @param dt The date & time value of the last modification (e.g. file modification time). +*/ +KCONTACTS_EXPORT bool LDIFToAddressee(const QString &str, AddresseeList &addrList, QVector &contactGroupList, + const QDateTime &dt = QDateTime::currentDateTime()); + +/** + Converts a list of addressees to a LDIF string. + + @param addrList The addresseelist. + @param str The LDIF string. +*/ +KCONTACTS_EXPORT bool addresseeToLDIF(const AddresseeList &addrList, QString &str); + +/** + Converts a list of addressees and contactgrouplist to a LDIF string. + + @param addrList The addresseelist. + @param contactGroupList The contact group list + @param str The LDIF string. + +*/ +KCONTACTS_EXPORT bool addresseeAndContactGroupToLDIF(const AddresseeList &addrList, const QVector &contactGroupList, QString &str); +/** + Converts an addressee to a LDIF string. + + @param addr The addressee. + @param str The LDIF string. +*/ +KCONTACTS_EXPORT bool addresseeToLDIF(const Addressee &addr, QString &str); + +/** + Converts a list of contact group to a LDIF string. + + @param contactGroupList The contact group list + @param str The LDIF string. +*/ +KCONTACTS_EXPORT bool contactGroupToLDIF(const ContactGroup::List &contactGroupList, QString &str); + +/** + Converts a contact group to a LDIF string. + + @param contactGroup The contact group + @param str The LDIF string. +*/ +KCONTACTS_EXPORT bool contactGroupToLDIF(const ContactGroup &contactGroup, QString &str); + +} + +} +#endif diff --git a/src/converter/vcardconverter.cpp b/src/converter/vcardconverter.cpp new file mode 100644 index 0000000..4353272 --- /dev/null +++ b/src/converter/vcardconverter.cpp @@ -0,0 +1,148 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2002 Tobias Koenig + + 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 "vcardconverter.h" +#include "vcardtool.h" + +using namespace KContacts; + +VCardConverter::VCardConverter() + : d(Q_NULLPTR) +{ +} + +VCardConverter::~VCardConverter() +{ +} + +QByteArray VCardConverter::exportVCard(const Addressee &addr, Version version) const +{ + Addressee::List list; + list.append(addr); + + return exportVCards(list, version); +} + +QByteArray VCardConverter::exportVCards(const Addressee::List &list, Version version) const +{ + VCardTool tool; + QByteArray returnValue; + switch (version) { + case v2_1: + returnValue = tool.exportVCards(list, VCard::v2_1); + break; + case v3_0: + returnValue = tool.exportVCards(list, VCard::v3_0); + break; + case v4_0: + returnValue = tool.exportVCards(list, VCard::v4_0); + break; + } + + return returnValue; +} + +QByteArray VCardConverter::createVCard(const Addressee &addr, Version version) const +{ + Addressee::List list; + list.append(addr); + + return createVCards(list, version); +} + +QByteArray VCardConverter::createVCards(const Addressee::List &list, Version version) const +{ + VCardTool tool; + QByteArray returnValue; + switch (version) { + case v2_1: + returnValue = tool.createVCards(list, VCard::v2_1); + break; + case v3_0: + returnValue = tool.createVCards(list, VCard::v3_0); + break; + case v4_0: + returnValue = tool.createVCards(list, VCard::v4_0); + break; + } + + return returnValue; +} + +Addressee VCardConverter::parseVCard(const QByteArray &vcard) const +{ + Addressee::List list = parseVCards(vcard); + + return list.isEmpty() ? Addressee() : list[ 0 ]; +} + +Addressee::List VCardConverter::parseVCards(const QByteArray &vcard) const +{ + VCardTool tool; + + return tool.parseVCards(vcard); +} + +/* Helper functions */ + +QString KContacts::dateToVCardString(const QDateTime &dateTime) +{ + return dateTime.toString(QStringLiteral("yyyyMMddThhmmssZ")); +} + +QString KContacts::dateToVCardString(QDate date) +{ + return date.toString(QStringLiteral("yyyyMMdd")); +} + +QDateTime KContacts::VCardStringToDate(const QString &dateString) +{ + QDate date; + QTime time; + QString d(dateString); + + d = d.remove(QLatin1Char('-')).remove(QLatin1Char(':')); + + if (d.length() >= 8) { + date = QDate(d.midRef(0, 4).toUInt(), d.midRef(4, 2).toUInt(), d.midRef(6, 2).toUInt()); + } + + if (d.length() > 9 && d[ 8 ].toUpper() == QLatin1Char('T')) { + time = QTime(d.midRef(9, 2).toUInt(), d.midRef(11, 2).toUInt(), d.midRef(13, 2).toUInt()); + } + + return QDateTime(date, time); +} + +void KContacts::adaptIMAttributes(QByteArray &data) +{ + data.replace("X-messaging/aim-All", ("X-AIM")); + data.replace("X-messaging/icq-All", ("X-ICQ")); + data.replace("X-messaging/xmpp-All", ("X-JABBER")); + data.replace("X-messaging/msn-All", ("X-MSN")); + data.replace("X-messaging/yahoo-All", ("X-YAHOO")); + data.replace("X-messaging/gadu-All", ("X-GADUGADU")); + data.replace("X-messaging/skype-All", ("X-SKYPE")); + data.replace("X-messaging/groupwise-All", ("X-GROUPWISE")); + data.replace("X-messaging/sms-All", ("X-SMS")); + data.replace("X-messaging/meanwhile-All", ("X-MEANWHILE")); + data.replace("X-messaging/irc-All", ("X-IRC")); + data.replace("X-messaging/googletalk-All", ("X-GTALK")); +} diff --git a/src/converter/vcardconverter.h b/src/converter/vcardconverter.h new file mode 100644 index 0000000..46d3dba --- /dev/null +++ b/src/converter/vcardconverter.h @@ -0,0 +1,158 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2002 Tobias Koenig + + 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 KCONTACTS_VCARDCONVERTER_H +#define KCONTACTS_VCARDCONVERTER_H + +#include "kcontacts_export.h" +#include "kcontacts/addressee.h" +#include + +namespace KContacts +{ + +/** + @short Class to converting contact objects into vCard format and vice versa. + + This class implements reading and writing of contact using from/to the + vCard format. Currently vCard version 2.1 and 3.0 is supported. + + Example: + + \code + + QFile file( "myfile.vcf" ); + file.open( QIODevice::ReadOnly ); + + QByteArray data = file.readAll(); + + VCardConverter converter; + Addressee::List list = converter.parseVCards( data ); + + // print formatted name of first contact + qDebug( "name=%s", list[ 0 ].formattedName().toLatin1() ); + + \endcode +*/ +class KCONTACTS_EXPORT VCardConverter +{ +public: + + /** + @li v2_1 - VCard format version 2.1 + @li v3_0 - VCard format version 3.0 + @li v4_0 - VCard format version 4.0 + */ + enum Version { + v2_1, + v3_0, + v4_0 + }; + + /** + Constructor. + */ + VCardConverter(); + + /** + Destructor. + */ + ~VCardConverter(); + + /** + Creates a string in vCard format which contains the given + contact. + + @param addr The contact object + @param version The version of the generated vCard format + */ + QByteArray createVCard(const Addressee &addr, Version version = v3_0) const; + + /** + Creates a string in vCard format which contains the given + list of contact. + + @param list The list of contact objects + @param version The version of the generated vCard format + */ + // FIXME: Add error handling + QByteArray createVCards(const Addressee::List &list, Version version = v3_0) const; + + /** + * @since 4.9.1 + */ + QByteArray exportVCard(const Addressee &addr, Version version) const; + + /** + * @since 4.9.1 + */ + QByteArray exportVCards(const Addressee::List &list, Version version) const; + + /** + Parses a string in vCard format and returns the first contact. + */ + Addressee parseVCard(const QByteArray &vcard) const; + + /** + Parses a string in vCard format and returns a list of contact objects. + */ + // FIXME: Add error handling + Addressee::List parseVCards(const QByteArray &vcard) const; + +private: + Q_DISABLE_COPY(VCardConverter) + class VCardConverterPrivate; + VCardConverterPrivate *const d; +}; + +/** + Helper functions + */ + +/** + * Converts a QDateTime to a date string as it is used in VCard and LDIF files. + * The return value is in the form "yyyyMMddThhmmssZ" (e.g. "20031201T120000Z") + * @param dateTime date and time to be converted + */ +KCONTACTS_EXPORT QString dateToVCardString(const QDateTime &dateTime); + +/** + * Converts a QDate to a short date string as it is used in VCard and LDIF files. + * The return value is in the form "yyyyMMdd" (e.g. "20031201") + * @param date date to be converted + */ +KCONTACTS_EXPORT QString dateToVCardString(QDate date); + +/** + * Converts a date string as it is used in VCard and LDIF files to a QDateTime value. + * If the date string does not contain a time value, it will be returned as 00:00:00. + * (e.g. "20031201T120000" will return a QDateTime for 2003-12-01 at 12:00) + * @param dateString string representing the date and time. + */ +KCONTACTS_EXPORT QDateTime VCardStringToDate(const QString &dateString); + +/** + * @brief adaptIMAttributes. Convert KAddressBook attribute to VCard IM Attribute + * @param data + */ +KCONTACTS_EXPORT void adaptIMAttributes(QByteArray &data); + +} +#endif diff --git a/src/countrytransl.map b/src/countrytransl.map new file mode 100644 index 0000000..2810d36 --- /dev/null +++ b/src/countrytransl.map @@ -0,0 +1,5685 @@ +Andorra ad +Андора ad +Андора ad +Andora ad +ອີນເດີຍ ad +Andora ad +Андорра ad +安道尔 ad +United Arab Emirates ae +Vereenigde Arabiese Emirate ae +الإمارات العربية المتحدة ae +Злучаныя Арабскія Эміраты ae +Обединени Арабски Емирства ae +Ujedinjeni arapski emirati ae +Emirats Àrabs Units ae +Spojené arabské emiráty ae +Forenende Arabiske Emirater ae +Vereinigte Arabische Emirate ae +Ενωμένα Αραβικά Εμιράτα ae +Emiratos árabes unidos ae +Araabia Ühendemiraadid ae +Arabiar Emirato Batuak ae +امارات متحده عربی ae +Yhdistyneet Arabiemiraatit ae +Émirats Arabes Unis ae +איחוד האמירויות הערביות ae +Ujedinjeni arapski emirati ae +Egyesült Arab Emirátusok ae +Emirati arabi uniti ae +アラブ首長国連邦 ae +아랍 에미레이트 연합 ae +ສະຫະລັດ ae +Jungtiniai Arabų Emiratai ae +Emirati Għarab Magħquda ae +De forente arabiske emirater ae +Verenigde Arabische Emiraten ae +Dei sameinte arabiske emirata ae +Di-Emirate tseo di Kopanego tsa Arab ae +Zjednoczone Emiraty Arabskie ae +Emiratos Árabes Unidos ae +Emirados Árabes ae +Emiratele Arabe Unite ae +Объединенные Арабские Эмираты ae +Spojené arabské emiráty ae +Združeni arabski Emirati ae +Förenade arabemiraten ae +³ì¸¢Â «ÃÒ ¿¡Î¸û ae +Birleşik Arap Emirlikleri ae +Об'єднані Арабські Емірати ae +Mashango o tangananaho a Emirates ae +阿拉伯联合酋长国 ae +阿拉伯聯合大公國 ae +Izindawo zezinduna zase-United Arab ae +Afghanistan af +Афганістан af +Афганистан af +Afganistan af +Afghanistán af +Afganisztán af +ລີທົ່ວເນີຍ af +Afeganistão af +Afganistan af +Afganistan af +Afganistan af +Афганістан af +阿富汗 af +Antigua and Barbuda ag +Antigue en Barbuda ag +أنتيغوا و باربودا ag +Antigua və Barbuda ag +Антыгуа і Барбуда ag +Антигуа и Барбадос ag +Antigua ha Barbuda ag +Antigua i Barbuda ag +Antigua i Barbuda ag +Antigua a Barbuda ag +Antigua og Barbuda ag +Antigua und Barbuda ag +Antigua και Barbuda ag +Antigvo kaj Barbudo ag +Antigua y Barbuda ag +Antigua ja Barbuda ag +Antigua eta Barbuda ag +آنتیگوا و باربودا ag +Antigua ja Barbados ag +Antigua og Barbuda ag +Antigua et Barbuda ag +Antiga e Barbuda ag +אנטיגואה וברבודה ag +Antigua i Barbuda ag +Antigua és Barbuda ag +Antigua dan Barbuda ag +Antigúa og Barbúda ag +Antigua e Barbuda ag +アンティグアバーブーダ ag +앤티가 바부다 ag +Antikva ir Barbuda ag +Antigva un Barbudas ag +Antigwa u Barbuda ag +Antigua og Barbuda ag +Antigua en Barbuda ag +Antigua og Barbuda ag +Antigua le Barbuda ag +Antigua e Barbuda ag +Antigua i Barbuda ag +Antigua e Barbuda ag +Antigua e Barbuda ag +Antigua şi Barbuda ag +Антигуа и Барбадос ag +Antigua a Barbuda ag +Antigva in Barbuda ag +Antigua i Barbuda ag +I-Antigua kanye ne Barbuda ag +Antigua och Barbuda ag +¬ýÊÌÅ¡ & À¡÷Ò¼¡ ag +Antigua ve Barbuda ag +Трінідад та Тобаго ag +Antigua và Barbuda ag +Antigua eyet Barbuda ag +Antigua ne Barbuda ag +安地瓜岛和巴布达岛 ag +安地瓜島和巴布達島 ag +Antigua kanye ne-Barbuda ag +Anguilla ai +Ангуила ai +ແພນວິນ ai +Angvila ai +Ангілья ai +安圭拉 ai +Albania al +Альбанія al +Албания al +Albanija al +Albanien al +Albánia al +ແອດແລນຕິກ al +Albânia al +Albánsko al +Albanija al +Albanien al +Албанія al +阿尔巴尼亚 al +Armenia am +Армэнія am +Армения am +Armenija am +Armenien am +Örményország am +ອາເຈນຕິນາ am +Armênia am +Arménsko am +Armenija am +Armenien am +Арменія am +亚美尼亚 am +Netherlands Antilles an +Холандски Антили an +Nizozemski Antili an +Nederlandske antiller an +Antillas holandesas an +Antilla Holandarrak an +Holland-Antillák an +ເນເທີແລນ an +Antilhas an +Holandské Antily an +Nizozemski Antili an +Nederländska Antillerna an +Голландські Антилли an +荷属安的列斯群岛 an +Angola ao +Ангола ao +Ангола ao +ບັນແກເລີຍ ao +Ангола ao +安哥拉 ao +Argentina ar +Argentinië ar +الأرجنتين ar +Аргентына ar +Аржентина ar +Arc'hantina ar +Argentinien ar +Αργεντινή ar +Argentino ar +Argentiina ar +آرژانتین ar +Agentiina ar +Argentine ar +Arxentina ar +ארגנטינה ar +Argentína ar +Argentína ar +アルゼンチン ar +아르헨티나 ar +ອາເຈນຕິນາ ar +ArgentÄ«na ar +ArÄ¡entina ar +Argentinië ar +Argentyna ar +Аргентина ar +Argentína ar +I-Argentina ar +¬÷¦ºƒýÊÉ¡ ar +อาร์เจนตินา ar +Arjantin ar +Аргентина ar +Agenthina ar +Årdjintene ar +阿根廷 ar +阿根廷 ar +American Samoa as +Амэрыканскае Самоа as +Американска Самоа as +Američka Samoa as +Samoa (USA) as +Samoa americana as +Amerikako Samoa as +Amerikai Szamoa as +ອາເມລິກາເຫນືອ as +Samoa Americana as +Americká Samoa as +AmeriÅ¡ka Samoa as +Amerikanska Samoa as +Американське Самоа as +美属萨摩亚群岛 as +Austria at +Oostenryk at +النمسا at +Avstriya at +Аўстрыя at +Австрия at +Aostria at +Austrija at +Àustria at +Rakousko at +Østrig at +Österreich at +Αυστρία at +AÅ­strio at +اتریش at +Itävalta at +Eysturríki at +Autriche at +אוסטריה at +Austrija at +Ausztria at +Austurríki at +オーストリア at +오스트리아 at +ອອດສະເຕເລີຍ at +Austrija at +Austrija at +Awtrija at +Østerrike at +Oostenrijk at +Austerrike at +Áustria at +Áustria at +Австрия at +Rakúsko at +Avstrija at +Austrija at +I-Austria at +Österrike at +¬Íò¾¢Ã¢Â¡ at +ออสเตรีย at +Avusturya at +Австрія at +Ositiria at +A'o at +Ôtriche at +奥地利 at +奧地利 at +Australia au +Australië au +أستراليا au +Avustralya au +Аўстралія au +Австралия au +Aostralia au +Australija au +Austràlia au +Austrálie au +Australien au +Australien au +Αυστραλία au +AÅ­stralio au +Austraalia au +استرالیا au +Australie au +אוסטרליה au +Australija au +Ausztrália au +Ástralía au +オーストラリア au +오스트레일리아 au +ອອດສະເຕເລີຍ au +Australija au +Austrālija au +Awstralja au +Australië au +Austrália au +Austrália au +Австралия au +Austrália au +Avstralija au +Australija au +I-Australia au +Australien au +¬ŠÍò¾¢§ÃĢ¡ au +ออสเตรเลีย au +Avusturalya au +Австралія au +Ositiralia au +U'c au +Ôstraleye au +澳大利亚 au +澳大利亞 au +Aruba aw +Аруба aw +ເກມໄັພ່ aw +Аруба aw +阿鲁巴岛 aw +Azerbaijan az +أذربيجان az +Azərbaycan az +Азэрбайджан az +Азарбайджан az +Azerbejdžan az +Azerbaitjan az +Ázerbajdžánský az +Azerbajdjan az +Aserbaidschan az +Αζερμπαϊτζάν az +Azerbajĝana az +Azerbaiján az +Aserbaidžaan az +آذربایجان az +Azerbaidzan az +Aserbadsjan az +אזרביג'ן az +Azerbejdžan az +Azerbajdzsán az +Azerbaigian az +アゼルバイジャン az +아제르바이잔 az +ອາເຊີໄບຈັນ az +Azerbaidžanas az +Azerbaidžāņu az +AżerbajÄ¡an az +Aserbajdsjan az +Azerbeidjan az +Aserbajdsjan az +Azerbejdżan az +Azerbaijão az +Turco az +Azerbadjan az +Азербайджан az +Ázerbajdžánsky az +Azerbajdžan az +Azerbejdžan az +I-Azerbaijan az +«º÷¨Àº¡ý az +อาร์เซอร์ไบจัน az +Azerice az +Азербайджан az +Azerbaydjan az +阿塞拜疆 az +亞塞拜然 az +Bosnia and Herzegovina ba +Bosnië en Herzegovina ba +البوسنا و الهرسك ba +Босьнія і Герцагавіна ba +Боснена и Херцеговина ba +Bosna i Hercegovina ba +Bòsnia i Hercegovina ba +Bosna a Herzegovina ba +Bosnien-Herzegovina ba +Bosnien und Herzegowina ba +Βοσνία και Ερζεγοβίνη ba +Bosnio kaj Hercegovino ba +Bosnia y Herzegovina ba +Bosnia ja Hertsegovina ba +Bosnia eta Herzegovina ba +بوسنی و هرزگوین ba +Bosnia ja Herzegovina ba +Bosnia-Herzegovina ba +Bosnie herzégovine ba +בוסניה הרצגובינה ba +Bosna i Hercegovina ba +Bosznia-Hercegovina ba +Bosnia e Erzegovina ba +ボスニアヘルツェゴビナ ba +보스니아어와 헤르체고비나 ba +ບອສເນີຍ ແລະ ເຫີເຊີໂກວິນາ ba +Bosnija ir Hercegovina ba +Bosnija un Hercogovina ba +Bożnia u Ħerżegovina ba +Bosnia-Hercegovina ba +Bosnië en Herzegovina ba +Bosnia-Hercegovina ba +Bosnia le Herzegovina ba +Bośnia i Hercegowina ba +Bósnia e Herzegovina ba +Bósnia Herzegóvina ba +Bosnia şi HerÅ£egovina ba +Босния и Герцеговина ba +Bosna a Hercegovina ba +Bosna in Hercegovina ba +I-Bosnia kanye ne Herzegovina ba +Bosnien och Herzegovina ba +¦À¡Íɢ¡ ba +บอสเนีย และ เฮอร์เซโกวินา ba +Bosna Hersek ba +Боснія та Герцеговина ba +Mubosinia na Muhezegovina ba +Bosneye ba +Bosnia ne Herzegovina ba +波斯尼亚和黑塞哥维那 ba +波士尼亞與赫塞哥維納 ba +Bosnia kanye ne-Herzegovina ba +Barbados bb +بربادوس bb +Барбадос bb +Барбадос bb +Μπαρμπάντος bb +Babadoso bb +باربادوس bb +Barbade bb +ברבדוס bb +バルバドス bb +바르바도스 bb +ບາລບາດອດສ bb +Barbadosas bb +Barbadosa bb +Барбадос bb +I-Barbados bb +À¡÷§À¼¡Í bb +บาร์บาดอส bb +Барбадос bb +Barbades bb +巴巴多斯 bb +巴貝多 bb +Bangladesh bd +بنغلاديش bd +Banqladeş bd +Банглядэш bd +Бангладеш bd +BangladeÅ¡ bd +Bangladéš bd +Bangladesch bd +Μπαγκλαντές bd +Bangladeŝo bd +بنگلادش bd +בנגלדש bd +BangladeÅ¡ bd +Banglades bd +バングラデシュ bd +방글라데시 bd +ບັງຄະລາເທດ bd +BangladeÅ¡as bd +BangladeÅ¡a bd +Bangladexx bd +Bangladesz bd +Banglade bd +Бангладеш bd +Bangladéš bd +BangladeÅ¡ bd +I-Bangladesh bd +Àí¸Ç¡§¾Í bd +บังคลาเทศ bd +Bangladeş bd +Бангладеш bd +孟加拉 bd +孟加拉 bd +Belgium be +België be +بلجيكا be +Belçika be +Бэльгія be +Белгия be +Belgia be +Belgija be +Bèlgica be +Belgie be +Belgien be +Belgien be +Βέλγιο be +Belgio be +Bélgica be +Belgia be +Belgika be +بلژیک be +Belgia be +Belgia be +Belgique be +Bélxica be +בלגיה be +Belgija be +Belgia be +Belgía be +Belgio be +ベルギー be +벨기에 be +ເບລຢ່ງມ be +Belgija be +Beļģija be +BelÄ¡ju be +Belgia be +België be +Belgia be +Bèlgica be +Belgia be +Bélgica be +Bélgica be +Belgia be +Бельгия be +Belgicko be +Belgija be +Belgija be +I-Belgium be +Belgien be +¦Àøº¢Âõ be +เบลเยียม be +Belçika be +Бельгія be +Beljike be +比利时 be +比利時 be +Burkina Faso bf +Буркіна Фасо bf +Буркина Фаско bf +ຕຸລະກີ bf +Буркіна Фасо bf +布基纳法索 bf +Bulgaria bg +Bulgarye bg +بلغاريا bg +Bolgarıstan bg +Баўгарыя bg +България bg +Bugarska bg +Bulgària bg +Bulharsko bg +Bulgarien bg +Bulgarien bg +Βουλγαρία bg +Bulgario bg +Bulgaaria bg +بلغارستان bg +Bulgarie bg +בולגריה bg +Bugarska bg +Bulgária bg +Búlgaría bg +ブルガリア bg +불가리아 bg +ບັນແກເລີຍ bg +Bulgarija bg +Bulgārija bg +Bulgarija bg +Bulgarije bg +Bułgaria bg +Bulgária bg +Bulgária bg +Болгария bg +Bulharsko bg +Bolgarija bg +Bugarska bg +I-Bulgaria bg +Bulgarien bg +Àø§¸Ã¢Â¡ bg +บัลแกเรีย bg +Bulgaristan bg +Болгарія bg +Baligaria bg +BulgÃ¥reye bg +保加利亚 bg +保加利亞 bg +Bahrain bh +البحرين bh +Бахрэйн bh +Бахрейн bh +Bahrein bh +Bahrajn bh +Μπαχρέιν bh +Bahrein bh +Bahrein bh +بحرین bh +בחריין bh +バーレーン bh +바레인 bh +ຖັກກ່ງວ bh +Bahreinas bh +Baħrain bh +Baghrein bh +Bahrajn bh +Bahamas bh +Bahrein bh +Бахрейн bh +Bahrajn bh +Bahrajn bh +I-Bahrain bh +Bahrein bh +À‹¨Ãý bh +Bahreyn bh +Бахрейн bh +巴林 bh +巴林 bh +Burundi bi +Бурундзі bi +Бурунди bi +ເຄອຣດ bi +Бурунді bi +布隆迪 bi +Benin bj +Бэнін bj +Бенин bj +ບອສເນີຍ bj +Бенін bj +贝宁 bj +Bermuda bm +Бэрмуды bm +Бермуда bm +ເຍລລະມັນ bm +Bermudy bm +Bermudi bm +Бермуди bm +百慕大 bm +Brunei Darussalam bn +Брунэй bn +Бруней bn +Brunei bn +Brunei Szultánság bn +ເບລາລັສເຊີຍ bn +Brunei bn +Brunei Darusalam bn +Бруней Даруссалам bn +Bolivia bo +Bolivië bo +بوليفيا bo +Boliviya bo +Балівія bo +Боливия bo +Bolivija bo +Bolívia bo +Bolívie bo +Bolivien bo +Βολιβία bo +Bolivio bo +Boliivia bo +بولیوی bo +Bolivie bo +בוליביה bo +Bolivija bo +Bolívia bo +Bólivía bo +ボリビア bo +볼리비아 bo +ໂບລີເວີຍ bo +Bolivija bo +BolÄ«vija bo +Bolivja bo +Boliwia bo +Bolívia bo +Bolívia bo +Боливия bo +Bolívia bo +Bolivija bo +Bolivija bo +I-Bolivia bo +¦À¡Ä¢Å¢Â¡ bo +โบลิเวีย bo +Bolivya bo +Болівія bo +Boliveye bo +波利维亚 bo +玻利維亞 bo +Brazil br +Brazilië br +البرازيل br +Braziliya br +Бразылія br +Бразилия br +Brasil br +Brazílie br +Brasilien br +Brasilien br +Βραζιλία br +Brazilo br +Brasil br +Brasiilia br +Brasil br +برزیل br +Brasilia br +Brésil br +Brasil br +ברזיל br +Brazília br +Brasilía br +Brasile br +ブラジル br +브라질 br +ບາຊີລ br +Brazilija br +BrazÄ«lija br +Brażil br +Brasil br +Brazilië br +Brasil br +Brasil br +Brazylia br +Brasil br +Brasil br +Brazilia br +Бразилия br +Brazília br +Brazilija br +I-Brazil br +Brasilien br +À¢§Ãº¢ø br +บราซิล br +Brezilya br +Бразилія br +Burazili br +Braezi br +巴西 br +巴西 br +Bahamas bs +Багамы bs +Бахами bs +Bahami bs +Bahamák bs +ປານາມາ bs +Bahamy bs +Bahami bs +Багами bs +巴哈马 bs +Bhutan bt +Бутан bt +Бутан bt +Butan bt +Bhután bt +Bhután bt +ຖັກກ່ງວ bt +Butan bt +Бутан bt +不丹 bt +Botswana bw +Батсвана bw +Боцвана bw +Bocvana bw +ບອດສເນີຍ bw +Botsvana bw +Ботсвана bw +博茨瓦纳 bw +Belarus by +روسيا البيضاء by +Беларусь by +Беларус by +Bjelorusija by +Bělorusko by +Hviderusland by +Weißrussland by +Bjelorusio by +Valgevene by +بلاروس by +Valkovenäjä by +Hvítarusland by +Bélarus by +בלרוס by +Bjelorusija by +Fehéroroszország by +Hvíta-Rússland by +Bielorussia by +ベラルーシ by +벨라루스 by +ເບລາລັສ by +Baltarusija by +Baltkrievu by +Hviterussland by +Wit-Rusland by +Kviterussland by +Białoruś by +Bielorússia by +Bielorusso by +Беларусь by +Bielorusko by +Belorusija by +I-Belarus by +Vitryssland by +¦ÀÄ¡åÍ by +เบลารัส by +Білорусія by +Belaruss by +白俄罗斯 by +白俄羅斯 by +Belize bz +Бэлізе bz +Белиз bz +ເບລຍ່ງມ bz +Беліз bz +伯利兹 bz +Default C +Verstek C +افتراضي C +Əsas C +Па ўмаўчаньні C +По подразбиране C +Dre ziouer C +Omissió C +Výchozí C +Standard C +Standard C +Προκαθορισμένο C +Apriora C +Predeterminado C +Vaikimisi C +Aurremugatua C +پیش‌فرض C +Oletus C +Forsettur C +Par défaut C +Por Omisión C +ברירת מחדל C +Uobičajeno C +Alapértelmezett C +Standar C +Sjálfgefið C +Predefinito C +標準 C +기본 C +ຄ່າປະລິຍາຍ C +Nutylima C +Noklusētais C +Normali C +Standard C +Standaard C +Standard C +Thuso ya Tshoganetso C +Omission C +Domyślnie C +Por Omissão C +Padrão C +Implicit C +По умолчанию C +Å tandardný C +Privzeto C +Predefinisano C +Förval C +¦¸¡¼¡¿¢¨Ä C +ค่าปริยาย C +Öntanımlı C +Типовий C +Mặc định C +Prémetou C +Okwendalo C +默认 C +預設 C +Okwendalo C +Canada ca +Kanada ca +كندا ca +Kanada ca +Канада ca +Канада ca +Kanada ca +Kanada ca +Canadà ca +Kanada ca +Kanada ca +Καναδάς ca +Kanado ca +Canadá ca +Kanada ca +Kanada ca +کانادا ca +Kanada ca +Kanada ca +Canadá ca +קנדה ca +Kanada ca +Kanada ca +Kanada ca +Kanada ca +カナダ ca +캐나다 ca +ແຄນາດາ ca +Kanada ca +Kanāda ca +Kanada ca +Kanada ca +Canadá ca +Canadá ca +Канада ca +Kanada ca +Kanada ca +Kanada ca +I-Canada ca +Kanada ca +¸É¼¡ ca +แคนาดา ca +Kanada ca +Канада ca +加拿大 ca +加拿大 ca +Cocos (Keeling) Islands cc +Кокосови Острови cc +Kokosovo (Keeling) ostrvo cc +Islas Cocos (Keeling) cc +Koko Irlak cc +Kókusz-szigetek (Keeling) cc +Ilhas Cocos cc +Kokosove Ostrovy cc +Kokosovi (Keelingovi) otoki cc +Kokosöarna cc +Кокосові острови cc +Congo, the democratic republic of the cd +Дэмакратычная Рэспубліка Конга cd +Конго cd +Kongo, demokratska republika cd +Congo, den demokratiske republik cd +Congo, república democrática del cd +Kongo, errepublika demokratikoa cd +Kongói Demokratikus Köztársaság cd +República Democrática do Congo cd +Demokratická Republika Kongo cd +Kongo, demokratična republika cd +Demokratiska republiken Kongo cd +刚果民主共和国 cd +Central African Republic cf +ЦАР cf +Centralnoafrička Republika cf +Central-afrikanske Republik cf +República Centroafricana cf +Afrika Erdiko Errepublika cf +Közép-Afrikai Köztársaság cf +ໂດມິນິກັນ cf +República da África Central cf +Stredoafrická Republika cf +CentralnoafriÅ¡ka republika cf +Centralafrikanska Republiken cf +Центральноафриканська республіка cf +中非共和国 cf +Congo cg +Конга cg +Конго cg +Kongo cg +Kongo cg +Kongó cg +ຄອນໂໍຊລ cg +Kongo cg +Kongo cg +Kongo cg +Конго cg +刚果 cg +Switzerland ch +Switserland ch +سويسرا ch +İsveçrə ch +Швэйцарыя ch +Швейцария ch +Suis ch +Å vicarska ch +Suïssa ch +Å výcarsko ch +Schweiz ch +Schweiz ch +Ελβετία ch +Svislando ch +Suiza ch +Å veits ch +Suitza ch +سوییس ch +Sveitsi ch +Suisse ch +Suíza ch +שוייץ ch +Å vicarska ch +Svájc ch +Swiss ch +Sviss ch +Svizzera ch +スイス ch +스위스 ch +ສະວິສເຊີແລນ ch +Å veicarija ch +Å veice ch +Svizzera ch +Sveits ch +Zwitserland ch +Sveits ch +Suissa ch +Szwajcaria ch +Suíça ch +Suíça ch +ElveÅ£ia ch +Швейцария ch +Å vajčiarsko ch +Å vica ch +Å vajcarska ch +I-Switzerland ch +Schweiz ch +ÍÅ¢ðº÷Ä¡óÐ ch +สวิสเซอร์แลนด์ ch +İsviçre ch +Швейцарія ch +Thuỵ SÄ© ch +Swisse ch +瑞士 ch +瑞士 ch +Cote d'ivoire ci +Бераг Слановай Косьці ci +Кот'Дивоар ci +Obala Slonovače ci +Elfenbenskysten ci +Costa de Marfil ci +Elefántcsontpart ci +ປ່ອຍຫມາກກະລອກ ci +Slonokoščena obala ci +Elfenbenskusten ci +Кот д'Івуар ci +Cook islands ck +Kukova ostrva ck +Cook-øerne ck +Islas Cook ck +Cook Irlak ck +Cook-szigetek ck +ຄຸກກີ້ ck +Ilhas Cook ck +Cookove ostrovy ck +Cookovi otoki ck +Cooköarna ck +Острови Кука ck +库克群岛 ck +Chile cl +Chilië cl +تشيلي cl +Şili cl +Чылі cl +Чили cl +Čile cl +Xile cl +Χιλή cl +Ĉilio cl +TÅ¡iili cl +Txile cl +شیلی cl +Chili cl +צ'ילה cl +Čile cl +Chili cl +Cile cl +チリ cl +칠레 cl +ຊີລີ cl +Čilė cl +Čīle cl +Ċile cl +Chili cl +Cile cl +Чили cl +Čile cl +Čile cl +Čile cl +I-Chile cl +º¢Ä¢ cl +ชิลี cl +Şili cl +Чилі cl +Chi lê cl +Tchili cl +智利 cl +智利 cl +Cameroon cm +Камэрун cm +Камерун cm +Kamerun cm +Cameroun cm +Camerún cm +Kamerun cm +Kamerun cm +ຕາລາງງານ - K cm +Camarões cm +Komerun cm +Kamerun cm +Kamerun cm +Камерун cm +喀麦隆 cm +China cn +Sjina cn +الصين cn +Çin cn +Кітай cn +Китай cn +Sina cn +Kina cn +Xina cn +Čína cn +Kina cn +Κίνα cn +Ĉinujo cn +Hiina cn +Txina cn +چین cn +Kiina cn +Kina cn +Chine cn +סין cn +Kina cn +Kína cn +Cina cn +Kína cn +Cina cn +中国 cn +중국 cn +ຈີນ cn +Kinija cn +Ķīna cn +Ċina cn +Kina cn +Kina cn +Xina cn +Chiny cn +Китай cn +Čína cn +Kitajska cn +Kina cn +I-China cn +Kina cn +º£É¡ cn +จีน cn +Çin cn +Китай cn +Trung Quốc cn +Chine cn +中国 cn +中國 cn +Colombia co +Colombië co +كولمبيا co +Калюмбія co +Колумбия co +Kolumbija co +Colòmbia co +Kolumbie co +Kolumbien co +Κολομβία co +Kolumbio co +Kolumbia co +Kolonbia co +کلمبیا co +Kolumbia co +Colombie co +קולומביה co +Kolumbija co +Kolumbia co +コロンビア co +콜롬비아 co +ໂຄລຳເບີຍ co +Kolumbija co +Kolumbija co +Kolumbja co +Columbia co +Kolumbia co +Colômbia co +Colômbia co +Columbia co +Колумбия co +Kolumbia co +Kolumbija co +I-Colombia co +¦¸¡ÄõÀ¢Â¡ co +โคลัมเบีย co +Kolombiya co +Колумбія co +Colombeye co +Columbia co +哥伦比亚 co +哥倫比亞 co +Costa Rica cr +كوستاريكا cr +Коста Рыка cr +Коста Рика cr +Kostarika cr +Kostarika cr +Κόστα Ρίκα cr +کاستاریکا cr +Kosta Rika cr +קוסטה ריקה cr +Costa rica cr +コスタリカ cr +코스타 리카 cr +ໂຄເອເທີຍ cr +Kosta Rika cr +Kostaryka cr +Коста-Рика cr +Kostarika cr +Kostarika cr +I-Costa Rica cr +§¸¡Š¼¡ ⸡ cr +Kosta Rika cr +Коста-Ріка cr +哥斯达黎加 cr +哥斯大黎加 cr +Cuba cu +Kuba cu +كوبا cu +Куба cu +Куба cu +Kuba cu +Kuba cu +Kuba cu +Κούβα cu +Kuuba cu +Kuba cu +کوبا cu +Kuuba cu +Kuba cu +קובה cu +Kuba cu +キューバ cu +쿠바 cu +ເກມໄພ່ cu +Kuba cu +Kuba cu +Kuba cu +Куба cu +Kuba cu +Kuba cu +I-Cuba cu +Kuba cu +¸¢ÔÀ¡ cu +Küba cu +Куба cu +古巴 cu +古巴 cu +Cape Verde cv +Капе Верде cv +Zelenortska ostrva cv +Kapverdiske øer cv +Cabo Verde cv +Cabo Verde cv +Zöldfoki-szigetek cv +ເກມໄພ່ cv +Cabo Verde cv +Kap Verde cv +佛得角 cv +Christmas Island cx +Božično ostrvo cx +Juleøen cx +Islas Christmas cx +Eguberri Irla cx +Karácsony-szigetek cx +ຄິດສະຕອລ cx +Ilhas do Natal cx +Vianočné Ostrovy cx +Božični otok cx +Julön cx +Острів Різдва cx +圣诞岛 cx +Cyprus cy +Кіпр cy +Кипър cy +Kipar cy +Cypern cy +Chipre cy +Txipre cy +Ciprus cy +ບີບອັດ cy +Chipre cy +Ciper cy +Cypern cy +Кипр cy +塞浦路斯 cy +Czechia cz +Czechië cz +التشيك cz +Çex Respublikası cz +Чэхія cz +Чехия cz +Tchekia cz +ČeÅ¡ka cz +Txèquia cz +Česko cz +Tjekkiet cz +Tschechien cz +Τσεχία cz +ĈeÄ¥io cz +República Checa cz +TÅ¡ehhi cz +Txekia cz +چک cz +Tsekki cz +République tchèque cz +Chequia cz +צ'כיה cz +ČeÅ¡ka cz +Csehország cz +Tékkland cz +Repubblica Ceca cz +チェコ cz +체코 cz +Čekija cz +Čehija cz +Cżekia cz +Tsjekkia cz +Tsjechië cz +Tsjekkia cz +Chèquia cz +Czechy cz +República Checa cz +República Tcheca cz +Cehia cz +Чехия cz +Česko cz +ČeÅ¡ka cz +ČeÅ¡ka cz +I-Czechia cz +Tjeckien cz +¦ºì¡ cz +Çek Cumhuriyeti cz +Чехія cz +Séc cz +Tchekeye cz +捷克 cz +捷克 cz +Germany de +Duitsland de +ألمانيا de +Almaniya de +Нямеччына de +Германия de +Alamagn de +Njemačka de +Alemanya de +Německo de +Tyskland de +Deutschland de +Γερμανία de +Germanio de +Alemania de +Saksamaa de +Alemania de + آلمان de +Saksa de +Týskland de +Allemagne de +Alemaña de +גרמניה de +Njemačka de +Németország de +Jerman de +Þýskaland de +Germania de +ドイツ de +독일 de +ເຍລລະມັນນີ de +Vokietija de +Vācija de +Ä ermanja de +Tyskland de +Duitsland de +Tyskland de +Alemanya de +Niemcy de +Alemanha de +Alemanha de +Germania de +Германия de +Nemecko de +Nemčija de +Nemačka de +I-Germany de +Tyskland de +§º÷ÁÉ¢ de +เยอรมันนี de +Almanya de +Німеччина de +Đức de +Almagne de +德国 de +德國 de +IJalimani de +Djibouti dj +جيبوتي dj +Джыбуці dj +Джибути dj +Đibuti dj +Džibuti dj +Dschibuti dj +Τζιμπουτί dj +جیبوتی dj +ג'יבוטי dj +Džibuti dj +Dzsibuti dj +ジブティ dj +지부티 dj +ພັດພາ dj +Džibuti dj +DÄ¡ibuti dj +Dżibuti dj +Djibuti dj +Djibuti dj +Джибути dj +Džibuty dj +Džibuti dj +I-Djibouti dj +Ê¢ƒ¢¦À¡Ê dj +Cibuti dj +Джібуті dj +吉布提 dj +吉布地 dj +Denmark dk +Denemarke dk +الدنمارك dk +Danimarka dk +Данія dk +Дания dk +Danmark dk +Danska dk +Dinamarca dk +Dánsko dk +Danmark dk +Dänemark dk +Δανία dk +Danlando dk +Dinamarca dk +Taani dk +Danimarka dk +دانمارک dk +Tanska dk +Danmark dk +Danemark dk +Dinamarca dk +דנמרק dk +Danska dk +Dánia dk +Danmörk dk +Danimarca dk +デンマーク dk +덴마크 dk +ເດນມາກ dk +Danija dk +Dānija dk +Danimarka dk +Danmark dk +Denemarken dk +Danmark dk +Dinamarca dk +Dania dk +Dinamarca dk +Dinamarca dk +Danemarca dk +Дания dk +Dánsko dk +Danska dk +Danska dk +I-Denmark dk +Danmark dk +¦¼ýÁ¡÷ì dk +เดนมาร์ก dk +Danimarka dk +Данія dk +Đan Mạch dk +DaenmÃ¥tche dk +丹麦 dk +丹麥 dk +Dominica dm +Дамініка dm +Доминика dm +Dominika dm +Dominika dm +ໂລມາເນີຍ dm +Dominicana dm +Dominikánsko dm +Dominikanska republika dm +Домініка dm +多米尼加 dm +Dominican Republic do +Dominikiese Republiek do +جمهورية الدومينيكان do +Dominik Respublikası do +Дамініканская Рэспубліка do +Доминиканска република do +Republik Dominikan do +Dominikanska Republika do +República Dominicana do +Dominikánská republika do +Dominikanske Republik do +Dominikanische Republik do +Δομινικανή Δημοκρατία do +Dominika Respubliko do +República Dominicana do +Dominikaani Vabariik do +Dominikar Errepublika do +جمهوری دامینیکن do +Dominikaaninen tasavalta do +République dominicaine do +República Dominicana do +הרפובליקה הדומיניקנית do +Dominikanska Republika do +Dominikai Köztársaság do +Republik Dominika do +Dóminíska Lýðveldið do +Repubblica Dominicana do +ドミニカ共和国 do +도미니카 공화국 do +ໂດມິນີກັນ do +Dominikos Respublika do +Dominikas Republika do +Repubblika Dominikana do +Den dominikanske republikk do +Dominicaanse Republiek do +Den dominikanske republikken do +Republica Dominicana do +Dominikana do +República Dominicana do +República Dominicana do +Republica Dominicană do +Доминиканская республика do +Dominikánska republika do +Dominikanska republika do +Dominikanska republika do +I-Dominican Republic do +Dominikanska republiken do +¦¼¡Á¢É¢ì¸ý ÌÊÂÃÍ do +โดมินิกัน do +Dominik Cumhuriyeti do +Домініканська республіка do +Muvhuso wa Dominican do +Cộng hoà Dominican do +Republike Dominikinne do +IRepublic yeDominican do +多米尼加共和国 do +多明尼加共和國 do +Algeria dz +Algerië dz +الجزائر dz +Альжыр dz +Алжир dz +Alžir dz +Algèria dz +Alžírsko dz +Algeriet dz +Algerien dz +Αλγερία dz +Algerio dz +Argelia dz +Alžeeria dz + الجزیره dz +Algérie dz +אלג'יריה dz +Alžir dz +Algéria dz +アルジェリア dz +알제리 dz +ບັນກາເລີຍ dz +Alžyras dz +AlÄ¡erija dz +Algerie dz +Algerije dz +Algerie dz +Algieria dz +Argélia dz +Argélia dz +Алжир dz +Alžírsko dz +Alžirija dz +I-Algeria dz +Algeriet dz +«øƒ¢Ã¢Â¡ dz +Алжир dz +Aldjereye dz +阿尔及利亚 dz +阿爾及利亞 dz +Equador ec +Ewenaar ec +الإكوادور ec +Ekvator ec +Эквадор ec +Еквадор ec +Ecuador ec +Ekvador ec +Ekvádor ec +Ecuador ec +Ισημερινός ec +Ekvadoro ec +Ecuador ec +Ekvador ec +Ekuador ec +اکوادور ec +Équateur ec +Ecuador ec +אקוודור ec +Ekvador ec +Ecuador ec +Ekvador ec +Ecuador ec +エクアドル ec +에콰도르 ec +ເອກໍດໍ ec +Ekvadoras ec +Ekvadora ec +Ekwador ec +Ecuador ec +Ecuador ec +Ekwador ec +Ecuador ec +Эквадор ec +Ekvádor ec +Ekvador ec +Ekvador ec +I-Equador ec +®ì¦Å§¼¡÷ ec +เอกวาดอร์ ec +Ekvator ec +Еквадор ec +EcwÃ¥teur ec +厄瓜多尔 ec +厄瓜多 ec +Estonia ee +Estlandies ee +استونيا ee +Estoniya ee +Эстонія ee +Естония ee +Estonija ee +Estònia ee +Estonsko ee +Estland ee +Estland ee +Εσθονία ee +Estlando ee +Eesti ee +استونی ee +Eesti ee +Estonie ee +אסטוניה ee +Estonija ee +Észtország ee +Eistland ee +エストニア ee +에스토니아 ee +ເອໂທເນີຍ ee +Estija ee +Igaunija ee +Estonja ee +Estland ee +Estland ee +Estland ee +Estònia ee +Estónia ee +Estônia ee +Эстония ee +Estónsko ee +Estonija ee +Estonija ee +I-Estonia ee +Estland ee +±Í§¼¡É¢Â¡ ee +เอสโธเนีย ee +Estonya ee +Естонія ee +Estoneye ee +爱沙尼亚 ee +愛沙尼亞 ee +Egypt eg +Egipte eg +مصر eg +Misir eg +Эгіпэт eg +Египет eg +Egipat eg +Egipte eg +Egypten eg +Ägypten eg +Αίγυπτος eg +Egiptujo eg +Egipto eg +Egiptus eg +Egypto eg +مصر eg +Egypti eg +Egyptaland eg +Égypte eg +מצרים eg +Egipat eg +Egyiptom eg +Egyptaland eg +Egitto eg +エジプト eg +이집트 eg +ອີຢີບ eg +Egiptas eg +Ēģipte eg +EÄ¡ittu eg +Egypte eg +Egepeta eg +Egipt eg +Egipto eg +Egito eg +Egipt eg +Египет eg +Egipt eg +I-Egypt eg +Egypten eg +±¸¢ôÐ eg +อียิปต์ eg +Mısır eg +Єгипет eg +Edjipe eg +埃及 eg +埃及 eg +Igibhithe eg +Western Sahara eh +Западна Сахара eh +Zapadna Sahara eh +Vestsahara eh +Sahara occidental eh +Mendebaldeko Sahara eh +Nyugat-Szahara eh +ພື້ນທີ່ທຳງານ eh +Sahara eh +Západna Sahara eh +Zahodna Sahara eh +Västsahara eh +Західна Сахара eh +西撒哈拉 eh +Eritrea er +Эрытрэя er +Еритрея er +Eritreja er +ແກ້ໄຂແຟ້ມທຳງານ er +Eritreja er +Еритрея er +厄立特里亚 er +Spain es +Spanje es +أسبانيا es +İspaniya es +Гішпанія es +Испания es +Spagn es +Å panija es +Espanya es +Å panělsko es +Spanien es +Spanien es +Ισπανία es +Hispanio es +España es +Hispaania es +Espainia es +اسپانیا es +Espanja es +Spania es +Espagne es +España es +ספרד es +Å panjolska es +Spanyolország es +Spanyol es +Spánn es +Spagna es +スペイン es +스페인 es +ສະເປັນ es +Ispanija es +Spānija es +Spanja es +Spania es +Spanje es +Spania es +Espanha es +Hiszpania es +Espanha es +Espanha es +Spania es +Испания es +Å panielsko es +Å panija es +Å panija es +I-Spain es +Spanien es +ͦÀ¢ý es +สเปน es +İspanya es +Іспанія es +Tây Ban Nha es +Sipagne es +西班牙 es +西班牙 es +Ethiopia et +Этыёпія et +Етиопия et +Etiopija et +Ethiopien et +Etiopía et +Etiopia et +Etiópia et +ເອໂທເນີຍ et +Etiópia et +Etiópia et +Etiopija et +Etiopien et +Ефіопія et +埃塞俄比亚 et +Finland fi +فنلندا fi +Finlandiya fi +Фінляндыя fi +Финландия fi +Finska fi +Finlàndia fi +Finsko fi +Finnland fi +Φινλανδία fi +Finlando fi +Finlandia fi +Soome fi +Finlandia fi +فنلاند fi +Suomi fi +Finnland fi +Finlande fi +Finlandia fi +פינלנד fi +Finska fi +Finnország fi +Finlandia fi +Finnland fi +Finlandia fi +フィンランド fi +핀란드 fi +ຟີນແລນ fi +Suomija fi +Somija fi +Finlandja fi +Finlandia fi +Finlandia fi +Finlândia fi +Finlândia fi +Finlanda fi +Финляндия fi +Fínsko fi +Finska fi +Finska fi +I-Finland fi +À¢ýÄ¡óÐ fi +ฟินแลนด์ fi +Finlandiya fi +Фінляндія fi +Phần Lan fi +Finlande fi +芬兰 fi +芬蘭 fi +Fiji fj +Фіджы fj +Фиджи fj +Fidži fj +Fidzsi fj +ມີດີ fj +Ilhas Fiji fj +Fidži fj +Fidži fj +Фіджі fj +斐济 fj +Falkland Islands (Malvinas) fk +Фолклендски Острови fk +Foklandska ostrva (Malvini) fk +Falkland-øerne fk +Islas Falkland (Malvinas) fk +Falkland Irlak (Malvinak) fk +Falkland-szigetek fk +Ilhas Malvinas fk +Falklandské Ostrovy (Malviny) fk +Falklandski otoki (Malvini) fk +Falklandsöarna fk +福克兰岛 (马尔维纳斯) fk +Micronesia, Federated states of fm +Федэрацыя Мiкранэзіі fm +Микронезия fm +Mikronezija, Federalne države fm +Mikronesien, de forenede stater af fm +Micronesia, Estados federados de fm +Mikronesia, Estatu Federatuak fm +Mikronézia fm +Estados Federados da Micronésia fm +Spjoené Å¡táty Mikronézie fm +Mikronezija, Združene države fm +Mikronesiska federationen fm +密克罗尼西亚联邦 fm +Faroe Islands fo +Фареорски Острови fo +Farska ostrva fo +Færøerne fo +islas Faroe fo +Faroe Irlak fo +Faroe-szigetek fo +ໄອແລນ fo +Ilhas Faroe fo +Ostrovy Faroe fo +Otoki Faroe fo +Färöarna fo +Фарерські острови fo +France fr +Frankryk fr +فرنسا fr +Fransa fr +Францыя fr +Франция fr +Frañs fr +Francuska fr +França fr +Francie fr +Frankrig fr +Frankreich fr +Γαλλία fr +Francio fr +Francia fr +Prantsusmaa fr +Frantzia fr +فرانسه fr +Ranska fr +Frakland fr +Francia fr +צרפת fr +Francuska fr +Franciaország fr +Prancis fr +Frakkland fr +Francia fr +フランス fr +프랑스 fr +ຝຣັ່ງ fr +PrancÅ«zija fr +Francija fr +Franza fr +Frankrike fr +Frankrijk fr +Frankrike fr +Fora fr +França fr +Francja fr +França fr +França fr +FranÅ£a fr +Франция fr +Francúzsko fr +Francija fr +Francuska fr +I-France fr +Frankrike fr +À¢Ã¡ýÍ fr +ฝรั่งเศส fr +Fransa fr +Франція fr +Fura fr +Pháp fr +Fransi fr +法国 fr +法國 fr +Gabon ga +Габон ga +Габон ga +Gabón ga +ແກລ່ງນ ga +Gabão ga +Габон ga +加蓬 ga +United Kingdom gb +Vereenigde Koninkryk gb +المملكة المتحدة gb +Birləşmiş Krallıq gb +Злучанае Каралеўства gb +Великобритания gb +Rouantelezh Unanet gb +Velika Britanija gb +Regne Unit gb +Spojené království gb +Storbritannien gb +Großbritannien gb +Ηνωμένο Βασίλειο gb +Britio gb +Reino Unido gb +Ühendatud Kuningriigid gb +Erreinu Batua gb +بریتانیا gb +Iso-Britannia gb +Stórabretland gb +Royaume Uni gb +Reino Unido gb +בריטניה gb +Ujedinjeno Kraljevstvo gb +Egyesült Királyság gb +Inggris gb +Stóra Bretland gb +Regno Unito gb +イギリス gb +영국 gb +ສະຫະລາດສະອານາຈັກ gb +Jungtinė Karalystė gb +Apvienotā Karaliste gb +Renju Unit gb +Storbritannia gb +Verenigd Koninkrijk gb +Storbritannia gb +Regne Unit gb +Wielka Brytania gb +Reino Unido gb +Reino Unido gb +Anglia gb +Великобритания gb +Anglicko gb +Združeno kraljestvo gb +Velika Britanija gb +I-United Kingdom gb +Storbritannien gb +³ì¸¢Â ­Ã¡îº¢Âõ gb +สหราชอาณาจักร gb +Birleşik Krallık gb +Великобританія gb +Anh gb +United Kingdom gb +联合王国 gb +聯合王國 gb +United Kingdom gb +Grenada gd +غرينادا gd +Qrenada gd +Грэнада gd +Гренада gd +Granada gd +Γρενάδα gd +Grenado gd +Granada gd +گرانادا gd +Grenade gd +Granada gd +גרנדה gd +Grænhöfðaeyjar gd +Granada gd +グラナダ gd +그러네이다 gd +ເກນາດາ gd +Grenāda gd +Granada gd +Granada gd +Granada gd +Гренада gd +I-Grenada gd +¸¢¦Ãɼ¡ gd +เกรนาดา gd +Гренада gd +格林纳达 gd +格瑞那達 gd +Georgia ge +Грузія ge +Грузия ge +Gruzija ge +Georgien ge +Grúzia ge +ເຊີເບີຍ ge +Geórgia ge +Gruzija ge +Georgien ge +Грузія ge +格鲁吉亚 ge +Ghana gh +غانا gh +Гана gh +Гана gh +Gana gh +Γκάνα gh +غنا gh +גאנה gh +ガーナ gh +ຈີນ gh +Gana gh +Gana gh +Gana gh +Гана gh +Gana gh +I-Ghana gh +¸¡É¡ gh +Гана gh +加纳 gh +迦納 gh +Gibraltar gi +Гибралтар gi +Gibraltár gi +ມອລຕາ gi +Гібралтар gi +直布罗陀 gi +Gambia gm +Гамбія gm +Гамбия gm +Gambija gm +ແກມມາ gm +Gâmbia gm +Gambija gm +Гамбія gm +冈比亚 gm +Guinea gn +Гвінэя gn +Гвинея gn +Gvineja gn +ເຖາວັນ gn +Guiné gn +Gvineja gn +Гвінея gn +几内亚 gn +Guadeloupe gp +Гвадалупа gp +Gvadalupe gp +Guadalupe gp +ເດີລຸກ gp +Guadalupe gp +Гваделупа gp +瓜德罗普岛 gp +Equatorial Guinea gq +Экватарыяльная Гвінэя gq +Екваториялна Гвинея gq +Ekvatorijalna Gvineja gq +Ækvatorial Guinea gq +Guinea equatorial gq +Ginea Ekuatoriala gq +Egyenlítői Guinea gq +ການສອນ gq +Guiné Equatorial gq +Rovníkova Guinea gq +Ekvatorialna Gvineja gq +Ekvatorialguinea gq +Екваторіальна Гвінея gq +赤道几内亚 gq +Greece gr +Griekeland gr +اليونان gr +Yunanıstan gr +Грэцыя gr +Гърция gr +Gres gr +Grčka gr +Grècia gr +Řecko gr +Grækenland gr +Griechenland gr +Ελλάδα gr +Grekujo gr +Grecia gr +Kreeka gr +Grezia gr +یونان gr +Kreikka gr +Grikkaland gr +Grèce gr +Grecia gr +יוון gr +Grčka gr +Görögország gr +Grikkland gr +Grecia gr +ギリシャ gr +그리스 gr +ກີຊ gr +Graikija gr +GrieÄ·ija gr +Greċja gr +Hellas gr +Griekenland gr +Hellas gr +Grèça gr +Grecja gr +Grécia gr +Grécia gr +Grecia gr +Греция gr +Grécko gr +Grčija gr +Grčka gr +I-Greece gr +Grekland gr +¸¢Ã£Í gr +กรีซ gr +Yunanistan gr +Греція gr +Hy Lạp gr +Grece gr +希腊 gr +希臘 gr +Guatemala gt +Gautemala gt +غواتيمالا gt +Quatemala gt +Гватэмала gt +Гватемала gt +Gvatemala gt +Γουατεμάλα gt +Gvatemalo gt +Guatemaala gt +گواتمالا gt +גואטמלה gt +Gvatemala gt +カタロニア gt +과테말라 gt +ກັວເຕມາລາ gt +Gvatemala gt +Gvatemala gt +Gwatemala gt +Gwatemala gt +Гватемала gt +Gvatemala gt +Gvatemala gt +I-Guatemala gt +ÌÅ¡ò¾Á¡Ä¡ gt +กัวเตมาลา gt +Гватемала gt +Gwatemala gt +瓜地马拉 gt +瓜地馬拉 gt +Guam gu +Гуам gu +ແກມມາ gu +Гуам gu +关岛 gu +Guinea-Bissau gw +Гвінэя-Бісаў gw +Гвинея-Бисау gw +Gvineja-Bisau gw +Ginea-Bissau gw +Bissau-Guinea gw +ລັດເຊີຍ gw +Guiné-Bissau gw +Гвінея-Біссау gw +几内亚比绍 gw +Guyana gy +Гвіяна gy +Гуана gy +Gvajana gy +ຈີນ gy +Guiana gy +Gvajana gy +Гаяна gy +圭亚那 gy +Hong Kong hk +Ганконг hk +Хонг Конг hk +Hongkong hk +ບໍ່ຮູ້ຈັກ hk +Гонконг hk +香港 hk +Honduras hn +هندوراس hn +Гандурас hn +Хондурас hn +Hondures hn +Ονδούρα hn +Honduraso hn +Honduuras hn +هندوراس hn +הונדורס hn +ホンデュラス hn +온두라스 hn +ຫອນດູລັດ hn +HondÅ«ras hn +Hondurasa hn +Ħonduras hn +Hondures hn +Гондурас hn +I-Honduras hn +¬ñÎáŠÍ hn +ฮอนดูรัส hn +Гондурас hn +洪都拉斯 hn +宏都拉斯 hn +Croatia hr +Kroatië hr +كرواتيا hr +Xırvatıstan hr +Харватыя hr +Хърватска hr +Kroatia hr +Hrvatska hr +Croàcia hr +Chorvatsko hr +Kroatien hr +Kroatien hr +Κροατία hr +Kroatio hr +Croacia hr +Horvaatia hr +Kroazia hr +کرواسی hr +Kroatia hr +Kroatia hr +Croatie hr +Croacia hr +קרואטיה hr +Hrvatska hr +Horvátország hr +Kroasia hr +Króatía hr +Croazia hr +クロアチア hr +크로아티아 hr +ໂຄເອເທີຍ hr +Kroatija hr +Horvātija hr +Kroazja hr +Kroatia hr +Kroatië hr +Kroatia hr +Croacia hr +Chorwacja hr +Croácia hr +Croácia hr +CroaÅ£ia hr +Хорватия hr +Chorvátsko hr +HrvaÅ¡ka hr +Hrvatska hr +I-Croatia hr +Kroatien hr +̦á§Åº¢Â¡ hr +โครเอเธีย hr +Hırvatistan hr +Хорватія hr +CrowÃ¥ceye hr +克罗地亚 hr +克羅埃西亞 hr +Haiti ht +Гаіці ht +Хаити ht +Haití ht +ວາດຮູບ - K ht +Гаїті ht +海地岛 ht +Hungary hu +Hongarye hu +هنغاريا hu +Macarıstan hu +Вугоршчына hu +Унгария hu +Hungaria hu +Mađarska hu +Hongria hu +Maďarsko hu +Ungarn hu +Ungarn hu +Ουγγαρία hu +Hungario hu +Hungría hu +Ungari hu +Hungaria hu +مجارستان hu +Unkari hu +Ungarn hu +Hongrie hu +Hungría hu +הונגריה hu +Mađjarska hu +Magyarország hu +Hungaria hu +Ungverjaland hu +Ungheria hu +ハンガリー hu +헝가리 hu +ຫັງກາລີ hu +Vengrija hu +Ungārija hu +Ungerija hu +Ungarn hu +Hongarije hu +Ungarn hu +Hongria hu +Węgry hu +Hungria hu +Hungria hu +Ungaria hu +Венгрия hu +Maďarsko hu +Madžarska hu +Mađarska hu +I-Hungary hu +Ungern hu +¬í§¸Ã¢ hu +ฮังการี hu +Macaristan hu +Угорщина hu +Hongreye hu +匈牙利 hu +匈牙利 hu +Indonesia id +Indonesië id +إندونيسيا id +İndoneziya id +Інданэзія id +Индонезия id +Indonezija id +Indonèsia id +Indonésie id +Indonesien id +Indonesien id +Ινδονησία id +Indonezio id +Indoneesia id +اندونزی id +Indonésie id +אינדונזיה id +Indonezija id +Indonézia id +Indónesía id +インドネシア id +인도네시아 id +ອີຍໂດນີເຊີຍ id +Indonezija id +Indonēzija id +Indoneżja id +Indonesië id +Indonezja id +Indonésia id +Indonésia id +Indonezia id +Индонезия id +Indonézia id +Indonezija id +I-Indonesia id +Indonesien id +­ó§¾¡É£º¢Â¡ id +อินโดนีเซีย id +İndonezya id +Індонезія id +Indoneseye id +印度尼西亚 id +印尼 id +Ireland ie +Ierland ie +أيرلندا ie +İrlandiya ie +Ірляндыя ie +Ирландия ie +Iwerzhon ie +Irska ie +Irlanda ie +Irsko ie +Irland ie +Irland ie +Ιρλανδία ie +Islando ie +Irlanda ie +Island ie +Irlanda ie +ایرلند ie +Irlanti ie +Írland ie +Irlande ie +Irlanda ie +אירלנד ie +Irska ie +Írország ie +Irlandia ie +Írland ie +Irlanda ie +アイスランド ie +아일랜드 ie +ໄອແລນ ie +Airija ie +Īrija ie +Irlanda ie +Irland ie +Ierland ie +Irland ie +Irlanda ie +Irlandia ie +Irlanda ie +Irlanda ie +Irlanda ie +Ирландия ie +Írsko ie +Irska ie +Irska ie +I-Ireland ie +Irland ie +«Â÷Ä¡óÐ ie +ไอร์แลนด์ ie +İrlanda ie +Ірландія ie +Irlande ie +爱尔兰 ie +愛爾蘭 ie +Israel il +اسرائيل il +İzrail il +Ізраіль il +Израел il +Izrael il +Izrael il +Ισραήλ il +Israelo il +Iisrael il +اسراییل il +Ísrael il +Israël il +ישראל il +Izrael il +Izrael il +Ísrael il +Israele il +イスラエル il +이스라엘 il +ອິດສະລະເອລ il +Izraelis il +Izraēla il +Iżrael il +Izrael il +Израиль il +Izrael il +Izrael il +Izrael il +I-Israel il +­Í§Ãø il +อิสราเอล il +İsrail il +Ізраїль il +Israyel il +USirayeli il +以色列 il +以色列 il +India in +Indië in +الهند in +Hindistan in +Індыя in +Индия in +Indija in +Índia in +Indie in +Indien in +Indien in +Ινδία in +Hindujo in +هندوستان in +Intia in +Inde in +הודו in +Indija in +Indland in +インド in +인도 in +ອິນເດີຍ in +Indija in +Indija in +Indja in +Indie in +Índia in +Índia in +Индия in +Indija in +I-India in +Indien in +­ó¾¢Â¡ in +อินเดีย in +Hindistan in +Індія in +Inde in +印度 in +印度 in +Endiya in +Iraq iq +Irak iq +العراق iq +İraq iq +Ірак iq +Ирак iq +Irak iq +Irák iq +Irak iq +Irak iq +Ιράκ iq +Irako iq +Irak iq +Iraak iq +عراق iq +Irak iq +Irak iq +Irak iq +עירק iq +Irak iq +Irak iq +Írak iq +Irak iq +イラク iq +이라크 iq +ອີລັກ iq +Irakas iq +Irāka iq +Irak iq +Irak iq +Irak iq +Irak iq +Iraque iq +Iraque iq +Irak iq +Ирак iq +Irák iq +Irak iq +I-Iraq iq +Irak iq +®Ã¡ì iq +อิรัค iq +Irak iq +Ірак iq +Irak iq +伊拉克 iq +伊拉克 iq +Iran ir +أيران ir +Іран ir +Иран ir +Írán ir +Ιράν ir +Iraan ir +ایران ir +אירן ir +Irán ir +イラン ir +이란 ir +ອີລັກ ir +Iranas ir +Irão ir +Irã ir +Иран ir +Irán ir +I-Iran ir +®Ã¡ý ir +İran ir +Іран ir +伊朗 ir +伊朗 ir +Iceland is +Ysland is +أيسلندا is +İslandiya is +Ісьляндыя is +Исландия is +Island is +Island is +Islàndia is +Island is +Island is +Island is +Ισλανδία is +Islando is +Islandia is +Island is +Islandia is +ایسلند is +Islanti is +Ísland is +Islande is +Islandia is +איסלנד is +Island is +Izland is +Islandia is +Ísland is +Islanda is +アイスランド is +아이슬란드 is +ໄອຊແລນ is +Islandija is +Islande is +Islandja is +Island is +IJsland is +Island is +Islandia is +Islandia is +Islândia is +Islândia is +Islanda is +Исландия is +Island is +Islandija is +Island is +I-Iceland is +Island is +³ÍÄ¡óÐ is +ไอซ์แลนด์ is +İzlanda is +Ісландія is +Izlande is +冰岛 is +冰島 is +Icelandi is +Italy it +Italië it +ايطاليا it +İtalyia it +Італія it +Италия it +Italia it +Italija it +Itàlia it +Itálie it +Italien it +Italien it +Ιταλία it +Italio it +Italia it +Itaalia it +Italia it +ایتالیا it +Italia it +Italia it +Italie it +Italia it +איטליה it +Italija it +Olaszország it +Italia it +Ítalía it +Italia it +イタリア it +이탈리아 it +ອີຕາລີ it +Italija it +Itālija it +Italja it +Italia it +Italië it +Italia it +Italia it +Włochy it +Itália it +Itália it +Italia it +Италия it +Taliansko it +Italija it +Italija it +I-Italy it +Italien it +­ò¾¡Ä¢ it +อิตาลี it +İtalya it +Італія it +ItÃ¥leye it +Ithali it +意大利 it +義大利 it +Jamaica jm +Jamaika jm +جامايكا jm +Yamayka jm +Ямайка jm +Ямайка jm +Jamaika jm +Jamajka jm +Jamajka jm +Jamaika jm +Τζαμάικα jm +Ä´amaiko jm +Jamaika jm +Jamaika jm +جاماییکا jm +Jamaika jm +Jamaïque jm +Xamaica jm +ג'מייקה jm +Jamajka jm +Jamaika jm +Jamaika jm +Giamaica jm +ジャマイカ jm +자메이카 jm +ຈາໄມກາ jm +Jamaika jm +Jamaika jm +Ä amajka jm +Jamajka jm +Ямайка jm +Jamajka jm +Jamajka jm +Jamajka jm +I-Jamaica jm +ƒº¦Áö측 jm +จาไมกา jm +Jamaika jm +Ямайка jm +Djamayike jm +牙买加 jm +牙買加 jm +Jordan jo +Jordaan jo +الأردن jo +İordaniya jo +Ярданія jo +Йордания jo +Jordania jo +Jordán jo +Jordanien jo +Ιορδανία jo +Jordanio jo +Jordania jo +اردن jo +Jordania jo +Jordanie jo +ירדן jo +Jordánia jo +Jórdanía jo +Giordania jo +ヨルダン jo +요르단 jo +ຈໍແດນ jo +Jordanija jo +Jordāna jo +Ä ordan jo +Jordanië jo +Jordania jo +Jordânia jo +Jordânia jo +Iordania jo +Иордания jo +Jordánsko jo +Jordanija jo +I-Jordan jo +Jordanien jo +§Â¡÷¾¡ý jo +จอร์แดน jo +Ürdün jo +Йорданія jo +Djordaneye jo +约旦 jo +約旦 jo +Ijolidani jo +Japan jp +اليابان jp +Yaponiya jp +Японія jp +Япония jp +Japó jp +Japonsko jp +Ιαπωνία jp +Japanio jp +Japón jp +Jaapan jp +Japonia jp +ژاپن jp +Japani jp +Japon jp +Xapón jp +יפן jp +Japán jp +Jepang jp +Giappone jp +日本 jp +일본 jp +ຍີ່ປຸ່ນ jp +Japonija jp +Japāna jp +Ä appun jp +Japon jp +Japonia jp +Japão jp +Japão jp +Japonia jp +Япония jp +Japonsko jp +Japonska jp +I-Japan jp +ºôÀ¡ý jp +ญี่ปุ่น jp +Japonya jp +Японія jp +Nhật bản jp +Djapon jp +日本 jp +日本 jp +Kenya ke +Кенія ke +Кения ke +Kenija ke +Kenia ke +ເວນດາ ke +Quênia ke +Keňa ke +Kenija ke +Кенія ke +肯尼亚 ke +Kyrgyzstan kg +Кыргызстан kg +Киргистан kg +Kirgistan kg +Kirgizistan kg +Kyrgyzstán kg +Kirgizisztán kg +ຄສິຕັລ kg +Kirgizstan kg +Kirgizistan kg +Киргизстан kg +吉尔吉斯坦 kg +Cambodia kh +Камбоджа kh +Камбоджа kh +Kambođa kh +Kambodzsa kh +ໂຄລຳເບີຍ kh +Cambodja kh +Kambodža kh +Kambodža kh +Kambodja kh +Камбоджа kh +柬埔寨 kh +Kiribati ki +Кiрыбацi ki +Кирибати ki +ແຟຄທັລ - K ki +Кірібаті ki +基里巴斯 ki +Comoros km +Каморы km +Коморски km +Komori km +Comorerne km +ສີ km +Komori km +Komorerna km +Комори km +科摩罗群岛 km +St. Kitts and Nevis kn +St. Kitts en Nevis kn +سانت كيتس و نيفيس kn +St. Kitts və Nevis kn +Св. Кристоф и Невис kn +S. Kitts ha Nevis kn +St. Kitts i Nevis kn +Sv. Kitts a Nevis kn +St. Kitts-Nevis kn +St. Kitts und Nevis kn +St. Kitts και Nevis kn +St. Kitts kaj Nevis kn +St. Kitts y Nevis kn +St. Kitts ja Nevis kn +St. Kitts eta Nevis kn +سن کیتس و نویس kn +St. Kitts ja Nevis kn +St Kitts et Nevis kn +Saint Kitts e Nevis kn +סנט קיטס ונביס kn +St. Kitts és Nevis kn +St. Kitts dan Nevis kn +Ss. Kitts e Nevis kn +セントキッツネヴィス kn +세인트 키츠 네비스 kn +Å v. Kitts ir Nevis kn +St. Kitts un Nevis kn +St. Kitts u Nevis kn +St. Kitts og Nevis kn +St. Kitts en Nevis kn +St. Kitts og Nevis kn +St. Kitts le Nevis kn +St. Kitts e Nevis kn +St. Kitts e Nevis kn +St Kitts e Nevis kn +Sf. Kitts şi Nevis kn +о. Св. Кристофа и Невиса kn +St. Kitts a Nevis kn +St. Kitts in Nevis kn +St. Kitts i Nevis kn +I-St. Kitts and Nevis kn +St. Kitts och Nevis kn +¦ºÂ¢ý𠸢ðÍ & ¦¿Å¢Í kn +St. Kitts ve Nevis kn +Федерація Сент-Кітс і Невіс kn +St. Kitts na Nevis kn +St. Kitts neNevis kn +圣基特和里维斯 kn +聖克理斯多福及尼維斯 kn +St. Kitts kanye no-Nevis kn +North Korea kp +Noord Korea kp +كوريا الشمالية kp +Şimali Koreya kp +Паўночная Карэя kp +Северна Корея kp +Norzh-Korea kp +Sjeverna Koreja kp +Corea del Nord kp +Severní Korea kp +Nordkorea kp +Nord-Korea kp +Βόρεια Κορέα kp +Nordkoreo kp +Corea del Norte kp +Põhja-Korea kp +Ipar Korea kp +کره شمالی kp +Pohjois-Korea kp +Norðurkorea kp +Corée du nord kp +Corea do Norte kp +צפון קוריאה kp +Sjeverna Koreja kp +Észak-Korea kp +Korea Utara kp +Kórea - Norðurkórea kp +Corea del Nord kp +北朝鮮 kp +조선민주주의 인민공화국 kp +ເກົາລີເຫນືອ kp +Å iaurės Korėja kp +ZiemeļKoreja kp +Korea ta' Fuq kp +Nord-Korea kp +Noord-Korea kp +Nord-Korea kp +Lebowa la Korea kp +Corea dèu Nord kp +Korea Północna kp +Coreia do Norte kp +Coréia do Norte kp +Coreea de Nord kp +Северная Корея kp +severná Kórea kp +Severna Koreja kp +Severna Koreja kp +I-North Korea kp +Nordkorea kp +ż ¦¸¡Ã¢Â¡ kp +เกาหลีเหนือ kp +Kuzey Kore kp +Північна Корея kp +Devhula ha Korea kp +Bắc Triều Tiên kp +Bijhe Coreye kp +Umntla Korea kp +朝鲜 kp +北韓 kp +Enyakatho ne-Korea kp +South Korea kr +Suid Korea kr +كوريا الجنوبية kr +Cənubi Koreya kr +Паўднёвая Карэя kr +Южна Корея kr +Su-Korea kr +Južna Koreja kr +Corea del Sud kr +Jižní Korea kr +Sydkorea kr +Süd-Korea kr +Νότια Κορέα kr +Sudkoreo kr +Corea del Sur kr +Lõuna-Korea kr +Hego Korea kr +کره جنوبی kr +Etelä-Korea kr +Suðurkorea kr +Corée du sud kr +Corea do Sur kr +דרום קוריאה kr +Južna Koreja kr +Dél-Korea kr +Korea Selatan kr +Kórea - Suðurkórea kr +Corea del Sud kr +韓国 kr +대한민국 kr +ເກົາລີໃຕ້ kr +Pietų Korėja kr +DievidKoreja kr +Korea t'Isfel kr +Sør-Korea kr +Zuid-Korea kr +Sør-Korea kr +Borwa bja Korea kr +Corea dèu Sud kr +Korea Południowa kr +Coreia do Sul kr +Coréia do Sul kr +Coreea de Sud kr +Южная Корея kr +Južná Kórea kr +Južna Koreja kr +Južna Koreja kr +I-South Korea kr +Sydkorea kr +¦¾ý ¦¸¡Ã¢Â¡ kr +เกาหลีใต้ kr +Güney Kore kr +Південна Корея kr +Korea tshipembe kr +Hàn Quốc kr +Nonne Coreye kr +Umzantsi Korea kr +韩国 kr +南韓 kr +Emzansi Korea kr +Kuwait kw +Kuwaït kw +الكويت kw +Кувэйт kw +Кувейт kw +Kuvajt kw +Kuvajt kw +Κουβέιτ kw +Kuveit kw +کویت kw +Kuvait kw +Kowait kw +כווית kw +Kuvajt kw +Kuvait kw +クェート kw +쿠웨이트 kw +ແຕ້ມຮູບ- K kw +Kuveitas kw +Koeweit kw +Koweit kw +Kuveit kw +Кувейт kw +Kuvajt kw +Kuvajt kw +I-Kuwait kw +̨Åò kw +KКувейт kw +科威特 kw +科威特 kw +Cayman Islands ky +Кайманови Острови ky +Kajmanska ostrva ky +Cayman-øerne ky +Islas Caimán ky +Kaiman Irlak ky +Kajmán-szigetek ky +ຄາຕາລັນ ky +Ilhas Cayman ky +Kajmanske Ostrovy ky +Kajmanski otoki ky +Caymanöarna ky +Кайманські острови ky +开曼群岛 ky +Kazakhstan kz +Казахстан kz +Казахстан kz +Kazahstan kz +Kazakhstán kz +Kazahsztán kz +ແກແລກຕິກ - K kz +Kazaquistão kz +Kazachstan kz +Kazahstan kz +Kazakstan kz +Казахстан kz +哈萨克斯坦 kz +Laos la +Лаос la +Лаос la +Laosz la +ລາວ la +老挝 la +Lebanon lb +Libanon lb +لبنان lb +Ліван lb +Ливан lb +Liban lb +Libanon lb +Libanon lb +Libanon lb +Λίβανος lb +Lebanono lb +Líbano lb +Liibanon lb +لبنان lb +Libanon lb +Libanon lb +Liban lb +לבנון lb +Libanon lb +Libanon lb +Libano lb +レバノン lb +레바논 lb +ເດນ່ງນ lb +Libanas lb +Libanu lb +Libanon lb +Libanon lb +Libanon lb +Liban lb +Líbano lb +Líbano lb +Liban lb +Ливан lb +Libanon lb +Libanon lb +I-Lebanon lb +Libanon lb +¦ÄÀÉ¡ý lb +Ліван lb +Liban lb +黎巴嫩 lb +黎巴嫩 lb +St. Lucia lc +سانت لوسيا lc +Св. Люсиа lc +S. Lucia lc +Svatá Lucie lc +Σάντα Λουτσία lc +St. Lucio lc +Santa Lucía lc +سن لوسیا lc +Sankta Lusia lc +Sainte Lucie lc +Santa Lucía lc +סנטה לוסיה lc +Santa Lucia lc +セントルキア lc +세인트 루시아 lc +ເຊັນລູເຊີຍ lc +Å v Liucija lc +Sv. LÅ«cija lc +St. Luċija lc +Santa Lúcia lc +Santa Lúcia lc +Sf. Lucia lc +о. Св. Люсии lc +Sv. Júlia lc +Sv. Lucija lc +I-St. Lucia lc +¦ºýð 溢¡ lc +เซนต์ลูเซีย lc +Санта Лучія lc +圣路西亚 lc +聖露西亞 lc +Liechtenstein li +Ліхтэнштэйн li +Лихтенщайн li +LihtenÅ¡tajn li +Liechtestein li +ຟ້າແມບ li +列支敦士登 li +Sri Lanka lk +Шры-Ланка lk +Шри Ланка lk +Å ri Lanka lk +ເຊີເບີຍ lk +Å ri Lanka lk +斯里兰卡 lk +Liberia lr +Лібэрыя lr +Либеря lr +Liberija lr +Libéria lr +ລິຊາ lr +Libéria lr +Lýbia lr +Liberija lr +利比里亚 lr +Lesotho ls +Лесота ls +Лесото ls +Lesoto ls +Lesoto ls +ທົດສອບ ls +Lesoto ls +莱索托 ls +Lithuania lt +Lithuanië lt +ليتوانيا lt +Litvaniya lt +Літва lt +Литва lt +Litvanija lt +Lituània lt +Litva lt +Litauen lt +Litauen lt +Λιθουανία lt +Litovio lt +Lituania lt +Leedu lt +Lituania lt +لیتوانی lt +Liettua lt +Lituanie lt +ליטא lt +Litva lt +Litvánia lt +Litháenska lt +Lituania lt +リトアニア lt +리 투아니아 lt +ລິທົ່ວເນີຍ lt +Lietuva lt +Lietuva lt +Litwanja lt +Litauen lt +Litouwen lt +Litauen lt +Litwa lt +Lituânia lt +Lituânia lt +Lituania lt +Литва lt +Litva lt +Litva lt +Litvanija lt +I-Lithuania lt +Litauen lt +Ä¢òЧÅɢ¡ lt +ลิธัวเนีย lt +Litvanya lt +Литва lt +立陶宛 lt +立陶宛 lt +Luxembourg lu +Luxenburg lu +لوكسمبورغ lu +Lüksemburq lu +Люксэмбург lu +Люксембург lu +Luksemburg lu +Luxemburg lu +Lucembursko lu +Luxemburg lu +Λουξεμβούργο lu +Luksemburgo lu +Luxemburgo lu +Luksemburg lu +Luxemburg lu +لوگزامبورگ lu +Luxemburg lu +Luksemborg lu +לוקסמבורג lu +Luksemburg lu +Luxemburg lu +Lúxemborg lu +Lussemburgo lu +ルクセンブルグ lu +룩셈부르크 lu +ລັກແຊມເບີກ lu +Liuksemburgas lu +Luksemburga lu +Lussemburgu lu +Luxemburg lu +Luksemburg lu +Luxemburgo lu +Luxemburgo lu +Luxemburg lu +Люксембург lu +Luxemburg lu +Luksemburg lu +Luksemburg lu +I-Luxembourg lu +Luxemburg lu +Äìºõ§À¡÷ì lu +ลักเซมเบอร์ก lu +Lüksemburg lu +Люксембург lu +Lucsimbork lu +卢森堡 lu +盧森堡 lu +Latvia lv +لاتفيا lv +Latviya lv +Латвія lv +Латвия lv +Latvija lv +LotyÅ¡sko lv +Letland lv +Lettland lv +Λιθουανία lv +Latvio lv +Letonia lv +Läti lv +لاتویا lv +Lettonie lv +לטביה lv +Latvija lv +Lettország lv +Léttland lv +Lettonia lv +ラトビア lv +라트비아 lv +ລັດເວີຍ lv +Latvija lv +Latvija lv +Latvja lv +Letland lv +Łotwa lv +Letónia lv +Латвия lv +LotyÅ¡sko lv +Latvija lv +Latvija lv +I-Latvia lv +Lettland lv +ÄðŢ¡ lv +ลัธเวีย lv +Litvanya lv +Латвія lv +Lativia lv +拉脱维亚 lv +拉脫維亞 lv +Libya ly +Libië ly +ليبيا ly +Лівія ly +Либия ly +Libija ly +Líbia ly +Lýbie ly +Libyen ly +Libyen ly +Λιβύη ly +Libia ly +Liibüa ly +Libia ly +لیبی ly +Lybie ly +לוב ly +Líbia ly +Libia ly +リビア ly +ລິຊາ ly +Libija ly +Libië ly +Libia ly +Líbia ly +Líbia ly +Ливия ly +Lýbia ly +Libija ly +I-Libya ly +Libyen ly +Ä¢À¢Â¡ ly +Лівія ly +利比亚 ly +利比亞 ly +Morocco ma +Morokko ma +المغرب ma +Марока ma +Мароко ma +Maroko ma +Marroc ma +Maroko ma +Marokko ma +Marokko ma +Μαρόκο ma +Moroko ma +Marruecos ma +Maroko ma +Maroko ma +مراکش ma +Marokko ma +Marokko ma +Maroc ma +מרוקו ma +Maroko ma +Marokkó ma +Marocco ma +モロッコ ma +모로코 ma +ເມົາລິ ma +Marokas ma +Marokk ma +Marokko ma +Marokko ma +Marokko ma +Maroko ma +Marrocos ma +Marrocos ma +Maroc ma +Марокко ma +Maroko ma +Maroko ma +I-Morocco ma +Marocko ma +§Á¡Ã¡§¸¡ ma +Марокко ma +Marok ma +摩洛哥 ma +摩洛哥 ma +Monaco mc +Манака mc +Монако mc +Monako mc +Mónaco mc +ເມົາລິ mc +Mônaco mc +Monako mc +Monako mc +摩纳哥 mc +Moldova md +Малдова md +Молдова md +Moldavia md +Moldavia md +ສະໂລວັກ md +Moldávsko md +Moldavien md +摩尔多瓦 md +Madagascar mg +Мадагаскар mg +Мадагаскар mg +Madagaskar mg +Madagaszkár mg +ຄາສະບາລ - K mg +Madagaskar mg +Madagaskar mg +Madagaskar mg +马达加斯加 mg +Marshall Islands mh +Маршаллавы астравы mh +Маршалови Острови mh +MarÅ¡alova ostrva mh +Marshall-øerne mh +Islas Marshall mh +Marshall Irlak mh +Marshall-szigetek mh +ລາດສະອານາຈັກໄທຍ mh +Ilhas Marshall mh +Maršálove ostrovy mh +Marshallovi otoki mh +Marshallöarna mh +马绍尔群岛 mh +Macedonia mk +Makedoniese mk +مقدونيا mk +Makedonya mk +Македонія mk +Македония mk +Makedonia mk +Makedonija mk +Macedònia mk +Makedonie mk +Makedonien mk +Makedonien mk +Μακεδονία mk +Macedonio mk +Makedoonia mk +Mazedonia mk +مقدونیه mk +Makedonia mk +Macédoine mk +מקדוניה mk +Makedonija mk +Macedónia mk +Masedonia mk +Makedónía mk +マケドニア語 mk +마케도니아 mk +ມາເຊໂດເນີຍ mk +Makedonija mk +MaÄ·edonija mk +Maċedonja mk +Makedonia mk +Macedonië mk +Makedonia mk +Macedònian mk +Macedónia mk +Macedônia mk +Македония mk +Macedónsky mk +Makedonija mk +Makedonija mk +I-Macedonia mk +Makedonien mk +Á¡º¢§¼¡É¢Â¡ mk +มาเซโดเนีย mk +Makedonya mk +Македонія mk +Masedonia mk +马其顿 mk +馬其頓 mk +Mali ml +Малі ml +Мали ml +ຈົດຫມາຍ ml +马里 ml +Myanmar mm +М'янма mm +Майнмар mm +Mjanmar mm +Burma mm +Birmania mm +ຕົວຮງກພີື້ນທີ່ທຳງານ - K mm +Mjanmar mm +缅甸 mm +Mongolia mn +Манголія mn +Монголия mn +Mongolija mn +Mongoliet mn +Mongólia mn +ລອກອິນ mn +Mongólia mn +Mongolsko mn +Mongolija mn +Mongoliet mn +蒙古 mn +Macau mo +Макао mo +Makau mo +Macao mo +Makaó mo +ມອລຕາ mo +Makao mo +Macao mo +澳门 mo +Martinique mq +Мартиника mq +Martinik mq +Martinica mq +ເມົາລິ mq +Martinik mq +马提尼克岛 mq +Mauritania mr +Маўрытанія mr +Мавритания mr +Mauritanija mr +Mauretanien mr +Mauritánia mr +ລິທົວເນີຍ mr +Mauritânia mr +Mavretanija mr +Mauretanien mr +毛里塔尼亚 mr +Montserrat ms +Монсерат ms +Monsera ms +ຈໍພາບ ms +蒙特塞拉特岛 ms +Malta mt +مالطة mt +Мальта mt +Малта mt +Μάλτα mt +Malto mt +مالت mt +Malte mt +מלטה mt +Málta mt +マルタ mt +왈타 mt +ມອລຕາ mt +Мальта mt +I-Malta mt +Á¡ø¼¡ mt +มอลตา mt +Мальта mt +Male mt +马耳他 mt +馬爾他 mt +Mauritius mu +Маўрыцы mu +Маурици mu +Mauricijus mu +Mauricio mu +ພາທິຊັ້ນ mu +Maurícius mu +Mavricij mu +毛里求斯 mu +Maldives mv +Мальдывы mv +Малдиви mv +Maldivi mv +Maldiverne mv +Maldivas mv +Maldív-szigetek mv +ມັລດິສ mv +Maldivas mv +Maldiv mv +Maldiverna mv +马尔代夫 mv +Malawi mw +Малаві mw +Малави mw +Malavi mw +ມອລຕາ mw +马拉维 mw +Mexico mx +Meksiko mx +المكسيك mx +Meksika mx +Мэксыка mx +Мексико mx +Mec'hiko mx +Meksiko mx +Mèxic mx +Mexiko mx +Mexiko mx +Μεξικό mx +Meksikujo mx +México mx +Mehhiko mx +Mexiko mx +مکزیک mx +Meksiko mx +Meksiko mx +Mexique mx +México mx +מקסיקו mx +Meksiko mx +Mexikó mx +Meksiko mx +Mexíkó mx +Messico mx +メキシコ mx +멕시코 mx +ເມັກຊີໂກ mx +Meksika mx +Meksika mx +Messiku mx +Mèxic mx +Meksyk mx +México mx +México mx +Mexic mx +Мексика mx +Mexiko mx +Mehika mx +Meksiko mx +I-Mexico mx +¦Á캢§¸¡ mx +เม็กซิโก mx +Meksika mx +Мексика mx +Mê hi cô mx +Mecsike mx +墨西哥 mx +墨西哥 mx +Malaysia my +Малайзыя my +Малайзия my +Malezija my +Malasia my +Malasia my +Malajzia my +ມອລຕາ my +Malásia my +Malajzia my +Malezija my +马来西亚 my +Mozambique mz +Мазамбік mz +Мозамбик mz +Mozambik mz +Mozambik mz +ຫນ່ວຍຄວາມຈຳ mz +Moçambique mz +Mozambik mz +Mozambik mz +Moçambique mz +莫桑比克 mz +Namibia na +Намібія na +Намибия na +Namibija na +Namíbia na +ຈາໄມກາ na +Namíbia na +Namíbia na +Namibija na +纳米比亚 na +New Caledonia nc +Нова Каледония nc +Nova Kaledonija nc +Ny Caledonien nc +Nueva Caledonia nc +Kaledonia Berria nc +Új-Kaledónia nc +ມາເຊໂດເນີຍ nc +Nova Caledônia nc +Nová Kaledónia nc +Nova Kaledonija nc +Nya Caledonien nc +新喀里多尼亚 nc +Niger ne +Нігер ne +Нигер ne +ຕົວຮງກພື້ນທີ່ທຳງານ ne +Nigéria ne +Nigéria ne +尼日尔 ne +Norfolk Island nf +Остров Норфолк nf +Norfolk ostrvo nf +Norfolk-øerne (Australien) nf +Isla Norfolk nf +Norfok Irla nf +Norfolk-szigetek nf +ໂປແລນ nf +Ilhas Norfolk nf +Ostrov Norfolk nf +Otok Norfolk nf +Norfolkön nf +诺福克岛 nf +Nigeria ng +Нігерыя ng +Нигерия ng +Nigerija ng +Nigéria ng +ບັນແກເລີຍ ng +Nigéria ng +Nigéria ng +Nigerija ng +尼日利亚 ng +Nicaragua ni +Nikaragua ni +نيكاراغوا ni +Нікарагуа ni +Никарагуа ni +Nikaragva ni +Nikaragua ni +Νικαράγουα ni +Nikaraagua ni +نیکاراگویه ni +Nikaragua ni +Nikaragua ni +ניקרגווה ni +ニカラグア ni +니카라과 ni +ປາລາກກວຍ ni +Nikaragua ni +Nikaragwa ni +Nikaragua ni +Nicarágua ni +Nicarágua ni +Никарагуа ni +Nikaragua ni +Nikaragva ni +I-Nicaragua ni +¿¢¸Ã¡Ì§Å ni +Nikaragua ni +Нікарагуа ni +尼加拉瓜 ni +尼加拉瓜 ni +Netherlands nl +Nederland nl +هولندا nl +Hollandiya nl +Галяндыя nl +Холандия nl +Izelvroioù nl +Nizozemska nl +Holanda nl +Nizozemí nl +Holland nl +Niederlande nl +Κάτω Χώρες nl +Nederlando nl +Países Bajos nl +Holland nl +Holanda nl +هلند nl +Alankomaat nl +Háland nl +Pays bas nl +Países Baixos nl +הולנד nl +Nizozemska nl +Hollandia nl +Belanda nl +Holland nl +Paesi Bassi nl +オランダ nl +네덜란드 nl +ເນເທີແລນ์ nl +Olandija nl +NÄ«derlande nl +Nederland nl +Nederland nl +Nederland nl +Holanda nl +Holandia nl +Países Baixos nl +Holanda nl +Olanda nl +Нидерланды nl +Holandsko nl +Nizozemska nl +Holandija nl +I-Netherlands nl +Nederländerna nl +¦¿¾÷Ä¡óÐ nl +เนเธอร์แลนด์ nl +Hollanda nl +Голландія nl +Hà Lan nl +荷兰 nl +荷蘭 nl +Norway no +Noorweë no +النرويج no +Norveç no +Нарвэгія no +Норвегия no +Norvegia no +NorveÅ¡ka no +Noruega no +Norsko no +Norge no +Norwegen no +Νορβηγία no +Norvegio no +Noruega no +Norra no +Norvegia no +نروژ no +Norja no +Norra no +Norvège no +Noruega no +נורבגיה no +NorveÅ¡ka no +Norvégia no +Norwegia no +Noregur no +Norvegia no +ノルウェー no +노르웨이 no +ນໍເວ no +Norvegija no +Norvēģija no +NorveÄ¡ja no +Norge no +Noorwegen no +Noreg no +Noruega no +Norwegia no +Noruega no +Noruega no +Norvegia no +Норвегия no +Nórsko no +NorveÅ¡ka no +NorveÅ¡ka no +I-Norway no +Norge no +¿¡÷§Å no +นอร์เวย์ no +Norveç no +Норвегія no +Na uy no +挪威 no +挪威 no +Nepal np +Нэпал np +Непал np +Nepál np +ເວນດາ np +尼泊尔 np +Nauru nr +Науру nr +Науру nr +Naurú nr +ປາລາກກວຍ nr +瑙鲁 nr +Niue nu +Ниуе nu +ເນ໊ຕ nu +纽埃岛 nu +New Zealand nz +Nuwe Seeland nz +نيوزيلاندا nz +Yeni Zellandiya nz +Новая Зэляндыя nz +Нова Зеландия nz +Zeland nevez nz +Novi Zeland nz +Nova Zelanda nz +Nový Zéland nz +Neuseeland nz +Νέα Ζηλανδία nz +Novzelando nz +Nueva Zelanda nz +Uus-Meremaa nz +Zelanda Berria nz +زلاندنو nz +Uusi-Seelanti nz +Nýsæland nz +Nouvelle Zélande nz +Nova Celandia nz +ניו זילנד nz +Novi Zeland nz +Új-Zéland nz +Selandia Baru nz +Nýja Sjáland nz +Nuova Zelanda nz +ニュージーランド nz +뉴질랜드 nz +ນີວຊີແລນ nz +Naujoji Zelandija nz +JaunZēlande nz +Nieuw Zeeland nz +Navera Zelanda nz +Nowa Zelandia nz +Nova Zelândia nz +Nova Zelândia nz +Noua Zeelandă nz +Новая Зеландия nz +Nový Zéland nz +Nova Zelandija nz +Novi Zeland nz +I-New Zealand nz +Nya Zeeland nz +¿¢äº¢Ä¡óÐ nz +นิวซีแลนด์ nz +Yeni Zelanda nz +Нова Зеландія nz +Nouve Zelande nz +新西兰 nz +紐西蘭 nz +Oman om +عُمان om +Аман om +Оман om +Omán om +Ομάν om +Omano om +Omán om +Omaan om +عمان om +עומן om +Omán om +オマーン om +오만 om +ເຍີຍລະມັນ om +Omanas om +Omã om +Оман om +Omán om +I-Oman om +µÁý om +Umman om +Оман om + Oman om +阿曼 om +阿曼 om +Panama pa +بنما pa +Панама pa +Панама pa +Panamà pa +Παναμάς pa +Panamo pa +Panamá pa +پاناما pa +Panamá pa +פנמה pa +パナマ pa +파나마 pa +ປານາມາ pa +Panamá pa +Panamá pa +Панама pa +I-Panama pa +ÀÉ¡Á¡ pa +ปานามา pa +Панама pa +巴拿马 pa +巴拿馬 pa +Peru pe +البيرو pe +Пэру pe +Перу pe +Perou pe +Perú pe +Περού pe +Peruo pe +Perú pe +Peruu pe +پرو pe +Pérou pe +Perú pe +פרו pe +Perú pe +Perù pe +ペルー pe +페루 pe +ເປລູ pe +PerÅ« pe +Pero pe +Perú pe +Перу pe +I-Peru pe +¦ÀÕ pe +เปรู pe +Перу pe +Perou pe +秘鲁 pe +秘魯 pe +French Polynesia pf +Француская Палінэзія pf +Френска Полинезия pf +Francuska Polinezija pf +Fransk Polynesien pf +Polinesia francesa pf +Polinesia Frantziarra pf +Francia-Polinézia pf +ຝຣັ່ງເສດ pf +Polinésia Francesa pf +Francúzska Polynézia pf +Francoska Polinezija pf +Franska Polynesien pf +法属波利尼西亚 pf +Papua New Guinea pg +Папуа–Новая Гвінэя pg +Папуа и Нова Гвинея pg +Papua Nova Gvineja pg +Papua Nueva Guinea pg +Papua Ginea Berria pg +Pápua Új-Guinea pg +ເທົາອ່ອນ pg +Nova Guiné Papua pg +Papua Nová Guinea pg +Papua Nova Gvineja pg +Papua Nya Guinea pg +巴布亚新几内亚 pg +Philippines ph +Філіпіны ph +Филипини ph +Filipini ph +Filippinerne ph +Filipinas ph +Filipinak ph +Fülöp-szigetek ph +ອາລະປະໂຫຍດ ph +Filipinas ph +Filipíny ph +Filipini ph +Filippinerna ph +菲律宾 ph +Pakistan pk +Пакістан pk +Пакистан pk +Pakisztán pk +ລງບ pk +Paquistão pk +巴基斯坦 pk +Poland pl +Poolland pl +بولندا pl +Polşa pl +Польшча pl +Полша pl +Polonia pl +Poljska pl +Polònia pl +Polsko pl +Polen pl +Polen pl +Πολωνία pl +Pollando pl +Polonia pl +Poola pl +Polonia pl +لهستان pl +Puola pl +Pólland pl +Pologne pl +Polonia pl +פולין pl +Poljska pl +Lengyelország pl +Polandia pl +Pólland pl +Polonia pl +ポーランド pl +폴란드 pl +ໂປແລນ pl +Lenkija pl +Polija pl +Polonja pl +Polen pl +Polen pl +Polen pl +Polònia pl +Polska pl +Polónia pl +Polônia pl +Polonia pl +Польша pl +Poľsko pl +Poljska pl +Poljska pl +I-Poland pl +Polen pl +§À¡Ä¡óÐ pl +โปแลนด์ pl +Polonya pl +Польща pl +Pholandi pl +Ba Lan pl +Pologne pl +波兰 pl +波蘭 pl +Saint Pierre and Miquelon pm +Sveti Pjer i Migelon pm +Saint Pierre og Miquelon pm +Saint Pierre y Miquelon pm +Saint Pierre eta Miquelon pm +Saint Pierre és Miquelon pm +Saint Pierre e Miquelon pm +Saint Pierre a Miquelon pm +Sveti Pierre in Miquelon pm +Saint Pierre och Miquelon pm +圣皮埃尔和密克隆岛 pm +Pitcairn pn +Pitkern pn +ລງບ pn +Puerto Rico pr +Пуерто Рико pr +Portoriko pr +ໂປຣໂຕຄອນ pr +Porto Rico pr +Portoriko pr +波多尼各 pr +Palestinian Territory ps +Palesteinse Gebied ps +السلطة الفلسطينية ps +Палестынская тэрыторыя ps +Палестина ps +Palestinska teritorija ps +Territori Palestí ps +Palestinské území ps +Palæstinensiske selvstyreomrÃ¥der ps +Palästinensisches Gebiet ps +Παλαιστίνη ps +Palestinaj teritorioj ps +Territorio palestino ps +Palestiina territoorium ps +Palestina ps +فلسطین ps +Palestiinalaisalue ps +Palestinensiska økið ps +Territoire palestinien ps +השטחים הפלסטיניים ps +Palestinski teritorij ps +Palesztin területek ps +Territori palestinesi ps +パレスチナ自治区 ps +팔레스타인 자치구 ps +ການພິມຜິດພາດ ps +Palestinos teritorija ps +Palestina ps +Palestinske territorier ps +Palestijns territorium ps +Palestinske territorium ps +Bohwa bja Palestina ps +Palestyna ps +Território Palestiniano ps +Território Palestino ps +Teritoriul Palestinian ps +Палестинские территории ps +Palestínske územia ps +Palestinski teritorij ps +I-Palestinian Territory ps +Palestina ps +À¡Äо£É ¬¨½Âõ ps +Filistin Bölgesi ps +Палестинська територія ps +Mukano wa maphalesitina ps +Palestene ps +Umhlaba wePalestina ps +巴勒斯坦地区 ps +巴勒斯坦領地 ps +Indawo yama-Phalesitina ps +Portugal pt +البرتغال pt +Portuqaliya pt +Партугалія pt +Португалия pt +Portugalsko pt +Πορτογαλία pt +Portugalo pt +پرتغال pt +Portugali pt +פורטוגל pt +Portugália pt +Portúgal pt +Portogallo pt +ポルトガル pt +포르투갈 pt +ໂປຣຕຸເກສ pt +Portugalija pt +Portugāle pt +Portugall pt +Portugalia pt +Portugalia pt +Португалия pt +Portugalsko pt +Portugalska pt +I-Portugal pt +§À¡÷òиø pt +โปรตุเกส pt +Portekiz pt +Португалія pt +BềEĐào Nha pt +葡萄牙 pt +葡萄牙 pt +Palau pw +Палау pw +Палау pw +ມອລຕາ pw +帕劳群岛 pw +Paraguay py +Paraguaai py +باراغواي py +Paraqvay py +Парагвай py +Парагвай py +Paragvaj py +Paraguai py +Παραγουάη py +Paragvajo py +Paraguai py +پاراگویه py +Paraguai py +פרגואי py +Paragvaj py +パラグアイ py +파라과이 py +ປາລາກກວຍ py +Paragvajus py +Paragvaja py +Paragwaj py +Paraguai py +Paragwaj py +Paraguai py +Paraguai py +Paraguai py +Парагвай py +Portugalsko py +Paragvaj py +Paragvaj py +I-Paraguay py +Àá̧Å py +ปารากวัย py +Парагвай py +Paragway py +巴拉圭 py +巴拉圭 py +Qatar qa +قطر qa +Катар qa +Катар qa +Katar qa +Katar qa +Katar qa +Κατάρ qa +Kataro qa +Katar qa +قطر qa +Katar qa +קטר qa +Katar qa +Katar qa +カタール qa +카타르 qa +ມອລຕາ qa +Katar qa +Катар qa +Katar qa +Katar qa +I-Qatar qa +¸¾¡÷ qa +Katar qa +Катар qa +卡塔尔 qa +卡達 qa +Romania ro +Romenië ro +رومانيا ro +Rumıniya ro +Румынія ro +Румъния ro +Roumania ro +Rumunija ro +Rumunsko ro +Rumænien ro +Rumänien ro +Ρουμανία ro +Rumanio ro +Rumanía ro +Rumeenia ro +Errumania ro +رومانی ro +Rumenia ro +Roumanie ro +Romanía ro +רומניה ro +Rumunjska ro +Románia ro +Rumania ro +Rúmenía ro +ルーマニア ro +루마니아 ro +ໂລມາເນີຍ ro +Rumunija ro +Rumānija ro +Rumanija ro +Roemenië ro +Rumunia ro +Roménia ro +Romênia ro +Румыния ro +Rumunsko ro +Romunija ro +Rumunija ro +I-Romania ro +Rumänien ro +Õ§Áɢ¡ ro +โรมาเนีย ro +Romanya ro +Румунія ro +Ru ma ni ro +Roumaneye ro +罗马尼亚 ro +羅馬尼亞 ro +Russia ru +Rusland ru +روسيا ru +Rusiya ru +Расея ru +Русия ru +Rusia ru +Rusija ru +Rússia ru +Rusko ru +Rusland ru +Russland ru +Ρωσία ru +Ruslando ru +Rusia ru +Venemaa ru +Errusia ru +روسیه ru +Venäjä ru +Russland ru +Russie ru +Rusia ru +רוסיה ru +Rusija ru +Oroszország ru +Rusia ru +Rússland ru +ロシア ru +러시아 ru +ລັດເຊີຍ ru +Rusija ru +Krievija ru +Russja ru +Russland ru +Rusland ru +Russland ru +Rosja ru +Rússia ru +Rússia ru +Rusia ru +Россия ru +Rusko ru +Rusija ru +Rusija ru +I-Russia ru +Ryssland ru +ú¢Â¡ ru +รัสเซีย ru +Rusya ru +Росія ru +Rashia ru +Nga ru +Russeye ru +Rashiya ru +俄罗斯 ru +俄羅斯 ru +Rwanda rw +Руанда rw +Руанда rw +Ruanda rw +Ruanda rw +Ruanda rw +ແພນດ້າ rw +Ruanda rw +Ruanda rw +卢旺达 rw +Saudi Arabia sa +Saudi Arabië sa +السعودية sa +Саудаўская Арабія sa +Саудитска Арабия sa +Saudijska Arabija sa +Aràbia Saudí sa +Saúdská Arábie sa +Saudi Arabien sa +Saudi-Arabien sa +Σαουδική Αραβία sa +SaÅ­di-Arabio sa +Arabia Saudí sa +Saudi Araabia sa +عربستان سعودی sa +Saudi-Arabia sa +Arabie Saoudite sa +ערב הסעודית sa +Saudijska Arabija sa +Szaúd-Arábia sa +Arabia saudita sa +サウジアラビア sa +사우디 아라비아 sa +ອາລະບິກ sa +Saudi Arabija sa +Għarabja Sawdita sa +Saudi-Arabia sa +Saudi-Arabië sa +Saudi-Arabia sa +Arabia Saudyjska sa +Arábia Saudita sa +Arábia Saudita sa +Arabia Saudită sa +Саудовская Аравия sa +Saudská arábia sa +Saudova Arabija sa +I-Saudi Arabia sa +Saudiarabien sa +º×¾¢ «§ÃÀ¢Â¡ sa +Suudi Arabistan sa +Саудівська Аравія sa +沙特阿拉伯 sa +沙烏地阿拉伯 sa +Solomon Islands sb +Саламонавы астравы sb +Соломонови Острови sb +Solomonska ostrva sb +Salomon-øerne sb +Islas Salomón sb +Solomon Irlak sb +Salamon-szigetek sb +ສະໂລວະເນີຍ sb +Ilhas Salomão sb +Å alamúnove ostrovy sb +Solomonovi otoki sb +Salomonöarna sb +所罗门群岛 sb +Seychelles sc +Сэйшэлы sc +Сейшелски острови sc +SejÅ¡eli sc +Seychellerne sc +ເຊລ sc +SejÅ¡eli sc +Seychellerna sc +塞舌尔 sc +Sudan sd +السودان sd +Судан sd +Судан sd +Sudán sd +Σουδάν sd +Sudano sd +Sudán sd +Sudaan sd +سودان sd +Sudania sd +Soudan sd +סודן sd +Szudán sd +Súdan sd +スーダン sd +수단 sd +ຊູດານ sd +Sudanas sd +Sudāna sd +Sudão sd +Sudão sd +Судан sd +Sudán sd +I-Sudan sd +ݼ¡ý sd +ซูดาน sd +Судан sd +Sudani sd +Soudan sd +苏丹 sd +蘇丹 sd +Sweden se +Swede se +السويد se +İsveç se +Швэцыя se +Швеция se +Sveden se +Å vedska se +Suècia se +Å védsko se +Sverige se +Schweden se +Σουηδία se +Svedio se +Suecia se +Rootsi se +Suedia se +سوید se +Ruotsi se +Svøriki se +Suède se +Suecia se +שבדיה se +Å vedska se +Svédország se +Swedia se +Svíþjóð se +Svezia se +スウェーデン se +스웨덴 se +ສະວີເດນ se +Å vedija se +Zviedrija se +Svezja se +Sverige se +Zweden se +Sverige se +Suècia se +Szwecja se +Suécia se +Suécia se +Suedia se +Швеция se +Å védsko se +Å vedska se +Å vedska se +I-Sweden se +Sverige se +ÍÅ£¼ý se +สวีเดน se +İsveç se +Швеція se +Swidene se +Thuỵ Điển se +瑞典 se +瑞典 se +Singapore sg +Сынгапур sg +Сингапур sg +Singapur sg +Singapur sg +Szingapúr sg +ໂຊນາ sg +Singapura sg +Singapur sg +Singapur sg +新加坡 sg +Saint Helena sh +Свети Елена sh +Sveta Helena sh +St. Helena sh +Santa Helena sh +Szent Heléna sh +ຫົວເລື່ອງ sh +Santa Helena sh +Svätá Helena sh +Sveta Helena sh +圣赫勒拿岛 sh +Slovenia si +Slovenië si +سلوفينيا si +Sloveniya si +Славенія si +Словения si +Slovenija si +Eslovenia si +Slovinsko si +Slovenien si +Slowenien si +Σλοβενία si +Slovenio si +Eslovenia si +Sloveenia si +Eslovenia si +اسلوانی si +Slovénie si +Eslovenia si +סלובניה si +Slovenija si +Szlovénia si +Slóvenía si +スロベニア si +슬로베니아 si +ສະໂລວະເນີຍ si +Slovėnija si +Slovēnija si +Slovenja si +Slovenië si +Eslovenia si +Słowenia si +Eslovénia si +Eslovênia si +Словения si +Slovinsko si +Slovenija si +Slovenija si +I-Slovenia si +Slovenien si +ͧġŢɢ¡ si +สโลเวเนีย si +Slovenya si +Словенія si +斯洛文尼亚 si +斯洛維尼亞 si +Slovakia sk +Slovakië sk +سلوفاكيا sk +Slovakiya sk +Славакія sk +Словакия sk +Slovačka sk +Eslovaquia sk +Slovensko sk +Slovakiet sk +Slowakien sk +Σλοβακία sk +Slovakujo sk +Eslovaquia sk +Slovakkia sk +Eslovakia sk +اسلواکی sk +Slovaquie sk +סלובקיה sk +Slovačka sk +Szlovákia sk +Slóvakía sk +Slovacchia sk +スロバキア sk +슬로바키아 sk +ສະໂລວັກ sk +Slovakija sk +Slovākija sk +Slovakja sk +Slovakije sk +Słowacja sk +Eslováquia sk +Eslováquia sk +Slovacia sk +Словакия sk +Slovensko sk +SlovaÅ¡ka sk +I-Slovakia sk +Slovakien sk +ͧġš츢 sk +สโลวัค sk +Slovakya sk +Словакія sk +斯洛伐克 sk +斯洛伐克 sk +San Marino sm +Сан-Марына sm +Сан Марино sm +ໂຊນາ sm +圣马力诺 sm +Senegal sn +Сэнэгал sn +Сенегал sn +Szenegál sn +ທົ່ວໄປ sn +塞内加尔 sn +Somalia so +Somalië so +صومال so +Самалі so +Сомалия so +Somalija so +Somàlia so +Somálsko so +Σομαλία so +Somalio so +Somaalia so +سومالی so +Somalie so +סומליה so +Somalija so +Szomália so +ソマリア so +소말리아 so +ໂລມາເນີຍ so +Somalis so +Somalija so +Somalie so +Somália so +Somália so +Сомали so +Somálsko so +Somalija so +I-Somalia so +§º¡Á¡Ä¢Â¡ so +Somali so +Сомалі so +Somaleye so +索马里 so +索馬利亞 so +Suriname sr +Сурынам sr +Суринам sr +Surinam sr +ເຊີເບີຍ sr +Surinam sr +Surinam sr +Surinam sr +Sao Tome and Principe st +Сан Томе и Приницпе st +Sao Tome i Principe st +Sao Tomé og Principe st +Sao Tome y Príncipe st +Sao Tome eta Principe st +Sao Tome és Principe st +ບໍລິການ st +São Tome e Príncipe st +Sao Tome a Principe st +Sao Tome in Principe st +São Tomé och Príncipe st +El Salvador sv +السلفادور sv +Сальвадор sv +Ел Салвадор sv +Salvador sv +Salvador sv +Ελ Σαλβαντόρ sv +Elsalvadoro sv +Salvador sv +السالوادور sv +Salvador sv +O Salvador sv +אל סלבדור sv +Salvador sv +エルサルバドル sv +엘살바도르 sv +ເອລຊັນວາດດໍ sv +Salvadoras sv +Salvadora sv +Salwador sv +Salvador sv +Сальвадор sv +Salvádor sv +Salvador sv +I-El Salvador sv +±ø º¡øÅ§¼¡÷ sv +เอลซัลวาดอร์ sv +Ель-Сальвадор sv +萨尔瓦多 sv +薩爾瓦多 sv +Syria sy +Sirië sy +سوريا sy +Сырыя sy +Сирия sy +Sirija sy +Síria sy +Sýrie sy +Syrien sy +Syrien sy +Συρία sy +Sirio sy +Siria sy +Süüria sy +Siria sy +سوریه sy +Syyria sy +Syrie sy +סוריה sy +Sirija sy +Szíria sy +Siria sy +シリア sy +시리아 sy +ເຊີເບີຍ sy +Sirija sy +Siria sy +Syrië sy +Síria sy +Síria sy +Siria sy +Сирия sy +Sýria sy +Sirija sy +I-Syria sy +Syrien sy +º¢Ã¢Â¡ sy +Suriye sy +Сирія sy +叙利亚 sy +敘利亞 sy +Swaziland sz +Свазылэнд sz +Свазиленд sz +Svazilend sz +Swazilandia sz +Swazilandia sz +Szváziföld sz +ລາດສະນາຈັກໄທຍ sz +Suécia sz +Swazijsko sz +Svazi sz +斯威士兰 sz +Turks and Caicos Islands tc +Turks i Kaikos ostrva tc +Turks- og Caicosøerne tc +Islas Turcos y Caicos tc +Turks eta Caicos Irlak tc +Turks- és Caicos-szigetek tc +Ilhas Caicos e Turca tc +Turks a Caicos ostrovy tc +Otoka Turks in Caicos tc +Turks- och Caicosöarna tc +特克斯和凯科斯群岛 tc +Chad td +Чад td +Чад td +Čad td +Tchad td +Txad td +Csád td +ເກມໄພ່ td +Čad td +Čad td +Tchad td +乍得 td +Togo tg +Тога tg +Того tg +ຂອງເລ່ນສະນຸກ tg +多哥 tg +Thailand th +تايلاند th +Tayland th +Тайлянд th +Тайланд th +Tajland th +Tailàndia th +Thajsko th +Ταϊλάνδη th +Tajlando th +Tailandia th +Tai th +Thailandia th +تایلند th +Thaimaa th +Tailand th +Thaïlande th +Tailandia th +תאילנד th +Tajland th +Thaiföld th +Tæland th +Tailandia th +タイ th +태국 (타이) th +ລາດສະນາຈັກໄທຍ th +Tailandas th +Taivāna th +Tajlandja th +Tailandia th +Tajlandia th +Tailândia th +Tailândia th +Tailanda th +Таиланд th +Thajsko th +Tajska th +Tajland th +I-Thailand th +¾¡öÄ¡óÐ th +ราชอาณาจักรไทย th +Tayland th +Таїланд th +Thái Lan th +Taylande th +泰国 th +泰國 th +Tajikistan tj +Таджыкістан tj +Таджикистан tj +Tadžikistan tj +Tajikistán tj +Tadzsikisztán tj +ໃຕ້ຫວັນ tj +Tajiquistão tj +Tadžikistan tj +Tadžikistan tj +Tadzjikistan tj +塔吉克斯坦 tj +Tokelau tk +Токелао tk +ເບລາລັສ tk +Turkmenistan tm +Туркмэністан tm +Туркменистан tm +Turkmenistán tm +Türkmenisztán tm +ຕຸລະກີ tm +Turquia tm +土库曼斯坦 tm +Tunisia tn +Tunisië tn +تونس tn +Туніс tn +Тунис tn +Tunis tn +Tuníssia tn +Tunisko tn +Tunesien tn +Tunesien tn +Τυνησία tn +Tunisio tn +Túnez tn +Tuneesia tn +تونس tn +Tunesia tn +Tunisie tn +תוניסיה tn +Tunis tn +Tunézia tn +チュニジア tn +튀니지 tn +ລັດເຊີຍ tn +Tunisas tn +Tuneżija tn +Tunisie tn +Tunezja tn +Tunísia tn +Tunísia tn +Тунис tn +Tunisko tn +Tunizija tn +I-Tunisia tn +Tunisien tn +ÐÉ¢º¢Â¡ tn +Tunus tn +Туніс tn +突尼斯 tn +突尼西亞 tn +Tonga to +Тонга to +Тонга to +ໂຊນາ to +汤加 to +East Timor tp +Источен Тимур tp +Istočni Timor tp +Østtimor tp +Timor oriental tp +Ekialdeko Timor tp +Kelet-Timor tp +ວັນແລະເວລາ tp +Timor Leste tp +Východný Timor tp +Vzhodni Timor tp +Östtimor tp +东帝汶 tp +Turkey tr +Turkeye tr +تركيا tr +Türkiyə tr +Турцыя tr +Турция tr +Turkia tr +Turska tr +Turquia tr +Turecko tr +Tyrkiet tr +Türkei tr +Τουρκία tr +Turkujo tr +Turquía tr +Türgi tr +Turkia tr +ترکیه tr +Turkki tr +Turkaland tr +Turquie tr +Turquía tr +טורקיה tr +Turska tr +Törökország tr +Turki tr +Tyrkland tr +Turchia tr +トルコ tr +터키 tr +ຕຸລະກີ tr +Turkija tr +Turcija tr +Turkija tr +Tyrkia tr +Turkije tr +Tyrkia tr +Turquia tr +Turcja tr +Turquia tr +Turquia tr +Turcia tr +Турция tr +Turecko tr +Turčija tr +Turska tr +I-Turkey tr +Turkiet tr +ÐÕ츢 tr +ตุรกี tr +Türkiye tr +Туреччина tr +ThềENhÄ© Kì tr +土耳其 tr +土耳其 tr +Trinidad and Tobago tt +Trinidad en Tobago tt +ترينيداد و توباغو tt +Trinidad və Tabaqo tt +Трынідад і Табага tt +Тринидад и Тобаго tt +Trinidad ha Tobago tt +Trinidad i Tobago tt +Trinidad i Tobago tt +Trinidad a Tobago tt +Trinidad og Tobago tt +Trinidad und Tobago tt +Τρίνινταντ και Τομπάγκο tt +Trinidado kaj Tobago tt +Trinidad y Tobago tt +Trinidad ja Tobago tt +Trinidad eta Tobago tt +ترینیداد و تُباگو tt +Trinidad ja Tobago tt +Trinidad og Tobago tt +Trinidad et Tobago tt +Trindade e Tobago tt +טרינידד וטובגו tt +Trinidad i Tobago tt +Trinidad és Tobago tt +Trinidad dan Tobago tt +Trinidad og Tobago tt +Trinidad e Tobago tt +トリニダードトバコ tt +트리니다드토바고 tt +ຕີນິແດດແລະໂທບາໂກ tt +Trinidadas ir Tobagas tt +Trinidada un Tobago tt +Trinidad u Tobago tt +Trinidad og Tobago tt +Trinidad en Tobago tt +Trinidad og Tobago tt +Trinidad le Tobago tt +Trinidad e Tobago tt +Trinidad i Tobago tt +Trinidade e Tobago tt +Trinidad e Tobago tt +Trinidad şi Tobago tt +Тринидад и Тобаго tt +Trinidad a Tobago tt +Trinidad in Tabago tt +Trinidad i Tobago tt +I-Trinidad kanye neTobago tt +Trinidad och Tobago tt +ðâɢ¼¡ð & ¦¼¡À¡§¸¡ tt +ตรีนิแดดและโทบาโก tt +Trinidad veTabago tt +Республіка Трінідад та Тобаго tt +Trinidad na Tobago tt +Trinidad và Tobago tt +Trinidad ne Tobago tt +特里尼达和多巴哥 tt +千里達及托貝哥 tt +Trinidad knaye ne-Tobago tt +Tuvalu tv +Тувалу tv +Тували tv +ຊູລູ tv +图瓦卢 tv +Taiwan tw +تايوان tw +Tayvan tw +Тайвань tw +Тайван tw +Tajvan tw +Ταϊβάν tw +Tajvano tw +Taiwán tw +Taivan tw +تایوان tw +Taivan tw +Taïwan tw +Taiwán tw +טיוואן tw +Tajvan tw +Tajvan tw +台湾 tw +대만 tw +ໃຕ້ຫວັນ tw +Taivanis tw +Taivāna tw +Tajwan tw +Tajwan tw +Formosa tw +Тайвань tw +Tajvan tw +Tajvan tw +I-Taiwan tw +¾¡öÅ¡ý tw +ได้หวัน tw +Tayvan tw +Тайвань tw +Đài Loan tw +中国台湾 tw +台灣 tw +Tanzania, United Republic of tz +Злучаная Рэспубліка Танзанія tz +Танзания tz +Tanzanija, Ujedinjena Republika tz +Tanzania tz +Tanzania, Republica de tz +Tanazia, Errepublika Batua tz +Tanzánia tz +ໂດມິນິກັນ tz +República da Tanzânia tz +Tanzánia, Spojená republika tz +Tanzanija, Združena republika tz +Förenade republiken Tanzania tz +坦桑尼亚 tz +Ukraine ua +Ukraïne ua +أوكرانيا ua +Ukrayna ua +Украіна ua +Украйна ua +Ukraina ua +Ukrajina ua +Ucraïna ua +Ukrajina ua +Ουκρανία ua +Ukrainio ua +Ucrania ua +Ukraina ua +Ukrania ua +اکراین ua +Ukraina ua +Ukraina ua +Ucraína ua +אוקראינה ua +Ukrajina ua +Ukrajna ua +Ukraina ua +Úkraína ua +Ucraina ua +ウクライナ ua +우크라이나 ua +ຍູເຄຣນ ua +Ukraina ua +Ukraina ua +Ukranja ua +Ukraina ua +Oekraïne ua +Ukraina ua +Ucraina ua +Ukraina ua +Ucrânia ua +Ucrânia ua +Ucraina ua +Украина ua +Ukrajina ua +Ukrajina ua +Ukrajna ua +I-Ukraine ua +Ukraina ua +¯ì¦Ãöý ua +ยูเครน ua +Ukrayna ua +Україна ua +Ukraina ua +Ucrinne ua +乌克兰 ua +烏克蘭 ua +Uganda ug +Уганда ug +Уганда ug +ແພນດ້າ ug +乌干达 ug +United States of America us +Vereenigde State van Amerika us +الولايات المتحدة الأمريكية us +Amerika Birləşmiş Ştatları us +Злучаныя Штаты Амэрыкі us +САЩ us +Stadoù-Unanet Amerika us +Sjedinjene Američke Države us +Estats Units d'Amèrica us +Spojené státy americké us +USA us +USA us +Ην. Πολιτείες της Αμερικής us +Usono us +Estados Unidos de América us +Ameerika Ühendriigid us +Amerikako Estatu Batuak us +ایالات متحده‌ی آمریکا us +Yhdysvallat us +Sambandsríki Amerika (USA) us +États Unis d'Amérique us +Estados Unidos de América us +ארצות הברית us +Sjedinjene Američke Države us +Amerikai Egyesült Államok us +Amerika Serikat us +Bandaríki Norður Ameríku us +Stati Uniti d'America us +アメリカ us +미 합중국 us +ສະຫະລັດອາເມລິກາ us +Jungtinės Amerikos Valstijos us +Amerikas Savienotās Valstis us +Stati Uniti us +USA us +Verenigde Staten van Amerika us +USA us +Estats Units d'Amèrica us +Stany Zjednoczone Ameryki us +Estados Unidos da América us +Estados Unidos us +Statele Unite ale Americii us +Соединенные Штаты Америки us +USA us +Združene države Amerike us +Sjedinjene američke države us +I-United States of America us +Amerikas förenta stater us +³ì¸¢Â «¦Áâì¸ ¿¡Î¸û us +สหรัฐอเมริกา us +Amerika Birleşik Devletleri us +США us +mashango o tangananaho a America us +MÄ© us +United States ye Melika us +美利坚合众国 us +美利堅合眾國 us +Uruguay uy +الأوروغواي uy +Uruqvay uy +Уругвай uy +Уругвай uy +Urugvaj uy +Uruguai uy +Ουρουγουάη uy +Urugvajo uy +Uruguai uy +اروگویه uy +Uruguai uy +אורוגואי uy +Urugvaj uy +ウルグアイ uy +우루과이 uy +ອຸລຸກກວຍ uy +Urugvajus uy +Urugvaja uy +Urugwaj uy +Uruguai uy +Urugwaj uy +Uruguai uy +Uruguai uy +Uruguai uy +Уругвай uy +Uruguaj uy +Urugvaj uy +Urugvaj uy +I-Uruguay uy +¯Õ̧Å uy +อุรุกวัย uy +Уругвай uy +Ourougway uy +乌拉圭 uy +烏拉圭 uy +Uzbekistan uz +Узбэкістан uz +Узбекистан uz +Uzbekistán uz +Üzbegisztán uz +ເດນ່ງນ uz +Uzbequistão uz +乌兹别克斯坦 uz +Vatican City va +Ватыкан va +Ватикана va +Vatikan va +Vatikanstaten va +Vaticano va +Batikano Hiria va +Vatikán va +ລັດເວີຍ va +Cidade do Vaticano va +Vatikán va +Vatikan va +Vatikanstaten va +梵蒂冈 va +St. Vincent and the Grenadines vc +St. Vincent en die Grenadene vc +سانت فينسنت و الغرينادين vc +St. Vincent və Grenadines vc +Сент-Винсент и Гренадине vc +S. Visant hag ar Grenadinez vc +Sveti Vincent i Grenadini vc +St. Vincent i les Granadines vc +St. Vincent a Grenadiny vc +St. Vincent og Grenadinerne vc +St. Vincent und Grenadinen vc +St. Vincent kaj la Grenadinoj vc +San Vicente y las Granadinas vc +St. Vincent ja Grenadines vc +St. Vincent eta Grenadines vc +سن وینسن و گرادینس vc +St. Vincent ja Grenadiinit vc +Sankta Vinsent og Grenadinoyggjar vc +St Vincent et les Grenadines vc +San Vicente e as Granadinas vc +סנט וינסנט והגרנדינים vc +St. Vincent és Grenadines vc +St. Vincent dan the Grenadines vc +St. Vincent og Grenadines vc +S. Vincent e the Grenadines vc +セントヴィンセントグレナディン vc +세인트 빈센트 그레나딘 vc +ເຊີນວິນແຊນ ແລະເກນາດີນ vc +Å v. Vincentas ir Grenadinai vc +Sv. Vincents un GrenadÄ«nes vc +St. Vinċenz u l-Grenadini vc +St. Vincent og Grenadinene vc +St. Vincent en de Grenadines vc +St. Vincent og Grenadinane vc +St. Vincent le Grenadines vc +St. Vincent e les Granadines vc +St. Vincent i Grenadyny vc +São Vicente e Grenadinas vc +São Vicente e Grenadines vc +Sf. Vincent şi Grenadines vc +Сент-Винсент и Гренадины vc +St. Vincent a Grenadines vc +Sv. Vincent in Grenadini vc +St. Vincent i Grenadine vc +I-St. Vincent and the Grenadines vc +St. Vincent och Grenadinerna vc +¦ºÂ¢ýð Å¢ý¦ºýð & ¸¢¦ÃÉËý¸û vc +เซนต์วินเซนต์ และ เกรนาดีน vc +St. Vincent ve Grenadines vc +Сент-Вінсент і Гренадіни vc +St. Vincent na Grenadines vc +St. Vincent và Grenadines vc +St. Vincent ne Grenadines vc +圣文森特和格林那达 vc +聖文森及格納那丁 vc +I-St. Vincent kanye ne-Grenadines vc +Venezuela ve +فنزويلا ve +Вэнэсуэла ve +Венецуела ve +Venecuela ve +Βενεζουέλα ve +Venezuelo ve +Venetsueela ve +ونزویلا ve +Venesuela ve +Vénézuela ve +ונצואלה ve +Venecuela ve +ベネズェラ ve +베네수엘라 ve +ເວເນຊຸເອລາ ve +Venesuela ve +Venecuēla ve +Veneżwela ve +Wenezuela ve +Венесуэла ve +Venecuela ve +I-Venezuela ve +¦ÅÉ¢ÍÅÄ¡ ve +เวเนซูเอลา ve +Венесуела ve +委内瑞拉 ve +委內瑞拉 ve +Virgin Islands, British vg +Вирджински Острови, Британски vg +Djevičanska ostrva, Britanska vg +Britiske jomfruøer vg +Islas Vírgenes Británicas vg +Irla Birjinak, Britaniar vg +Virgin-szigetek (brit) vg +Ilhas Virgens, Inglaterra vg +Panenské Ostrovy, Britské vg +DeviÅ¡ki otoki, Britanski vg +Brittiska Jungfruöarna vg +维尔京群岛,英国 vg +Virgin Islands, U.S. vi +Вирджински Острови, Американски vi +Djevičanska ostrva, Američka vi +Jomfruøerne vi +Islas Vírgenes Americanas vi +Irla Birjinak, EE.BB. vi +Virgin-szigetek (USA) vi +Ilhas Virgens, EUA vi +Panenské Ostrovy, Americké vi +DeviÅ¡ki otoki, ZDA vi +Amerikanska Jungfruöarna vi +维尔京群岛,美国 vi +Vietnam vn +Viëtnam vn +فييتنام vn +Vyetnam vn +Віетнам vn +Виетнам vn +Vijetnam vn +Βιετνάμ vn +Vjetnamo vn +ویتنام vn +וייטנאם vn +Vijetnam vn +Víetnam vn +ベトナム vn +베트남 vn +ຫວງດນາມ vn +Vietnamas vn +Vjetnama vn +Vjetnam vn +Viëtnam vn +Wietnam vn +Vietname vn +Vietnã vn +Вьетнам vn +I-Vietnam vn +เวียตนาม vn +В'єтнам vn +越南 vn +越南 vn +Vanuatu vu +Вануату vu +Ванути vu +ຈີນ vu +瓦努阿图 vu +Wallis and Futuna wf +Valis i Futuna wf +Wallis- og Futuna-øerne wf +Wallis y Futuna wf +Wallis eta Futuna wf +Wallis és Futuna wf +ປັກອິນພາບ wf +Wallis e Futuna wf +Wallis a Futuna wf +Wallis in Futuna wf +Wallis och Futuna wf +Samoa ws +Самоа ws +Самоя ws +Szamoa ws +ໂຊນາ ws +萨摩亚群岛 ws +Yemen ye +اليمن ye +Емен ye +Йемен ye +Jemen ye +Iemen ye +Jemen ye +Jemen ye +Υεμένη ye +Jemeno ye +Jeemen ye +یمن ye +Jemen ye +Jemen ye +תימן ye +Jemen ye +Jemen ye +イエメン ye +예멘 ye +ເດມອນ ye +Jemenas ye +Jemen ye +Jemen ye +Jemen ye +Jemen ye +Jemen ye +Iémen ye +Йемен ye +Jemen ye +Jemen ye +I-Yemen ye +Jemen ye +§ÂÁý ye +Ємен ye +也门 ye +葉門 ye +Yugoslavia yu +Югаславія yu +Югославия yu +Jugoslavija yu +Jugoslavien (Serbien/Montenegro) yu +Jugoszlávia yu +ໂບລິເວີຍ yu +Iugoslávia yu +Juhoslávia yu +Jugoslavija yu +Jugoslavien yu +南斯拉夫 yu +South Africa za +Suid Afrika za +جنوب أفريقيا za +Cənubi Afrika za +Паўднёвая Афрыка za +Южна Африка za +Suafrika za +Južna Afrika za +Sudàfrica za +Jižní Afrika za +Sydafrikanske republik za +Südafrika za +Νότια Αφρική za +Sudafriko za +Sudáfrica za +Lõuna Aafrika za +Hego Afrika za +آفریقای جنوبی za +Etelä-Afrikka za +Suðurafrika za +Afrique du sud za +África do Sur za +דרום אפריקה za +Južna Afrika za +Dél-Afrika za +Afrika Selatan za +Suður Afríka za +Sud Africa za +南アフリカ za +남 아프리카 공화국 za +ແອບພິກາໃຕ້ za +Pietų Afrika za +Dienvid Āfrika za +Afrika t'Isfel za +Sør-Afrika za +Zuid-Afrika za +Sør-Afrika za +Afrika Borwa za +Sudafrica za +Afryka Południowa za +Africa do Sul za +África do Sul za +Africa de Sud za +Южная Африка za +Južná Afrika za +Južna Afrika za +Južna Afrika za +I-South Africa za +Sydafrika za +¦¾ý ¬ôâ측 za +แอฟริกาใต้ za +Güney Afrika za +Південна Африка za +Afurika tshipembe za +Nam Phi za +Mzantsi Afrika za +南非 za +南非 za +Emzantsi Afrika za +Zambia zm +Замбія zm +Замбия zm +ຈາໄມກາ້ zm +Zâmbia zm +Zambija zm +赞比亚 zm +Zimbabwe zw +Зымбабвэ zw +Зимбабве zw +Zimbabve zw +ລິຊາ zw +Zimbabve zw +津巴布韦 zw diff --git a/src/email.cpp b/src/email.cpp new file mode 100644 index 0000000..105967c --- /dev/null +++ b/src/email.cpp @@ -0,0 +1,140 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2015 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; + str += QLatin1String("Email {\n"); + str += QStringLiteral(" mail: %1\n").arg(d->mail); + if (!d->parameters.isEmpty()) { + QMapIterator i(d->parameters); + QString param; + while (i.hasNext()) { + i.next(); + param += QStringLiteral("%1 %2").arg(i.key(), i.value().join(QStringLiteral(","))); + } + 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(); +} + +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 new file mode 100644 index 0000000..f51e6ce --- /dev/null +++ b/src/email.h @@ -0,0 +1,77 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2015 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 + +/** @short Class that holds a Email for a contact. + * @since 4.14.5 + */ + +namespace KContacts +{ + +class KCONTACTS_EXPORT Email +{ + friend KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &, const Email &); + friend KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &, Email &); +public: + /** + * Creates an empty email object. + */ + Email(); + Email(const Email &other); + Email(const QString &mail); + + ~Email(); + + typedef QVector List; + + void setEmail(const QString &mail); + QString mail() const; + + bool isValid() const; + + void setParameters(const QMap ¶ms); + QMap parameters() const; + + bool operator==(const Email &other) const; + bool operator!=(const Email &other) const; + + Email &operator=(const Email &other); + + QString toString() const; +private: + class Private; + QSharedDataPointer d; +}; + +KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &stream, const Email &object); + +KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &stream, Email &object); + +} +Q_DECLARE_TYPEINFO(KContacts::Email, Q_MOVABLE_TYPE); +#endif // EMAIL_H diff --git a/src/field.cpp b/src/field.cpp new file mode 100644 index 0000000..3406c9d --- /dev/null +++ b/src/field.cpp @@ -0,0 +1,654 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2002 Cornelius Schumacher + + 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 +#include + +#include +#include +#include "field.h" + +using namespace KContacts; + +class Q_DECL_HIDDEN Field::Private +{ +public: + Private(int fieldId, int category = 0, + const QString &label = QString(), + const QString &key = QString(), + const QString &app = QString()) + : mFieldId(fieldId), mCategory(category), mLabel(label), + mKey(key), mApp(app) {} + + enum FieldId { + CustomField, + FormattedName, + FamilyName, + GivenName, + AdditionalName, + Prefix, + Suffix, + NickName, + Birthday, + HomeAddressStreet, + HomeAddressPostOfficeBox, + HomeAddressLocality, + HomeAddressRegion, + HomeAddressPostalCode, + HomeAddressCountry, + HomeAddressLabel, + BusinessAddressStreet, + BusinessAddressPostOfficeBox, + BusinessAddressLocality, + BusinessAddressRegion, + BusinessAddressPostalCode, + BusinessAddressCountry, + BusinessAddressLabel, + HomePhone, + BusinessPhone, + MobilePhone, + HomeFax, + BusinessFax, + CarPhone, + Isdn, + Pager, + Email, + Mailer, + Title, + Role, + Organization, + Department, + Note, + Url + }; + + int fieldId() const + { + return mFieldId; + } + int category() const + { + return mCategory; + } + + QString label() const + { + return mLabel; + } + QString key() const + { + return mKey; + } + QString app() const + { + return mApp; + } + + static Field::List mAllFields; + static Field::List mDefaultFields; + static Field::List mCustomFields; + +private: + int mFieldId; + int mCategory; + + QString mLabel; + QString mKey; + QString mApp; +}; + +Field::List Field::Private::mAllFields; +Field::List Field::Private::mDefaultFields; +Field::List Field::Private::mCustomFields; + +Field::Field(Private *p) + : d(p) +{ +} + +Field::~Field() +{ + delete d; +} + +QString Field::label() +{ + switch (d->fieldId()) { + case Private::FormattedName: + return Addressee::formattedNameLabel(); + case Private::FamilyName: + return Addressee::familyNameLabel(); + case Private::GivenName: + return Addressee::givenNameLabel(); + case Private::AdditionalName: + return Addressee::additionalNameLabel(); + case Private::Prefix: + return Addressee::prefixLabel(); + case Private::Suffix: + return Addressee::suffixLabel(); + case Private::NickName: + return Addressee::nickNameLabel(); + case Private::Birthday: + return Addressee::birthdayLabel(); + case Private::HomeAddressStreet: + return Addressee::homeAddressStreetLabel(); + case Private::HomeAddressPostOfficeBox: + return Addressee::homeAddressPostOfficeBoxLabel(); + case Private::HomeAddressLocality: + return Addressee::homeAddressLocalityLabel(); + case Private::HomeAddressRegion: + return Addressee::homeAddressRegionLabel(); + case Private::HomeAddressPostalCode: + return Addressee::homeAddressPostalCodeLabel(); + case Private::HomeAddressCountry: + return Addressee::homeAddressCountryLabel(); + case Private::HomeAddressLabel: + return Addressee::homeAddressLabelLabel(); + case Private::BusinessAddressStreet: + return Addressee::businessAddressStreetLabel(); + case Private::BusinessAddressPostOfficeBox: + return Addressee::businessAddressPostOfficeBoxLabel(); + case Private::BusinessAddressLocality: + return Addressee::businessAddressLocalityLabel(); + case Private::BusinessAddressRegion: + return Addressee::businessAddressRegionLabel(); + case Private::BusinessAddressPostalCode: + return Addressee::businessAddressPostalCodeLabel(); + case Private::BusinessAddressCountry: + return Addressee::businessAddressCountryLabel(); + case Private::BusinessAddressLabel: + return Addressee::businessAddressLabelLabel(); + case Private::HomePhone: + return Addressee::homePhoneLabel(); + case Private::BusinessPhone: + return Addressee::businessPhoneLabel(); + case Private::MobilePhone: + return Addressee::mobilePhoneLabel(); + case Private::HomeFax: + return Addressee::homeFaxLabel(); + case Private::BusinessFax: + return Addressee::businessFaxLabel(); + case Private::CarPhone: + return Addressee::carPhoneLabel(); + case Private::Isdn: + return Addressee::isdnLabel(); + case Private::Pager: + return Addressee::pagerLabel(); + case Private::Email: + return Addressee::emailLabel(); + case Private::Mailer: + return Addressee::mailerLabel(); + case Private::Title: + return Addressee::titleLabel(); + case Private::Role: + return Addressee::roleLabel(); + case Private::Organization: + return Addressee::organizationLabel(); + case Private::Department: + return Addressee::departmentLabel(); + case Private::Note: + return Addressee::noteLabel(); + case Private::Url: + return Addressee::urlLabel(); + case Private::CustomField: + return d->label(); + default: + return i18n("Unknown Field"); + } +} + +int Field::category() +{ + return d->category(); +} + +QString Field::categoryLabel(int category) +{ + switch (category) { + case All: + return i18n("All"); + case Frequent: + return i18n("Frequent"); + case Address: + return i18nc("street/postal", "Address"); + case Email: + return i18n("Email"); + case Personal: + return i18n("Personal"); + case Organization: + return i18n("Organization"); + case CustomCategory: + return i18n("Custom"); + default: + return i18n("Undefined"); + } +} + +QString Field::value(const KContacts::Addressee &a) +{ + switch (d->fieldId()) { + case Private::FormattedName: + return a.formattedName(); + case Private::FamilyName: + return a.familyName(); + case Private::GivenName: + return a.givenName(); + case Private::AdditionalName: + return a.additionalName(); + case Private::Prefix: + return a.prefix(); + case Private::Suffix: + return a.suffix(); + case Private::NickName: + return a.nickName(); + case Private::Mailer: + return a.mailer(); + case Private::Title: + return a.title(); + case Private::Role: + return a.role(); + case Private::Organization: + return a.organization(); + case Private::Department: + return a.department(); + case Private::Note: + return a.note(); + case Private::Email: + return a.preferredEmail(); + case Private::Birthday: + if (a.birthday().isValid()) { + return a.birthday().date().toString(Qt::ISODate); + } else { + return QString(); + } + case Private::Url: + return a.url().url().toDisplayString(); + case Private::HomePhone: { + PhoneNumber::List::ConstIterator it; + + { + // check for preferred number + const PhoneNumber::List list = a.phoneNumbers(PhoneNumber::Home | PhoneNumber::Pref); + PhoneNumber::List::ConstIterator end(list.end()); + for (it = list.begin(); it != end; ++it) { + if (((*it).type() & ~(PhoneNumber::Pref)) == PhoneNumber::Home) { + return (*it).number(); + } + } + } + + { + // check for normal home number + const PhoneNumber::List list = a.phoneNumbers(PhoneNumber::Home); + PhoneNumber::List::ConstIterator end(list.end()); + for (it = list.begin(); it != end; ++it) { + if (((*it).type() & ~(PhoneNumber::Pref)) == PhoneNumber::Home) { + return (*it).number(); + } + } + } + + return QString(); + } + case Private::BusinessPhone: { + PhoneNumber::List::ConstIterator it; + + { + // check for preferred number + const PhoneNumber::List list = a.phoneNumbers(PhoneNumber::Work | PhoneNumber::Pref); + PhoneNumber::List::ConstIterator end(list.end()); + for (it = list.begin(); it != end; ++it) { + if (((*it).type() & ~(PhoneNumber::Pref)) == PhoneNumber::Work) { + return (*it).number(); + } + } + } + + { + // check for normal work number + const PhoneNumber::List list = a.phoneNumbers(PhoneNumber::Work); + for (it = list.begin(); it != list.end(); ++it) { + if (((*it).type() & ~(PhoneNumber::Pref)) == PhoneNumber::Work) { + return (*it).number(); + } + } + } + + return QString(); + } + case Private::MobilePhone: + return a.phoneNumber(PhoneNumber::Cell).number(); + case Private::HomeFax: + return a.phoneNumber(PhoneNumber::Home | PhoneNumber::Fax).number(); + case Private::BusinessFax: + return a.phoneNumber(PhoneNumber::Work | PhoneNumber::Fax).number(); + case Private::CarPhone: + return a.phoneNumber(PhoneNumber::Car).number(); + case Private::Isdn: + return a.phoneNumber(PhoneNumber::Isdn).number(); + case Private::Pager: + return a.phoneNumber(PhoneNumber::Pager).number(); + case Private::HomeAddressStreet: + return a.address(Address::Home).street(); + case Private::HomeAddressPostOfficeBox: + return a.address(Address::Home).postOfficeBox(); + case Private::HomeAddressLocality: + return a.address(Address::Home).locality(); + case Private::HomeAddressRegion: + return a.address(Address::Home).region(); + case Private::HomeAddressPostalCode: + return a.address(Address::Home).postalCode(); + case Private::HomeAddressCountry: + return a.address(Address::Home).country(); + case Private::BusinessAddressStreet: + return a.address(Address::Work).street(); + case Private::BusinessAddressPostOfficeBox: + return a.address(Address::Work).postOfficeBox(); + case Private::BusinessAddressLocality: + return a.address(Address::Work).locality(); + case Private::BusinessAddressRegion: + return a.address(Address::Work).region(); + case Private::BusinessAddressPostalCode: + return a.address(Address::Work).postalCode(); + case Private::BusinessAddressCountry: + return a.address(Address::Work).country(); + case Private::CustomField: + return a.custom(d->app(), d->key()); + default: + return QString(); + } +} + +bool Field::setValue(KContacts::Addressee &a, const QString &value) +{ + switch (d->fieldId()) { + case Private::FormattedName: + a.setFormattedName(value); + return true; + case Private::FamilyName: + a.setFamilyName(value); + return true; + case Private::GivenName: + a.setGivenName(value); + return true; + case Private::AdditionalName: + a.setAdditionalName(value); + return true; + case Private::Prefix: + a.setPrefix(value); + return true; + case Private::Suffix: + a.setSuffix(value); + return true; + case Private::NickName: + a.setNickName(value); + return true; + case Private::Mailer: + a.setMailer(value); + return true; + case Private::Title: + a.setTitle(value); + return true; + case Private::Role: + a.setRole(value); + return true; + case Private::Organization: + a.setOrganization(value); + return true; + case Private::Department: + a.setDepartment(value); + return true; + case Private::Note: + a.setNote(value); + return true; + case Private::Birthday: + a.setBirthday(QDateTime::fromString(value, Qt::ISODate)); + return true; + case Private::CustomField: + a.insertCustom(d->app(), d->key(), value); + return true; + default: + return false; + } +} + +QString Field::sortKey(const KContacts::Addressee &a) +{ + switch (d->fieldId()) { + case Private::FormattedName: + return a.formattedName(); + case Private::FamilyName: + return a.familyName(); + case Private::GivenName: + return a.givenName(); + case Private::AdditionalName: + return a.additionalName(); + case Private::Prefix: + return a.prefix(); + case Private::Suffix: + return a.suffix(); + case Private::NickName: + return a.nickName(); + case Private::Mailer: + return a.mailer(); + case Private::Title: + return a.title(); + case Private::Role: + return a.role(); + case Private::Organization: + return a.organization(); + case Private::Department: + return a.department(); + case Private::Note: + return a.note(); + case Private::Birthday: + if (a.birthday().isValid()) { + QDate date = a.birthday().date(); + QString key; + key.sprintf("%02d-%02d", date.month(), date.day()); + return key; + } else { + return QStringLiteral("00-00"); + } + default: + return value(a).toLower(); + } +} + +bool Field::isCustom() +{ + return d->fieldId() == Private::CustomField; +} + +Field::List Field::allFields() +{ + if (Private::mAllFields.isEmpty()) { + createField(Private::FormattedName, Frequent); + createField(Private::FamilyName, Frequent); + createField(Private::GivenName, Frequent); + createField(Private::AdditionalName); + createField(Private::Prefix); + createField(Private::Suffix); + createField(Private::NickName, Personal); + createField(Private::Birthday, Personal); + createField(Private::HomeAddressStreet, Address | Personal); + createField(Private::HomeAddressPostOfficeBox, Address | Personal); + createField(Private::HomeAddressLocality, Address | Personal); + createField(Private::HomeAddressRegion, Address | Personal); + createField(Private::HomeAddressPostalCode, Address | Personal); + createField(Private::HomeAddressCountry, Address | Personal); + createField(Private::HomeAddressLabel, Address | Personal); + createField(Private::BusinessAddressStreet, Address | Organization); + createField(Private::BusinessAddressPostOfficeBox, Address | Organization); + createField(Private::BusinessAddressLocality, Address | Organization); + createField(Private::BusinessAddressRegion, Address | Organization); + createField(Private::BusinessAddressPostalCode, Address | Organization); + createField(Private::BusinessAddressCountry, Address | Organization); + createField(Private::BusinessAddressLabel, Address | Organization); + createField(Private::HomePhone, Personal | Frequent); + createField(Private::BusinessPhone, Organization | Frequent); + createField(Private::MobilePhone, Frequent); + createField(Private::HomeFax); + createField(Private::BusinessFax); + createField(Private::CarPhone); + createField(Private::Isdn); + createField(Private::Pager); + createField(Private::Email, Email | Frequent); + createField(Private::Mailer, Email); + createField(Private::Title, Organization); + createField(Private::Role, Organization); + createField(Private::Organization, Organization); + createField(Private::Department, Organization); + createField(Private::Note); + createField(Private::Url); + } + + return Private::mAllFields; +} + +Field::List Field::defaultFields() +{ + if (Private::mDefaultFields.isEmpty()) { + createDefaultField(Private::FormattedName); + createDefaultField(Private::Email); + } + + return Private::mDefaultFields; +} + +void Field::createField(int id, int category) +{ + Private::mAllFields.append(new Field(new Private(id, category))); +} + +void Field::createDefaultField(int id, int category) +{ + Private::mDefaultFields.append(new Field(new Private(id, category))); +} + +void Field::deleteFields() +{ + Field::List::ConstIterator it; + + for (it = Private::mAllFields.constBegin(); it != Private::mAllFields.constEnd(); ++it) { + delete(*it); + } + Private::mAllFields.clear(); + + for (it = Private::mDefaultFields.constBegin(); it != Private::mDefaultFields.constEnd(); ++it) { + delete(*it); + } + Private::mDefaultFields.clear(); + + for (it = Private::mCustomFields.constBegin(); it != Private::mCustomFields.constEnd(); ++it) { + delete(*it); + } + Private::mCustomFields.clear(); +} + +void Field::saveFields(const QString &identifier, + const Field::List &fields) +{ + KConfigGroup cg(KSharedConfig::openConfig(), "KABCFields"); + + saveFields(cg, identifier, fields); +} + +void Field::saveFields(KConfigGroup &cfg, const QString &identifier, + const Field::List &fields) +{ + QList fieldIds; + + int custom = 0; + Field::List::ConstIterator it; + fieldIds.reserve(fields.count()); + for (it = fields.begin(); it != fields.end(); ++it) { + fieldIds.append((*it)->d->fieldId()); + if ((*it)->isCustom()) { + QStringList customEntry; + customEntry << (*it)->d->label(); + customEntry << (*it)->d->key(); + customEntry << (*it)->d->app(); + cfg.writeEntry(QLatin1String("KCONTACTS_CustomEntry_") + identifier + QLatin1Char('_') + + QString::number(custom++), customEntry); + } + } + + cfg.writeEntry(identifier, fieldIds); +} + +Field::List Field::restoreFields(const QString &identifier) +{ + KConfigGroup cg(KSharedConfig::openConfig(), "KABCFields"); + + return restoreFields(cg, identifier); +} + +Field::List Field::restoreFields(const KConfigGroup &cfg, const QString &identifier) +{ + const QList fieldIds = cfg.readEntry(identifier, QList()); + + Field::List fields; + + int custom = 0; + QList::ConstIterator it; + fields.reserve(fieldIds.count()); + for (it = fieldIds.begin(); it != fieldIds.end(); ++it) { + Private *f = Q_NULLPTR; + if ((*it) == Private::CustomField) { + QStringList customEntry = cfg.readEntry(QLatin1String("KCONTACTS_CustomEntry_") + + identifier + QLatin1Char('_') + + QString::number(custom++), QStringList()); + f = new Private(*it, CustomCategory, customEntry[ 0 ], + customEntry[ 1 ], customEntry[ 2 ]); + } else { + f = new Private(*it); + } + fields.append(new Field(f)); + } + + return fields; +} + +bool Field::equals(Field *field) +{ + bool sameId = (d->fieldId() == field->d->fieldId()); + + if (!sameId) { + return false; + } + + if (d->fieldId() != Private::CustomField) { + return true; + } + + return d->key() == field->d->key(); +} + +Field *Field::createCustomField(const QString &label, int category, + const QString &key, const QString &app) +{ + Field *field = new Field(new Private(Private::CustomField, + category | CustomCategory, + label, key, app)); + Private::mCustomFields.append(field); + + return field; +} diff --git a/src/field.h b/src/field.h new file mode 100644 index 0000000..485ce73 --- /dev/null +++ b/src/field.h @@ -0,0 +1,240 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2002 Cornelius Schumacher + + 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 KCONTACTS_FIELD_H +#define KCONTACTS_FIELD_H + +#include "addressee.h" +#include + +class KConfigGroup; + +namespace KContacts +{ + +/** + * @short Represents a field in the Addressbook + * + * This class represents a field in the Addressbook database. + * It provides methods for accessing meta-information about + * the field (such as label() or category()) as well as + * getting or setting the field's value in an instance of + * Addressee (value(), setValue()). + * + * Furthermore, some static methods are provided for getting + * a list of all fields (allFields(), defaultFields()), for + * creating new fields (createCustomField()) and for saving + * or loading fields to/from a config file (saveFields(), + * restoreFields()). + */ +class KCONTACTS_EXPORT Field +{ +public: + /** + * This type is used for a list of fields. + */ + typedef QList List; + + /** + * Represents the category a field belongs to. + */ + enum FieldCategory { + /** + * All fields + */ + All = 0x0, + /** + * Frequently used fields + */ + Frequent = 0x01, + /** + * Fields which belong to the address, such as Street, City, Zip, etc. + */ + Address = 0x02, + /** + * Fields which store information about the e-mail contact, such as + * e-mail address or mail client + */ + Email = 0x04, + /** + * Personal fields, such as Birthday, Home Address fields, IM Address, etc. + */ + Personal = 0x08, + /** + * Fields about the organization, such as Business Address fields, Department, + * Profession, etc. + */ + Organization = 0x10, + /** + * Custom (user-defined) fields + */ + CustomCategory = 0x20 + }; + + /** + * Returns the translated label for this field. + */ + virtual QString label(); + + /** + * Returns the ored categories the field belongs to. + */ + virtual int category(); + + /** + * Returns the translated label for @p category. + * + * @param category the category of type FieldCategory + * @return the translated label + */ + static QString categoryLabel(int category); + + /** + * Returns a string representation of the value the field has in the given + * Addressee. + * + * @return the string representation of the value or QString(), if it + * is not possible to convert the value to a string. + */ + virtual QString value(const KContacts::Addressee &addressee); + + /** + * Sets the value of the field in the given Addressee. + * + * @return @c true on success or @c false, if the given string couldn't + * be converted to a valid value. + */ + virtual bool setValue(KContacts::Addressee &addressee, const QString &value); + + /** + * Returns a string, that can be used for sorting. + */ + QString sortKey(const KContacts::Addressee &addressee); + + /** + * Returns, if the field is a user-defined field. + * + * @return @c true if this is a custom field, @c false otherwise + */ + virtual bool isCustom(); + + /** + * Returns, if the field is equal with @p field. + * + * @param field the field to compare this field to + * @return @c true if the fields are equal, @c false otherwise + */ + virtual bool equals(Field *field); + + /** + * Returns a list of all fields. + */ + static Field::List allFields(); + + /** + * Returns a list of the default fields. + */ + static Field::List defaultFields(); + + /** + * Creates a custom field. + * + * @param label The label for this field + * @param category The category of this field + * @param key Unique key for this field + * @param app Unique app name for this field + */ + static Field *createCustomField(const QString &label, int category, + const QString &key, const QString &app); + + /** + * Delete all fields from list. + */ + static void deleteFields(); + + /** + * Save the field settings to a config file. + * + * @param cfg The config file object + * @param identifier The unique identifier + * @param fields The list of the fields + */ + static void saveFields(KConfigGroup &cfg, const QString &identifier, + const Field::List &fields); + /** + * @overload + * + * Here, the list is stored in KSharedConfig::openConfig() in group "KABCFields". + * + * @param identifier The unique identifier + * @param fields The list of the fields + */ + static void saveFields(const QString &identifier, + const Field::List &fields); + + /** + * Load the field settings from a config file. + * + * @param cfg The config file object + * @param identifier The unique identifier + */ + static Field::List restoreFields(const KConfigGroup &cfg, const QString &identifier); + + /** + * @overload + * + * Here, the list is loaded from KSharedConfig::openConfig() from group "KABCFields". + * + * @param identifier The unique identifier + */ + static Field::List restoreFields(const QString &identifier); + +protected: + /** + * @internal + * + * Creates a field and appends it to the general list of fields. + * + * @param id The identifier for the field + * @param category The optional category for the field + */ + static void createField(int id, int category = 0); + + /** + * @internal + * + * Creates a field and appends it to the list of default fields. + * + * @param id The identifier for the field + * @param category The optional category for the field + */ + static void createDefaultField(int id, int category = 0); + +private: + class Private; + + Field(Private *p); + virtual ~Field(); + + Private *const d; +}; + +} +#endif diff --git a/src/gender.cpp b/src/gender.cpp new file mode 100644 index 0000000..2303e49 --- /dev/null +++ b/src/gender.cpp @@ -0,0 +1,131 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2015 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 "gender.h" + +#include +#include + +using namespace KContacts; + +class Q_DECL_HIDDEN Gender::Private : public QSharedData +{ +public: + Private() + { + } + + Private(const Private &other) + : QSharedData(other) + { + comment = other.comment; + gender = other.gender; + } + QString gender; + QString comment; +}; + +Gender::Gender() + : d(new Private) +{ + +} + +Gender::Gender(const QString &gender) + : d(new Private) +{ + d->gender = gender; +} + +Gender::Gender(const Gender &other) + : d(other.d) +{ +} + +Gender::~Gender() +{ + +} + +bool Gender::operator==(const Gender &other) const +{ + return (d->comment == other.comment()) && (d->gender == other.gender()); +} + +bool Gender::operator!=(const Gender &other) const +{ + return !(other == *this); +} + +Gender &Gender::operator=(const Gender &other) +{ + if (this != &other) { + d = other.d; + } + + return *this; +} + +QString Gender::toString() const +{ + QString str; + str += QLatin1String("Gender {\n"); + str += QStringLiteral(" gender: %1\n").arg(d->gender); + str += QStringLiteral(" comment: %1\n").arg(d->comment); + str += QLatin1String("}\n"); + return str; +} + +void Gender::setGender(const QString &gender) +{ + d->gender = gender; +} + +QString Gender::gender() const +{ + return d->gender; +} + +void Gender::setComment(const QString &comment) +{ + d->comment = comment; +} + +QString Gender::comment() const +{ + return d->comment; +} + +bool Gender::isValid() const +{ + return !d->gender.isEmpty() || !d->comment.isEmpty(); +} + +QDataStream &KContacts::operator<<(QDataStream &s, const Gender &gender) +{ + return s << gender.d->comment << gender.d->gender; +} + +QDataStream &KContacts::operator>>(QDataStream &s, Gender &gender) +{ + s >> gender.d->comment >> gender.d->gender; + return s; +} + diff --git a/src/gender.h b/src/gender.h new file mode 100644 index 0000000..9bfb5a4 --- /dev/null +++ b/src/gender.h @@ -0,0 +1,72 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2015 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 GENDER_H +#define GENDER_H +#include "kcontacts_export.h" +#include +#include + +/** @short Class that holds a Gender for a contact. + * @since 4.14.5 + */ + +namespace KContacts +{ + +class KCONTACTS_EXPORT Gender +{ + friend KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &, const Gender &); + friend KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &, Gender &); +public: + /** + * Creates an empty Gender object. + */ + Gender(); + Gender(const Gender &other); + Gender(const QString &gender); + + ~Gender(); + + void setGender(const QString &gender); + QString gender() const; + + void setComment(const QString &comment); + QString comment() const; + + bool isValid() const; + + bool operator==(const Gender &other) const; + bool operator!=(const Gender &other) const; + + Gender &operator=(const Gender &other); + + QString toString() const; +private: + class Private; + QSharedDataPointer d; +}; + +KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &stream, const Gender &object); + +KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &stream, Gender &object); +} +Q_DECLARE_TYPEINFO(KContacts::Gender, Q_MOVABLE_TYPE); +#endif // GENDER_H diff --git a/src/geo.cpp b/src/geo.cpp new file mode 100644 index 0000000..4581101 --- /dev/null +++ b/src/geo.cpp @@ -0,0 +1,174 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2001 Cornelius Schumacher + + 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 "geo.h" + +#include +#include + +using namespace KContacts; + +class Q_DECL_HIDDEN Geo::Private : public QSharedData +{ +public: + Private() + : mLatitude(91), mLongitude(181), + mValidLatitude(false), mValidLongitude(false) + { + } + + Private(const Private &other) + : QSharedData(other) + { + mLatitude = other.mLatitude; + mLongitude = other.mLongitude; + mValidLatitude = other.mValidLatitude; + mValidLongitude = other.mValidLongitude; + } + + float mLatitude; + float mLongitude; + + bool mValidLatitude; + bool mValidLongitude; +}; + +Geo::Geo() + : d(new Private) +{ +} + +Geo::Geo(float latitude, float longitude) + : d(new Private) +{ + setLatitude(latitude); + setLongitude(longitude); +} + +Geo::Geo(const Geo &other) + : d(other.d) +{ +} + +Geo::~Geo() +{ +} + +void Geo::setLatitude(float latitude) +{ + if (latitude >= -90 && latitude <= 90) { + d->mLatitude = latitude; + d->mValidLatitude = true; + } else { + d->mLatitude = 91; + d->mValidLatitude = false; + } +} + +float Geo::latitude() const +{ + return d->mLatitude; +} + +void Geo::setLongitude(float longitude) +{ + if (longitude >= -180 && longitude <= 180) { + d->mLongitude = longitude; + d->mValidLongitude = true; + } else { + d->mLongitude = 181; + d->mValidLongitude = false; + } +} + +float Geo::longitude() const +{ + return d->mLongitude; +} + +bool Geo::isValid() const +{ + return d->mValidLatitude && d->mValidLongitude; +} + +bool Geo::operator==(const Geo &other) const +{ + if (!other.isValid() && !isValid()) { + return true; + } + + if (!other.isValid() || !isValid()) { + return false; + } + + if (other.d->mLatitude == d->mLatitude && other.d->mLongitude == d->mLongitude) { + return true; + } + + return false; +} + +bool Geo::operator!=(const Geo &other) const +{ + return !(*this == other); +} + +Geo &Geo::operator=(const Geo &other) +{ + if (this != &other) { + d = other.d; + } + + return *this; +} + +QString Geo::toString() const +{ + QString str; + + str += QLatin1String("Geo {\n"); + str += QStringLiteral(" Valid: %1\n"). + arg(isValid() ? QStringLiteral("true") : QStringLiteral("false")); + str += QStringLiteral(" Latitude: %1\n").arg(d->mLatitude); + str += QStringLiteral(" Longitude: %1\n").arg(d->mLongitude); + str += QLatin1String("}\n"); + + return str; +} + +void Geo::clear() +{ + d->mValidLatitude = false; + d->mValidLongitude = false; +} + +QDataStream &KContacts::operator<<(QDataStream &s, const Geo &geo) +{ + return s << geo.d->mLatitude << geo.d->mValidLatitude + << geo.d->mLongitude << geo.d->mValidLongitude; +} + +QDataStream &KContacts::operator>>(QDataStream &s, Geo &geo) +{ + s >> geo.d->mLatitude >> geo.d->mValidLatitude + >> geo.d->mLongitude >> geo.d->mValidLongitude; + + return s; +} diff --git a/src/geo.h b/src/geo.h new file mode 100644 index 0000000..f455754 --- /dev/null +++ b/src/geo.h @@ -0,0 +1,141 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2001 Cornelius Schumacher + + 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 KCONTACTS_GEO_H +#define KCONTACTS_GEO_H + +#include "kcontacts_export.h" +#include +#include + +namespace KContacts +{ + +/** + * @short Geographic position + * + * This class represents a geographic position. + */ +class KCONTACTS_EXPORT Geo +{ + friend KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &, const Geo &); + friend KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &, Geo &); + +public: + /** + * Creates an invalid geographics position object. + */ + Geo(); + + /** + * Creates a geographics position object. + * + * @param latitude Geographical latitude + * @param longitude Geographical longitude + */ + Geo(float latitude, float longitude); + + /** + * Copy constructor. + */ + Geo(const Geo &other); + + /** + * Destroys the geographics position object. + */ + ~Geo(); + + /** + * Sets the @p latitude. + * + * @param latitude The location's latitude coordinate + */ + void setLatitude(float latitude); + + /** + * Returns the latitude. + */ + float latitude() const; + + /** + * Sets the @p longitude. + * + * @param longitude The location's longitude coordinate + */ + void setLongitude(float longitude); + + /** + * Returns the longitude. + */ + float longitude() const; + + /** + * Returns, whether this object contains a valid geographical position. + */ + bool isValid() const; + + /** + * Equality operator. + * + * @note Two invalid Geo instance will return @c true + */ + bool operator==(const Geo &other) const; + + /** + * Not-Equal operator. + */ + bool operator!=(const Geo &other) const; + + /** + * Assignment operator. + * + * @param other The Geo instance to assign to @c this + */ + Geo &operator=(const Geo &other); + + /** + * Returns string representation of geographical position. + */ + QString toString() const; + + /** + * Clears the class, marking it as invalid. + * + * @since 5.6 + */ + void clear(); + +private: + class Private; + QSharedDataPointer d; +}; + +/** + * Serializes the geographical position @p object into the @p stream. + */ +KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &stream, const Geo &object); + +/** + * Initializes the geographical position @p object from the @p stream. + */ +KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &stream, Geo &object); +} +Q_DECLARE_TYPEINFO(KContacts::Geo, Q_MOVABLE_TYPE); +#endif diff --git a/src/impp.cpp b/src/impp.cpp new file mode 100644 index 0000000..9e41fe9 --- /dev/null +++ b/src/impp.cpp @@ -0,0 +1,195 @@ +/* + This file is part of libkabc. + Copyright (c) 2015 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 "impp.h" + +#include +#include +#include +#include "kcontacts_debug.h" + +using namespace KContacts; + +class Q_DECL_HIDDEN Impp::Private : public QSharedData +{ +public: + Private() + : type(KContacts::Impp::Unknown) + { + } + + Private(const Private &other) + : QSharedData(other) + { + parameters = other.parameters; + type = other.type; + } + QMap parameters; + QString address; + ImppType type; +}; + +Impp::Impp() + : d(new Private) +{ + +} + +Impp::Impp(const Impp &other) + : d(other.d) +{ +} + +Impp::Impp(const QString &address) + : d(new Private) +{ + d->address = address; +} + +Impp::~Impp() +{ + +} + +bool Impp::isValid() const +{ + return !d->address.isEmpty() && (d->type != Unknown); +} + +Impp::ImppType Impp::type() const +{ + return d->type; +} + +void Impp::setType(Impp::ImppType type) +{ + d->type = type; +} + +void Impp::setAddress(const QString &address) +{ + d->address = address; +} + +QString Impp::address() const +{ + return d->address; +} + +void Impp::setParameters(const QMap ¶ms) +{ + d->parameters = params; +} + +QMap Impp::parameters() const +{ + return d->parameters; +} + +bool Impp::operator==(const Impp &other) const +{ + return (d->parameters == other.parameters()) && (d->address == other.address()) && (d->type == other.type()); +} + +bool Impp::operator!=(const Impp &other) const +{ + return !(other == *this); +} + +Impp &Impp::operator=(const Impp &other) +{ + if (this != &other) { + d = other.d; + } + + return *this; +} + +QString Impp::toString() const +{ + QString str; + str += QLatin1String("Impp {\n"); + str += QStringLiteral(" type: %1\n").arg(typeToString(d->type)); + str += QStringLiteral(" address: %1\n").arg(d->address); + if (!d->parameters.isEmpty()) { + QMapIterator i(d->parameters); + QString param; + while (i.hasNext()) { + i.next(); + param += QStringLiteral("%1 %2").arg(i.key(), i.value().join(QStringLiteral(","))); + } + str += QStringLiteral(" parameters: %1\n").arg(param); + } + str += QLatin1String("}\n"); + return str; +} + +QString Impp::typeToString(ImppType type) +{ + switch (type) { + case Unknown: + case EndList: + qCWarning(KCONTACTS_LOG) << "Invalid type requested"; + break; + case Skype: + return QStringLiteral("skype"); + case Xmpp: + return QStringLiteral("xmpp"); + case Jabber: + return QStringLiteral("jabber"); + case Sip: + return QStringLiteral("sip"); + case Aim: + return QStringLiteral("aim"); + case Msn: + return QStringLiteral("msn"); + case Twitter: + return QStringLiteral("twitter"); + case GoogleTalk: + return QStringLiteral("googletalk"); + case Yahoo: + return QStringLiteral("yahoo"); + case Qq: + return QStringLiteral("qq"); + case GaduGadu: + return QStringLiteral("gadugadu"); + case Ownclound: + return QStringLiteral("owncloud-handle"); + case Facebook: + return QStringLiteral("facebook"); + case Icq: + return QStringLiteral("icq"); + } + return QString(); +} + +QDataStream &KContacts::operator<<(QDataStream &s, const Impp &impp) +{ + return s << impp.d->parameters << impp.d->address << impp.d->type; +} + +QDataStream &KContacts::operator>>(QDataStream &s, Impp &impp) +{ + int i; + s >> impp.d->parameters >> impp.d->address >> i; + impp.d->type = static_cast(i); + return s; +} + diff --git a/src/impp.h b/src/impp.h new file mode 100644 index 0000000..167ddb3 --- /dev/null +++ b/src/impp.h @@ -0,0 +1,96 @@ +/* + This file is part of libkabc. + Copyright (c) 2015 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 IMPP_H +#define IMPP_H + +#include "kcontacts_export.h" +#include +#include +#include + +/** @short Class that holds a IMPP for a contact. + * @since 4.14.5 + */ +namespace KContacts +{ +class KCONTACTS_EXPORT Impp +{ + friend KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &, const Impp &); + friend KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &, Impp &); +public: + Impp(); + Impp(const Impp &other); + Impp(const QString &address); + + ~Impp(); + + typedef QVector List; + enum ImppType { + Unknown = 0, + Skype = 1, + Xmpp = 2, + Jabber = 3, + Sip = 4, + Aim = 5, + Msn = 6, + Twitter = 7, + GoogleTalk = 8, + Yahoo = 9, + Qq = 10, + GaduGadu = 11, + Ownclound = 12, + Icq = 13, + Facebook = 14, + EndList + }; + bool isValid() const; + + ImppType type() const; + void setType(ImppType type); + + void setAddress(const QString &address); + QString address() const; + + void setParameters(const QMap ¶ms); + QMap parameters() const; + + bool operator==(const Impp &other) const; + bool operator!=(const Impp &other) const; + + Impp &operator=(const Impp &other); + + QString toString() const; + + static QString typeToString(ImppType type); + +private: + class Private; + QSharedDataPointer d; +}; + +KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &stream, const Impp &object); + +KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &stream, Impp &object); + +} + +Q_DECLARE_TYPEINFO(KContacts::Impp, Q_MOVABLE_TYPE); +#endif // IMPP_H diff --git a/src/key.cpp b/src/key.cpp new file mode 100644 index 0000000..e8d6025 --- /dev/null +++ b/src/key.cpp @@ -0,0 +1,245 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2002 Tobias Koenig + + 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 "key.h" + +#include +#include + +#include +#include + +using namespace KContacts; + +class Q_DECL_HIDDEN Key::Private : public QSharedData +{ +public: + Private() + : mId(KRandom::randomString(8)) + { + } + + Private(const Private &other) + : QSharedData(other) + { + mId = other.mId; + mBinaryData = other.mBinaryData; + mTextData = other.mTextData; + mCustomTypeString = other.mCustomTypeString; + mIsBinary = other.mIsBinary; + mType = other.mType; + } + + QString mId; + QByteArray mBinaryData; + QString mTextData; + QString mCustomTypeString; + + Type mType; + bool mIsBinary; +}; + +Key::Key(const QString &text, Type type) + : d(new Private) +{ + d->mTextData = text; + d->mIsBinary = false; + d->mType = type; +} + +Key::Key(const Key &other) + : d(other.d) +{ +} + +Key::~Key() +{ +} + +bool Key::operator==(const Key &other) const +{ + if (d->mId != other.d->mId) { + return false; + } + + if (d->mType != other.d->mType) { + return false; + } + + if (d->mIsBinary != other.d->mIsBinary) { + return false; + } + + if (d->mIsBinary) { + if (d->mBinaryData != other.d->mBinaryData) { + return false; + } + } else { + if (d->mTextData != other.d->mTextData) { + return false; + } + } + + if (d->mCustomTypeString != other.d->mCustomTypeString) { + return false; + } + + return true; +} + +bool Key::operator!=(const Key &other) const +{ + return !(*this == other); +} + +Key &Key::operator=(const Key &other) +{ + if (this != &other) { + d = other.d; + } + + return *this; +} + +void Key::setId(const QString &id) +{ + d->mId = id; +} + +QString Key::id() const +{ + return d->mId; +} + +void Key::setBinaryData(const QByteArray &binary) +{ + d->mBinaryData = binary; + d->mIsBinary = true; +} + +QByteArray Key::binaryData() const +{ + return d->mBinaryData; +} + +void Key::setTextData(const QString &text) +{ + d->mTextData = text; + d->mIsBinary = false; +} + +QString Key::textData() const +{ + return d->mTextData; +} + +bool Key::isBinary() const +{ + return d->mIsBinary; +} + +void Key::setType(Type type) +{ + d->mType = type; +} + +void Key::setCustomTypeString(const QString &custom) +{ + d->mCustomTypeString = custom; +} + +Key::Type Key::type() const +{ + return d->mType; +} + +QString Key::customTypeString() const +{ + return d->mCustomTypeString; +} + +QString Key::toString() const +{ + QString str; + + str += QLatin1String("Key {\n"); + str += QStringLiteral(" Id: %1\n").arg(d->mId); + str += QStringLiteral(" Type: %1\n").arg(typeLabel(d->mType)); + if (d->mType == Custom) { + str += QStringLiteral(" CustomType: %1\n").arg(d->mCustomTypeString); + } + str += QStringLiteral(" IsBinary: %1\n"). + arg(d->mIsBinary ? QStringLiteral("true") : QStringLiteral("false")); + if (d->mIsBinary) { + str += QStringLiteral(" Binary: %1\n"). + arg(QString::fromLatin1(d->mBinaryData.toBase64())); + } else { + str += QStringLiteral(" Text: %1\n").arg(d->mTextData); + } + str += QLatin1String("}\n"); + + return str; +} + +Key::TypeList Key::typeList() +{ + static TypeList list; + + if (list.isEmpty()) { + list << X509 << PGP << Custom; + } + + return list; +} + +QString Key::typeLabel(Type type) +{ + switch (type) { + case X509: + return i18nc("X.509 public key", "X509"); + break; + case PGP: + return i18nc("Pretty Good Privacy key", "PGP"); + break; + case Custom: + return i18nc("A custom key", "Custom"); + break; + default: + return i18nc("another type of encryption key", "Unknown type"); + break; + } +} + +QDataStream &KContacts::operator<<(QDataStream &s, const Key &key) +{ + return s << key.d->mId << key.d->mType << key.d->mIsBinary << key.d->mBinaryData + << key.d->mTextData << key.d->mCustomTypeString; +} + +QDataStream &KContacts::operator>>(QDataStream &s, Key &key) +{ + uint type; + s >> key.d->mId >> type >> key.d->mIsBinary >> key.d->mBinaryData >> key.d->mTextData + >> key.d->mCustomTypeString; + + key.d->mType = Key::Type(type); + + return s; +} diff --git a/src/key.h b/src/key.h new file mode 100644 index 0000000..67e4776 --- /dev/null +++ b/src/key.h @@ -0,0 +1,186 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2002 Tobias Koenig + + 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 KCONTACTS_KEY_H +#define KCONTACTS_KEY_H + +#include "kcontacts_export.h" + +#include +#include + +namespace KContacts +{ + +/** + * @short A class to store an encryption key. + */ +class KCONTACTS_EXPORT Key +{ + friend KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &, const Key &); + friend KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &, Key &); + +public: + /** + List of keys. + */ + typedef QVector List; + + /** + Key types + */ + enum Type { + X509, /**< X509 key */ + PGP, /**< Pretty Good Privacy key */ + Custom /**< Custom or IANA conform key */ + }; + + /** + List of key types. + */ + typedef QList TypeList; + + /** + Creates a new key. + + @param text The text data. + @param type The key type, see Types. + */ + explicit Key(const QString &text = QString(), Type type = PGP); + + /** + Copy constructor. + */ + Key(const Key &other); + + /** + Destroys the key. + */ + ~Key(); + + /** + Equality operator. + */ + bool operator==(const Key &other) const; + + /** + Not-equal operator. + */ + bool operator!=(const Key &other) const; + + /** + Assignment operator. + + @param other The Key instance to assign to @c this + */ + Key &operator=(const Key &other); + + /** + Sets the unique @p identifier. + */ + void setId(const QString &identifier); + + /** + Returns the unique identifier. + */ + QString id() const; + + /** + Sets binary @p data. + */ + void setBinaryData(const QByteArray &data); + + /** + Returns the binary data. + */ + QByteArray binaryData() const; + + /** + Sets text @p data. + */ + void setTextData(const QString &data); + + /** + Returns the text data. + */ + QString textData() const; + + /** + Returns whether the key contains binary or text data. + */ + bool isBinary() const; + + /** + Sets the @p type. + + @param type The type of the key + + @see Type + */ + void setType(Type type); + + /** + Sets custom @p type string. + */ + void setCustomTypeString(const QString &type); + + /** + Returns the type, see Type. + */ + Type type() const; + + /** + Returns the custom type string. + */ + QString customTypeString() const; + + /** + Returns a string representation of the key. + */ + QString toString() const; + + /** + Returns a list of all available key types. + */ + static TypeList typeList(); + + /** + Returns a translated label for a given key @p type. + */ + static QString typeLabel(Type type); + +private: + class Private; + QSharedDataPointer d; +}; + +/** + Serializes the @p key object into the @p stream. +*/ +KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &stream, const Key &key); + +/** + Initializes the @p key object from the @p stream. +*/ +KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &stream, Key &key); + +} +Q_DECLARE_TYPEINFO(KContacts::Key, Q_MOVABLE_TYPE); +#endif diff --git a/src/lang.cpp b/src/lang.cpp new file mode 100644 index 0000000..ac13611 --- /dev/null +++ b/src/lang.cpp @@ -0,0 +1,139 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2015 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 "lang.h" +#include +#include +#include + +using namespace KContacts; + +class Q_DECL_HIDDEN Lang::Private : public QSharedData +{ +public: + Private() + { + } + + Private(const Private &other) + : QSharedData(other) + { + parameters = other.parameters; + language = other.language; + } + QMap parameters; + QString language; +}; + +Lang::Lang() + : d(new Private) +{ + +} + +Lang::Lang(const Lang &other) + : d(other.d) +{ + +} + +Lang::Lang(const QString &language) + : d(new Private) +{ + d->language = language; +} + +Lang::~Lang() +{ + +} + +void Lang::setLanguage(const QString &lang) +{ + d->language = lang; +} + +QString Lang::language() const +{ + return d->language; +} + +bool Lang::isValid() const +{ + return !d->language.isEmpty(); +} + +void Lang::setParameters(const QMap ¶ms) +{ + d->parameters = params; +} + +QMap Lang::parameters() const +{ + return d->parameters; +} + +bool Lang::operator==(const Lang &other) const +{ + return (d->parameters == other.parameters()) && (d->language == other.language()); +} + +bool Lang::operator!=(const Lang &other) const +{ + return !(other == *this); +} + +Lang &Lang::operator=(const Lang &other) +{ + if (this != &other) { + d = other.d; + } + + return *this; +} + +QString Lang::toString() const +{ + QString str; + str += QLatin1String("Lang {\n"); + str += QStringLiteral(" language: %1\n").arg(d->language); + if (!d->parameters.isEmpty()) { + QMapIterator i(d->parameters); + QString param; + while (i.hasNext()) { + i.next(); + param += QStringLiteral("%1 %2").arg(i.key(), i.value().join(QStringLiteral(","))); + } + str += QStringLiteral(" parameters: %1\n").arg(param); + } + str += QLatin1String("}\n"); + return str; +} + +QDataStream &KContacts::operator<<(QDataStream &s, const Lang &lang) +{ + return s << lang.d->parameters << lang.d->language; +} + +QDataStream &KContacts::operator>>(QDataStream &s, Lang &lang) +{ + s >> lang.d->parameters >> lang.d->language; + return s; +} diff --git a/src/lang.h b/src/lang.h new file mode 100644 index 0000000..75ac551 --- /dev/null +++ b/src/lang.h @@ -0,0 +1,71 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2015 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 LANG_H +#define LANG_H + +#include "kcontacts_export.h" +#include +#include +#include + +/** @short Class that holds a Language for a contact. + * @since 4.14.5 + */ +namespace KContacts +{ +class KCONTACTS_EXPORT Lang +{ + friend KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &, const Lang &); + friend KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &, Lang &); +public: + Lang(); + Lang(const Lang &other); + Lang(const QString &language); + + ~Lang(); + + typedef QVector List; + + void setLanguage(const QString &lang); + QString language() const; + + bool isValid() const; + + void setParameters(const QMap ¶ms); + QMap parameters() const; + + bool operator==(const Lang &other) const; + bool operator!=(const Lang &other) const; + + Lang &operator=(const Lang &other); + + QString toString() const; +private: + class Private; + QSharedDataPointer d; +}; +KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &stream, const Lang &object); + +KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &stream, Lang &object); + +} +Q_DECLARE_TYPEINFO(KContacts::Lang, Q_MOVABLE_TYPE); +#endif // LANG_H diff --git a/src/ldapdn.cpp b/src/ldapdn.cpp new file mode 100644 index 0000000..ff37fdd --- /dev/null +++ b/src/ldapdn.cpp @@ -0,0 +1,208 @@ +/* + A temporary copy to break dependency to KLDAP + + This file is part of libkldap. + Copyright (c) 2006 Sean Harmer + + 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 "ldapdn_p.h" + +#include + +#include "kcontacts_debug.h" + +class Q_DECL_HIDDEN LdapDN::LdapDNPrivate +{ +public: + LdapDNPrivate() : m_dn() {} + ~LdapDNPrivate() {} + + bool isValidRDNString(const QString &rdn) const; + QStringList splitOnNonEscapedChar(const QString &rdn, QChar ch) const; + + QString m_dn; +}; + +bool LdapDN::LdapDNPrivate::isValidRDNString(const QString &rdn) const +{ + qCDebug(KCONTACTS_LOG) << "Testing rdn:" << rdn; + + // If it is a muli-valued rdn, split it into its constituent parts + QStringList rdnParts = splitOnNonEscapedChar(rdn, QLatin1Char('+')); + if (rdnParts.size() > 1) { + for (int i = 0; i < rdnParts.size(); i++) { + if (!isValidRDNString(rdnParts.at(i))) { + return false; + } + } + return true; + } + + // Split the rdn into the attribute name and value parts + const QStringList components = rdn.split(QLatin1Char('=')); + + // We should have exactly two parts + if (components.size() != 2) { + return false; + } + + return true; +} + +QStringList LdapDN::LdapDNPrivate::splitOnNonEscapedChar(const QString &str, QChar ch) const +{ + QStringList strParts; + int index = 0; + int searchFrom = 0; + int strPartStartIndex = 0; + while ((index = str.indexOf(ch, searchFrom)) != -1) { + const QChar prev = str[std::max(0, index - 1)]; + if (prev != QLatin1Char('\\')) { + // Found a component of a multi-valued RDN + //qCDebug(KCONTACTS_LOG) << "Found" << ch << "at index" << index; + QString tmp = str.mid(strPartStartIndex, index - strPartStartIndex); + //qCDebug(KCONTACTS_LOG) << "Adding part:" << tmp; + strParts.append(tmp); + strPartStartIndex = index + 1; + } + + searchFrom = index + 1; + } + + // Add on the part after the last found delimeter + QString tmp = str.mid(strPartStartIndex); + //qCDebug(KCONTACTS_LOG) << "Adding part:" << tmp; + strParts.append(tmp); + + return strParts; +} + +LdapDN::LdapDN() + : d(new LdapDNPrivate) +{ + +} + +LdapDN::LdapDN(const QString &dn) + : d(new LdapDNPrivate) +{ + d->m_dn = dn; +} + +LdapDN::LdapDN(const LdapDN &that) + : d(new LdapDNPrivate) +{ + *d = *that.d; +} + +LdapDN &LdapDN::operator=(const LdapDN &that) +{ + if (this == &that) { + return *this; + } + + *d = *that.d; + return *this; +} + +LdapDN::~LdapDN() +{ + delete d; +} + +void LdapDN::clear() +{ + d->m_dn.clear(); +} + +bool LdapDN::isEmpty() const +{ + return d->m_dn.isEmpty(); +} + +QString LdapDN::toString() const +{ + return d->m_dn; +} + +QString LdapDN::toString(int depth) const +{ + QStringList rdns = d->splitOnNonEscapedChar(d->m_dn, QLatin1Char(',')); + if (depth >= rdns.size()) { + return QString(); + } + + // Construct a DN down to the requested depth + QString dn; + for (int i = depth; i >= 0; i--) { + dn += rdns.at(rdns.size() - 1 - i) + QLatin1Char(','); + qCDebug(KCONTACTS_LOG) << "dn =" << dn; + } + dn = dn.left(dn.length() - 1); // Strip off the extraneous comma + + return dn; +} + +QString LdapDN::rdnString() const +{ + /** \TODO We should move this into the d pointer as we calculate rdns quite a lot */ + QStringList rdns = d->splitOnNonEscapedChar(d->m_dn, QLatin1Char(',')); + return rdns.at(0); +} + +QString LdapDN::rdnString(int depth) const +{ + QStringList rdns = d->splitOnNonEscapedChar(d->m_dn, QLatin1Char(',')); + if (depth >= rdns.size()) { + return QString(); + } + return rdns.at(rdns.size() - 1 - depth); +} + +bool LdapDN::isValid() const +{ + qCDebug(KCONTACTS_LOG) << "Testing dn:" << d->m_dn; + + // Break the string into rdn's + QStringList rdns = d->splitOnNonEscapedChar(d->m_dn, QLatin1Char(',')); + + // Test to see if each rdn is valid + for (int i = 0; i < rdns.size(); i++) { + if (!d->isValidRDNString(rdns.at(i))) { + return false; + } + } + + return true; +} + +int LdapDN::depth() const +{ + QStringList rdns = d->splitOnNonEscapedChar(d->m_dn, QLatin1Char(',')); + return rdns.size(); +} + +bool LdapDN::operator == (const LdapDN &rhs) const +{ + return d->m_dn == rhs.d->m_dn; +} + +bool LdapDN::operator != (const LdapDN &rhs) const +{ + return d->m_dn != rhs.d->m_dn; +} diff --git a/src/ldapdn_p.h b/src/ldapdn_p.h new file mode 100644 index 0000000..9ae33d1 --- /dev/null +++ b/src/ldapdn_p.h @@ -0,0 +1,84 @@ +/* + A temporary copy to break dependency to KLDAP + + This file is part of libkldap. + Copyright (c) 2006 Sean Harmer + + 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 LDAPDN_P_H +#define LDAPDN_P_H + +#include + +class LdapDN +{ +public: + explicit LdapDN(); + explicit LdapDN(const QString &dn); + + LdapDN(const LdapDN &that); + LdapDN &operator=(const LdapDN &that); + + ~LdapDN(); + + void clear(); + + bool isEmpty() const; + + /** + * \returns A QString representing the DN. + */ + QString toString() const; + + /** + * \param depth The depth of the DN to return using a zero-based index. + * \returns A QString representing the DN levels deep in the directory. + */ + QString toString(int depth) const; + + /** + * \returns A QString representing the RDN of this DN. + */ + QString rdnString() const; + + /** + * \param depth The depth of the RDN to return using a zero-based index. + * \returns A QString representing the RDN levels deep in the directory. + */ + QString rdnString(int depth) const; + + /** + * \returns True if this is a valid DN, false otherwise. + */ + bool isValid() const; + + /** + * \returns The depth of this DN in the directory. + */ + int depth() const; + + bool operator==(const LdapDN &rhs) const; + + bool operator!=(const LdapDN &rhs) const; + +private: + class LdapDNPrivate; + LdapDNPrivate *const d; +}; + +#endif diff --git a/src/ldif.cpp b/src/ldif.cpp new file mode 100644 index 0000000..e90b683 --- /dev/null +++ b/src/ldif.cpp @@ -0,0 +1,453 @@ +/* + A temporary copy to break dependency to KLDAP + + This file is part of libkldap. + Copyright (c) 2004-2006 Szombathelyi György + + 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 "ldif_p.h" + +#include "kcontacts_debug.h" + +class Q_DECL_HIDDEN Ldif::LdifPrivate +{ +public: + int mModType; + bool mDelOldRdn, mUrl; + LdapDN mDn; + QString mAttr, mNewRdn, mNewSuperior, mOid; + QByteArray mLdif, mValue; + EntryType mEntryType; + + bool mIsNewLine, mIsComment, mCritical; + ParseValue mLastParseValue; + uint mPos, mLineNumber; + QByteArray mLine; +}; + +Ldif::Ldif() : d(new LdifPrivate) +{ + startParsing(); +} + +Ldif::Ldif(const Ldif &that) : d(new LdifPrivate) +{ + *d = *that.d; + + startParsing(); +} + +Ldif &Ldif::operator=(const Ldif &that) +{ + if (this == &that) { + return *this; + } + + *d = *that.d; + + return *this; +} + +Ldif::~Ldif() +{ + delete d; +} + +QByteArray Ldif::assembleLine(const QString &fieldname, + const QByteArray &value, + uint linelen, bool url) +{ + bool safe = false; + bool isDn; + QByteArray result; + + if (url) { + result = fieldname.toUtf8() + ":< " + value; + } else { + isDn = fieldname.toLower() == QLatin1String("dn"); + //SAFE-INIT-CHAR + if (value.size() > 0 && value[0] > 0 && value[0] != '\n' && + value[0] != '\r' && value[0] != ':' && value[0] != '<') { + safe = true; + } + + //SAFE-CHAR + if (safe) { + for (int i = 1; i < value.size(); ++i) { + //allow utf-8 in Distinguished Names + if ((isDn && value[i] == 0) || + (!isDn && value[i] <= 0) || + value[i] == '\r' || value[i] == '\n') { + safe = false; + break; + } + } + } + + if (value.size() == 0) { + safe = true; + } + + if (safe) { + result = fieldname.toUtf8() + ": " + value; + } else { + result = fieldname.toUtf8() + ":: " + value.toBase64(); + } + + if (linelen > 0) { + int i = (uint)(fieldname.length() + 2) > linelen ? fieldname.length() + 2 : linelen; + while (i < result.length()) { + result.insert(i, "\n "); + i += linelen + 2; + } + } + } + return result; +} + +QByteArray Ldif::assembleLine(const QString &fieldname, const QString &value, + uint linelen, bool url) +{ + return assembleLine(fieldname, value.toUtf8(), linelen, url); +} + +bool Ldif::splitLine(const QByteArray &line, QString &fieldname, QByteArray &value) +{ + int position; + QByteArray tmp; + int linelen; + +// qCDebug(KCONTACTS_LOG) << "line:" << QString::fromUtf8(line); + + position = line.indexOf(":"); + if (position == -1) { + // strange: we did not find a fieldname + fieldname = QLatin1String(""); + value = line.trimmed(); +// qCDebug(KCONTACTS_LOG) << "value :" << value[0]; + return false; + } + + linelen = line.size(); + fieldname = QString::fromUtf8(line.left(position).trimmed()); + + if (linelen > (position + 1) && line[ position + 1 ] == ':') { + // String is BASE64 encoded -> decode it now. + if (linelen <= (position + 3)) { + value.resize(0); + return false; + } + value = QByteArray::fromBase64(line.mid(position + 3)); + return false; + } + + if (linelen > (position + 1) && line[ position + 1 ] == '<') { + // String is an URL. + if (linelen <= (position + 3)) { + value.resize(0); + return false; + } + value = QByteArray::fromBase64(line.mid(position + 3)); + return true; + } + + if (linelen <= (position + 2)) { + value.resize(0); + return false; + } + value = line.mid(position + 2); + return false; +} + +bool Ldif::splitControl(const QByteArray &line, QString &oid, bool &critical, + QByteArray &value) +{ + QString tmp; + critical = false; + bool url = splitLine(line, tmp, value); + + qCDebug(KCONTACTS_LOG) << "value:" << QString::fromUtf8(value); + if (tmp.isEmpty()) { + tmp = QString::fromUtf8(value); + value.resize(0); + } + if (tmp.endsWith(QLatin1String("true"))) { + critical = true; + tmp.truncate(tmp.length() - 5); + } else if (tmp.endsWith(QLatin1String("false"))) { + critical = false; + tmp.truncate(tmp.length() - 6); + } + oid = tmp; + return url; +} + +Ldif::ParseValue Ldif::processLine() +{ + + if (d->mIsComment) { + return None; + } + + ParseValue retval = None; + if (d->mLastParseValue == EndEntry) { + d->mEntryType = Entry_None; + } + + d->mUrl = splitLine(d->mLine, d->mAttr, d->mValue); + + QString attrLower = d->mAttr.toLower(); + + switch (d->mEntryType) { + case Entry_None: + if (attrLower == QLatin1String("version")) { + if (!d->mDn.isEmpty()) { + retval = Err; + } + } else if (attrLower == QLatin1String("dn")) { + qCDebug(KCONTACTS_LOG) << "ldapentry dn:" << QString::fromUtf8(d->mValue); + d->mDn = LdapDN(QString::fromUtf8(d->mValue)); + d->mModType = Mod_None; + retval = NewEntry; + } else if (attrLower == QLatin1String("changetype")) { + if (d->mDn.isEmpty()) { + retval = Err; + } else { + QString tmpval = QString::fromUtf8(d->mValue); + qCDebug(KCONTACTS_LOG) << "changetype:" << tmpval; + if (tmpval == QLatin1String("add")) { + d->mEntryType = Entry_Add; + } else if (tmpval == QLatin1String("delete")) { + d->mEntryType = Entry_Del; + } else if (tmpval == QLatin1String("modrdn") || tmpval == QLatin1String("moddn")) { + d->mNewRdn = QLatin1String(""); + d->mNewSuperior = QLatin1String(""); + d->mDelOldRdn = true; + d->mEntryType = Entry_Modrdn; + } else if (tmpval == QLatin1String("modify")) { + d->mEntryType = Entry_Mod; + } else { + retval = Err; + } + } + } else if (attrLower == QLatin1String("control")) { + d->mUrl = splitControl(d->mValue, d->mOid, d->mCritical, d->mValue); + retval = Control; + } else if (!d->mAttr.isEmpty() && d->mValue.size() > 0) { + d->mEntryType = Entry_Add; + retval = Item; + } + break; + case Entry_Add: + if (d->mAttr.isEmpty() && d->mValue.size() == 0) { + retval = EndEntry; + } else { + retval = Item; + } + break; + case Entry_Del: + if (d->mAttr.isEmpty() && d->mValue.size() == 0) { + retval = EndEntry; + } else { + retval = Err; + } + break; + case Entry_Mod: + if (d->mModType == Mod_None) { + qCDebug(KCONTACTS_LOG) << "new modtype" << d->mAttr; + if (d->mAttr.isEmpty() && d->mValue.size() == 0) { + retval = EndEntry; + } else if (attrLower == QLatin1String("add")) { + d->mModType = Mod_Add; + } else if (attrLower == QLatin1String("replace")) { + d->mModType = Mod_Replace; + d->mAttr = QString::fromUtf8(d->mValue); + d->mValue = QByteArray(); + retval = Item; + } else if (attrLower == QLatin1String("delete")) { + d->mModType = Mod_Del; + d->mAttr = QString::fromUtf8(d->mValue); + d->mValue = QByteArray(); + retval = Item; + } else { + retval = Err; + } + } else { + if (d->mAttr.isEmpty()) { + if (QString::fromUtf8(d->mValue) == QLatin1String("-")) { + d->mModType = Mod_None; + } else if (d->mValue.size() == 0) { + retval = EndEntry; + } else { + retval = Err; + } + } else { + retval = Item; + } + } + break; + case Entry_Modrdn: + if (d->mAttr.isEmpty() && d->mValue.size() == 0) { + retval = EndEntry; + } else if (attrLower == QLatin1String("newrdn")) { + d->mNewRdn = QString::fromUtf8(d->mValue); + } else if (attrLower == QLatin1String("newsuperior")) { + d->mNewSuperior = QString::fromUtf8(d->mValue); + } else if (attrLower == QLatin1String("deleteoldrdn")) { + if (d->mValue.size() > 0 && d->mValue[0] == '0') { + d->mDelOldRdn = false; + } else if (d->mValue.size() > 0 && d->mValue[0] == '1') { + d->mDelOldRdn = true; + } else { + retval = Err; + } + } else { + retval = Err; + } + break; + } + return retval; +} + +Ldif::ParseValue Ldif::nextItem() +{ + ParseValue retval = None; + char c = 0; + + while (retval == None) { + if (d->mPos < (uint)d->mLdif.size()) { + c = d->mLdif[d->mPos]; + d->mPos++; + if (d->mIsNewLine && c == '\r') { + continue; //handle \n\r line end + } + if (d->mIsNewLine && (c == ' ' || c == '\t')) { //line folding + d->mIsNewLine = false; + continue; + } + if (d->mIsNewLine) { + d->mIsNewLine = false; + retval = processLine(); + d->mLastParseValue = retval; + d->mLine.resize(0); + d->mIsComment = (c == '#'); + } + if (c == '\n' || c == '\r') { + d->mLineNumber++; + d->mIsNewLine = true; + continue; + } + } else { + retval = MoreData; + break; + } + + if (!d->mIsComment) { + d->mLine += c; + } + } + return retval; +} + +void Ldif::endLdif() +{ + QByteArray tmp(3, '\n'); + d->mLdif = tmp; + d->mPos = 0; +} + +void Ldif::startParsing() +{ + d->mPos = d->mLineNumber = 0; + d->mDelOldRdn = false; + d->mEntryType = Entry_None; + d->mModType = Mod_None; + d->mDn = LdapDN(); + d->mNewRdn.clear(); + d->mNewSuperior.clear(); + d->mLine = QByteArray(); + d->mIsNewLine = false; + d->mIsComment = false; + d->mLastParseValue = None; +} + +void Ldif::setLdif(const QByteArray &ldif) +{ + d->mLdif = ldif; + d->mPos = 0; +} + +Ldif::EntryType Ldif::entryType() const +{ + return d->mEntryType; +} + +int Ldif::modType() const +{ + return d->mModType; +} + +LdapDN Ldif::dn() const +{ + return d->mDn; +} + +QString Ldif::newRdn() const +{ + return d->mNewRdn; +} + +QString Ldif::newSuperior() const +{ + return d->mNewSuperior; +} + +bool Ldif::delOldRdn() const +{ + return d->mDelOldRdn; +} + +QString Ldif::attr() const +{ + return d->mAttr; +} + +QByteArray Ldif::value() const +{ + return d->mValue; +} + +bool Ldif::isUrl() const +{ + return d->mUrl; +} + +bool Ldif::isCritical() const +{ + return d->mCritical; +} + +QString Ldif::oid() const +{ + return d->mOid; +} + +uint Ldif::lineNumber() const +{ + return d->mLineNumber; +} diff --git a/src/ldif_p.h b/src/ldif_p.h new file mode 100644 index 0000000..a850923 --- /dev/null +++ b/src/ldif_p.h @@ -0,0 +1,197 @@ +/* + A temporary copy to break dependency to KLDAP + + This file is part of libkldap. + Copyright (c) 2004-2006 Szombathelyi György + + 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 LDIF_P_H +#define LDIF_P_H + +#include +#include + +#include "ldapdn_p.h" + +/** + * Ldif + * + * Ldif implements an RFC 2849 compliant Ldif parser. Ldif files are used to + * represent directory information on LDAP-based servers, or to describe a set + * of changes which are to be applied to a directory. + */ +class Ldif +{ +public: + + typedef enum { + None, NewEntry, EndEntry, Item, Control, Err, MoreData + } ParseValue; + + typedef enum { + Entry_None, Entry_Add, Entry_Del, Entry_Mod, Entry_Modrdn + } EntryType; + + typedef enum { + Mod_None, Mod_Add, Mod_Replace, Mod_Del + } ModType; + + Ldif(); + + Ldif(const Ldif &that); + Ldif &operator=(const Ldif &that); + + virtual ~Ldif(); + + /** + * Assembles fieldname and value into a valid Ldif line, BASE64 encodes the + * value if necessary and optionally splits into more lines. + * @param fieldname The name of the entry. + * @param value The value of the entry. + * @param linelen Maximum length of the lines in the result. + * @param url If true, encode value as url ( use :< ). + */ + static QByteArray assembleLine(const QString &fieldname, + const QByteArray &value, uint linelen = 0, + bool url = false); + /** + * This is the same as the above function, the only difference that + * this accepts QString as the value. + */ + static QByteArray assembleLine(const QString &fieldname, + const QString &value, uint linelen = 0, + bool url = false); + + /** + * Splits one line from an Ldif file to attribute and value components. + * @return true if value is an URL, false otherwise + */ + static bool splitLine(const QByteArray &line, QString &fieldname, + QByteArray &value); + + /** + * Splits a control specification (without the "control:" directive) + * @param line is the control directive + * @param oid will contain the OID + * @param critical will contain the criticality of control + * @param value is the control value + */ + static bool splitControl(const QByteArray &line, QString &oid, + bool &critical, QByteArray &value); + + /** + * Starts the parsing of a new Ldif + */ + void startParsing(); + + /** + * Process one Ldif line + */ + ParseValue processLine(); + + /** + * Process the Ldif until a complete item can be returned + * @return NewEntry if a new DN encountered, Item if a new item returned, + * Err if the Ldif contains error, EndEntry if the parser reached the end + * of the current entry and MoreData if the parser encountered the end of + * the current chunk of the Ldif. + * + * If you want to finish the parsing after receiving MoreData, then call + * endLdif(), so the parser can safely flush the current entry. + */ + ParseValue nextItem(); + + /** + * Sets a chunk of Ldif. Call before startParsing(), or if nextItem() + * returned MoreData. + */ + void setLdif(const QByteArray &ldif); + + /** + * Indicates the end of the Ldif file/stream. Call if nextItem() returned + * MoreData, but actually you don't have more data. + */ + void endLdif(); + + /** + * Returns the requested LDAP operation extracted from the current entry. + */ + EntryType entryType() const; + + /** + * Returns the LDAP modify request type if entryType() returned Entry_Mod. + */ + int modType() const; + + /** + * Returns the Distinguished Name of the current entry. + */ + LdapDN dn() const; + + /** + * Returns the new Relative Distinguished Name if modType() returned + * Entry_Modrdn. + */ + QString newRdn() const; + + /** + * Returns the new parent of the entry if modType() returned Entry_Modrdn. + */ + QString newSuperior() const; + + /** + * Returns if the delete of the old RDN is required. + */ + bool delOldRdn() const; + + /** + * Returns the attribute name. + */ + QString attr() const; + + /** + * Returns the attribute value. + */ + QByteArray value() const; + + /** + * Returns if val() is an url + */ + bool isUrl() const; + + /** + * Returns the criticality level when modType() returned Control. + */ + bool isCritical() const; + + /** + * Returns the OID when modType() returned Control. + */ + QString oid() const; + + /** + * Returns the line number which the parser processes. + */ + uint lineNumber() const; + +private: + class LdifPrivate; + LdifPrivate *const d; +}; + +#endif diff --git a/src/phonenumber.cpp b/src/phonenumber.cpp new file mode 100644 index 0000000..de829a3 --- /dev/null +++ b/src/phonenumber.cpp @@ -0,0 +1,272 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2001 Cornelius Schumacher + + 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 "phonenumber.h" + +#include +#include + +#include +#include + +using namespace KContacts; + +static QString cleanupNumber(const QString &input) +{ + return input.simplified(); +} + +class Q_DECL_HIDDEN PhoneNumber::Private : public QSharedData +{ +public: + Private(Type type) + : mId(KRandom::randomString(8)), mType(type) + { + } + + Private(const Private &other) + : QSharedData(other) + { + mId = other.mId; + mType = other.mType; + mNumber = other.mNumber; + } + + QString mId; + QString mNumber; + Type mType; +}; + +PhoneNumber::PhoneNumber() + : d(new Private(Home)) +{ +} + +PhoneNumber::PhoneNumber(const QString &number, Type type) + : d(new Private(type)) +{ + d->mNumber = cleanupNumber(number); +} + +PhoneNumber::PhoneNumber(const PhoneNumber &other) + : d(other.d) +{ +} + +PhoneNumber::~PhoneNumber() +{ +} + +bool PhoneNumber::operator==(const PhoneNumber &other) const +{ + if (d->mId != other.d->mId) { + return false; + } + + if (d->mNumber != other.d->mNumber) { + return false; + } + + if (d->mType != other.d->mType) { + return false; + } + + return true; +} + +bool PhoneNumber::operator!=(const PhoneNumber &other) const +{ + return !(other == *this); +} + +PhoneNumber &PhoneNumber::operator=(const PhoneNumber &other) +{ + if (this != &other) { + d = other.d; + } + + return *this; +} + +bool PhoneNumber::isEmpty() const +{ + return d->mNumber.isEmpty(); +} + +void PhoneNumber::setId(const QString &id) +{ + d->mId = id; +} + +QString PhoneNumber::id() const +{ + return d->mId; +} + +void PhoneNumber::setNumber(const QString &number) +{ + d->mNumber = cleanupNumber(number); +} + +QString PhoneNumber::number() const +{ + return d->mNumber; +} + +void PhoneNumber::setType(Type type) +{ + d->mType = type; +} + +PhoneNumber::Type PhoneNumber::type() const +{ + return d->mType; +} + +QString PhoneNumber::typeLabel() const +{ + return typeLabel(type()); +} + +PhoneNumber::TypeList PhoneNumber::typeList() +{ + static TypeList list; + + if (list.isEmpty()) { + list << Home << Work << Msg << Pref << Voice << Fax << Cell << Video + << Bbs << Modem << Car << Isdn << Pcs << Pager << Undefined; + } + + return list; +} + +QString PhoneNumber::typeFlagLabel(TypeFlag type) +{ + switch (type) { + case Undefined: + return i18nc("Undefined phone type", "Telephone number"); + case Home: + return i18nc("Home phone", "Home"); + case Work: + return i18nc("Work phone", "Work"); + case Msg: + return i18n("Messenger"); + case Pref: + return i18nc("Preferred phone", "Preferred"); + case Voice: + return i18n("Voice"); + case Fax: + return i18n("Fax"); + case Cell: + return i18nc("Mobile Phone", "Mobile"); + case Video: + return i18nc("Video phone", "Video"); + case Bbs: + return i18n("Mailbox"); + case Modem: + return i18n("Modem"); + case Car: + return i18nc("Car Phone", "Car"); + case Isdn: + return i18n("ISDN"); + case Pcs: + return i18n("PCS"); + case Pager: + return i18n("Pager"); + default: + return i18nc("another type of phone", "Other"); + } +} + +QString PhoneNumber::typeLabel(Type type) +{ + QString label; + bool first = true; + + // special cases + // Pref stand alone -> Preferred Number + // Home+Fax or Work+Fax -> combine as initial string + if (type == Pref) { + return i18n("Preferred Number"); + } + + if (type & Fax) { + if (type & Home) { + label = i18n("Home Fax"); + first = false; + type &= ~Fax; + type &= ~Home; + } else if (type & Work) { + label = i18n("Work Fax"); + first = false; + type &= ~Fax; + type &= ~Work; + } + } + + const TypeList list = typeList(); + + TypeList::ConstIterator it; + TypeList::ConstIterator end(list.end()); + for (it = list.begin(); it != end; ++it) { + // these are actually flags + const TypeFlag flag = static_cast(static_cast(*it)); + if (type & flag) { + if (!first) { + label.append(QLatin1Char('/')); + } + + label.append(typeFlagLabel(flag)); + + if (first) { + first = false; + } + } + } + + return label; +} + +QString PhoneNumber::toString() const +{ + QString str; + + str += QLatin1String("PhoneNumber {\n"); + str += QStringLiteral(" Id: %1\n").arg(d->mId); + str += QStringLiteral(" Type: %1\n").arg(typeLabel(d->mType)); + str += QStringLiteral(" Number: %1\n").arg(d->mNumber); + str += QLatin1String("}\n"); + + return str; +} + +QDataStream &KContacts::operator<<(QDataStream &s, const PhoneNumber &phone) +{ + return s << phone.d->mId << (uint)phone.d->mType << phone.d->mNumber; +} + +QDataStream &KContacts::operator>>(QDataStream &s, PhoneNumber &phone) +{ + uint type; + s >> phone.d->mId >> type >> phone.d->mNumber; + phone.d->mType = PhoneNumber::Type(type); + + return s; +} diff --git a/src/phonenumber.h b/src/phonenumber.h new file mode 100644 index 0000000..13eaa9b --- /dev/null +++ b/src/phonenumber.h @@ -0,0 +1,232 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2001 Cornelius Schumacher + + 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 KCONTACTS_PHONENUMBER_H +#define KCONTACTS_PHONENUMBER_H + +#include "kcontacts_export.h" + +#include +#include +#include + +namespace KContacts +{ + +/** + * @short Phonenumber information. + * + * This class provides phone number information. A phone number is classified by + * a type. The following types are available, it's possible to use multiple types + * Types for a number by combining them through a logical or. +*/ +class KCONTACTS_EXPORT PhoneNumber +{ + friend KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &, const PhoneNumber &); + friend KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &, PhoneNumber &); + +public: + /** + Phone number types. + */ + enum TypeFlag { + Home = 1, /**< Home number */ + Work = 2, /**< Office number */ + Msg = 4, /**< Messaging */ + Pref = 8, /**< Preferred number */ + Voice = 16, /**< Voice */ + Fax = 32, /**< Fax machine */ + Cell = 64, /**< Cell phone */ + Video = 128, /**< Video phone */ + Bbs = 256, /**< Mailbox */ + Modem = 512, /**< Modem */ + Car = 1024, /**< Car phone */ + Isdn = 2048, /**< ISDN connection */ + Pcs = 4096, /**< Personal Communication Service*/ + Pager = 8192, /**< Pager */ + Undefined = 16384 /** Undefined number type */ + }; + + Q_DECLARE_FLAGS(Type, TypeFlag) + + /** + * List of phone number types. + */ + typedef QVector TypeList; + + /** + * List of phone numbers. + */ + typedef QVector List; + + /** + * Creates an empty phone number object. + */ + PhoneNumber(); + + /** + * Creates a phone number object. + * + * @param number Number + * @param type Type as defined in enum. Multiple types can be + * specified by combining them by a logical or. + */ + PhoneNumber(const QString &number, Type type = Home); //krazy:exclude=explicit + + /** + * Copy constructor. + * + * Fast operation, PhoneNumber's data is implicitly shared. + * + * @param other The PhoneNumber object to copy from + */ + PhoneNumber(const PhoneNumber &other); + + /** + * Destroys the phone number. + */ + ~PhoneNumber(); + + /** + * Equality operator. + * + * @return @c true if number, type and identifier are equal, + * otherwise @c false + */ + bool operator==(const PhoneNumber &other) const; + + /** + * Not-Equal operator. + */ + bool operator!=(const PhoneNumber &other) const; + + /** + * Assignment operator. + * + * Fast operation, PhoneNumber's data is implicitly shared. + * + * @param other The PhoneNumber object to asssign to @c this + */ + PhoneNumber &operator=(const PhoneNumber &other); + + /** + * Returns true, if the phone number is empty. + */ + bool isEmpty() const; + + /** + * Sets the unique @p identifier. + */ + void setId(const QString &identifier); + + /** + * Returns the unique identifier. + */ + QString id() const; + + /** + * Sets the phone @p number. + */ + void setNumber(const QString &number); + + /** + * Returns the phone number. + */ + QString number() const; + + /** + * Sets the @p type. + * Multiple types can be specified by combining them by a logical or. + * + * @param type The #Type of the phone number + */ + void setType(Type type); + + /** + * Returns the type. Can be a multiple types combined by a logical or. + * + * @see #TypeFlag + * @see typeLabel() + */ + Type type() const; + + /** + * Returns a translated string of the address' type. + */ + QString typeLabel() const; + + /** + * Returns a list of all available types + */ + static TypeList typeList(); + + /** + * Returns the translated label for phone number @p type. + * + * In opposite to typeFlagLabel( TypeFlag type ), it returns all types + * of the phone number concatenated by '/'. + * + * @param type An OR'ed combination of #TypeFlag + * + * @see type() + */ + static QString typeLabel(Type type); + + /** + * Returns the translated label for phone number @p type. + * + * @param type An OR'ed combination of #TypeFlag + * + * @see typeLabel() + * @since 4.5 + */ + static QString typeFlagLabel(TypeFlag type); + + /** + * Returns a string representation of the phone number. + */ + QString toString() const; + +private: + class Private; + QSharedDataPointer d; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(PhoneNumber::Type) + +/** + * Serializes the phone @p number object into the @p stream. + * + * @param stream The stream to write into + * @param number The phone number object to serialize + */ +KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &stream, const PhoneNumber &number); + +/** + * Initializes the phone @p number object from the @p stream. + * + * @param stream The stream to read from + * @param number The phone number object to deserialize into + */ +KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &stream, const PhoneNumber &number); + +} +Q_DECLARE_TYPEINFO(KContacts::PhoneNumber, Q_MOVABLE_TYPE); +#endif diff --git a/src/picture.cpp b/src/picture.cpp new file mode 100644 index 0000000..412c4d6 --- /dev/null +++ b/src/picture.cpp @@ -0,0 +1,250 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2002 Tobias Koenig + + 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 "picture.h" + +#include +#include + +namespace KContacts +{ + +class PicturePrivate : public QSharedData +{ +public: + PicturePrivate() + : mIntern(false) + { + } + + PicturePrivate(const PicturePrivate &other) + : QSharedData(other) + { + mUrl = other.mUrl; + mType = other.mType; + mData = other.mData; + mIntern = other.mIntern; + } + + QString mUrl; + QString mType; + mutable QImage mData; + mutable QByteArray mRawData; + + bool mIntern; +}; + +} + +Q_GLOBAL_STATIC_WITH_ARGS(QSharedDataPointer, s_sharedEmpty, (new KContacts::PicturePrivate)) + +using namespace KContacts; + +Picture::Picture() + : d(*s_sharedEmpty()) +{ +} + +Picture::Picture(const QString &url) + : d(new PicturePrivate) +{ + d->mUrl = url; +} + +Picture::Picture(const QImage &data) + : d(new PicturePrivate) +{ + setData(data); +} + +Picture::Picture(const Picture &other) + : d(other.d) +{ +} + +Picture::~Picture() +{ +} + +Picture &Picture::operator=(const Picture &other) +{ + if (this != &other) { + d = other.d; + } + + return *this; +} + +bool Picture::operator==(const Picture &p) const +{ + if (d->mIntern != p.d->mIntern) { + return false; + } + + if (d->mType != p.d->mType) { + return false; + } + + if (d->mIntern) { + if (!d->mData.isNull() && !p.d->mData.isNull()) { + if (d->mData != p.d->mData) { + return false; + } + } else if (!d->mRawData.isEmpty() && !p.d->mRawData.isEmpty()) { + if (d->mRawData != p.d->mRawData) { + return false; + } + } else if ((!d->mData.isNull() || !d->mRawData.isEmpty()) && + (!p.d->mData.isNull() || !p.d->mRawData.isEmpty())) { + if (data() != p.data()) { + return false; + } + } else { + // if one picture is empty and the other is not + return false; + } + } else { + if (d->mUrl != p.d->mUrl) { + return false; + } + } + + return true; +} + +bool Picture::operator!=(const Picture &p) const +{ + return !(p == *this); +} + +bool Picture::isEmpty() const +{ + return + ((d->mIntern == false && d->mUrl.isEmpty()) || + (d->mIntern == true && d->mData.isNull() && d->mRawData.isEmpty())); +} + +void Picture::setUrl(const QString &url) +{ + d->mUrl = url; + d->mType.clear(); + d->mIntern = false; +} + +void Picture::setUrl(const QString &url, const QString &type) +{ + d->mUrl = url; + d->mType = type; + d->mIntern = false; +} + +void Picture::setData(const QImage &data) +{ + d->mRawData.clear(); + d->mData = data; + d->mIntern = true; + +// set the type, the raw data will have when accessed through Picture::rawData() + if (!d->mData.hasAlphaChannel()) { + d->mType = QStringLiteral("jpeg"); + } else { + d->mType = QStringLiteral("png"); + } +} + +void Picture::setRawData(const QByteArray &rawData, const QString &type) +{ + d->mRawData = rawData; + d->mType = type; + d->mData = QImage(); + d->mIntern = true; +} + +void Picture::setType(const QString &type) +{ + d->mType = type; +} + +bool Picture::isIntern() const +{ + return d->mIntern; +} + +QString Picture::url() const +{ + return d->mUrl; +} + +QImage Picture::data() const +{ + if (d->mData.isNull() && !d->mRawData.isEmpty()) { + d->mData.loadFromData(d->mRawData); + } + + return d->mData; +} + +QByteArray Picture::rawData() const +{ + if (d->mRawData.isEmpty() && !d->mData.isNull()) { + QBuffer buffer(&d->mRawData); + buffer.open(QIODevice::WriteOnly); + + // d->mType was already set accordingly by Picture::setData() + d->mData.save(&buffer, d->mType.toUpper().toLatin1().data()); + } + + return d->mRawData; +} + +QString Picture::type() const +{ + return d->mType; +} + +QString Picture::toString() const +{ + QString str; + + str += QLatin1String("Picture {\n"); + str += QStringLiteral(" Type: %1\n").arg(d->mType); + str += QStringLiteral(" IsIntern: %1\n"). + arg(d->mIntern ? QStringLiteral("true") : QStringLiteral("false")); + if (d->mIntern) { + str += QStringLiteral(" Data: %1\n").arg(QString::fromLatin1(rawData().toBase64())); + } else { + str += QStringLiteral(" Url: %1\n").arg(d->mUrl); + } + str += QLatin1String("}\n"); + + return str; +} + +QDataStream &KContacts::operator<<(QDataStream &s, const Picture &picture) +{ + return s << picture.d->mIntern << picture.d->mUrl << picture.d->mType << picture.data(); +} + +QDataStream &KContacts::operator>>(QDataStream &s, Picture &picture) +{ + s >> picture.d->mIntern >> picture.d->mUrl >> picture.d->mType >> picture.d->mData; + + return s; +} diff --git a/src/picture.h b/src/picture.h new file mode 100644 index 0000000..554c27b --- /dev/null +++ b/src/picture.h @@ -0,0 +1,204 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2002 Tobias Koenig + + 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 KCONTACTS_PICTURE_H +#define KCONTACTS_PICTURE_H + +#include "kcontacts_export.h" + +#include +#include +#include +#include + +namespace KContacts +{ + +class PicturePrivate; + +/** + A class to store a picture of an addressee. It can store the data directly or + an url reference to a picture. +*/ +class KCONTACTS_EXPORT Picture +{ + friend KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &, const Picture &); + friend KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &, Picture &); + +public: + /** + * Creates an empty picture. + */ + Picture(); + + /** + * Creates a picture which points to the given url. + * + * @param url A URL that describes the location of the picture file. + */ + Picture(const QString &url); + + /** + * Creates a picture with the given data. + * + * @param data The raw data of the picture. + */ + Picture(const QImage &data); + + /** + * Copy constructor. + * + * Fast operation, Picture's data is implicitly shared. + * + * @param picture The Picture instance to copy from + */ + Picture(const Picture &picture); + + /** + * Destructor. + */ + ~Picture(); + + typedef QVector List; + /** + * Assignment operator + * + * Fast operation, Picture's data is implicitly shared. + * + * @param other The Picture instance to assign to @c this + */ + Picture &operator=(const Picture &other); + + /** + * Equality operator. + */ + bool operator==(const Picture &other) const; + + /** + * Not-Equal operator. + */ + bool operator!=(const Picture &other) const; + + /** + * Returns true, if the picture is empty. + */ + bool isEmpty() const; + + /** + * Sets a URL for the location of the picture file. When using this + * function, isIntern() will return 'false' until you use + * setData(). + * This also clears the type, as it is unknown. + * + * @param url The location URL of the picture file. + */ + void setUrl(const QString &url); + + /** + * Sets a URL for the location of the picture file. When using this + * function, isIntern() will return 'false' until you use + * setData(). + * + * @param url The location URL of the picture file. + * @param type The encoding format of the image, e.g. jpeg or png + * @since 4.10 + */ + void setUrl(const QString &url, const QString &type); + + /** + * Sets the image data of the picture. When using this function, + * isIntern() will return 'true' until you use setUrl(). + * This also sets type to "png" or "jpeg" depending + * on whether the image has an alpha channel or not. + * + * @param data The image data of the picture. + */ + void setData(const QImage &data); + + /** + * Sets the raw data of the picture. When using this function, + * isIntern() will return 'true' until you use setUrl(). + * + * @param rawData The raw data of the picture. + * @param type The encoding format of the image, e.g. jpeg or png + * @since 4.10 + */ + void setRawData(const QByteArray &rawData, const QString &type); + + /** + * Sets the type of the picture. + * @param type the picture's data type + * @deprecated type should only be set along with setRawData() + */ + void KCONTACTS_DEPRECATED setType(const QString &type); + + /** + * Returns whether the picture is described by a URL (extern) or + * by the raw data (intern). + * When this method returns 'true' you can use data() to + * get the raw data. Otherwise you can request the URL of this + * picture by url() and load the raw data from that location. + */ + bool isIntern() const; + + /** + * Returns the location URL of this picture. + */ + QString url() const; + + /** + * Returns the image data of this picture. + */ + QImage data() const; + + /** + * Returns the raw data of this picture. + * + * @since 4.10 + */ + QByteArray rawData() const; + + /** + * Returns the type of this picture. + */ + QString type() const; + + /** + * Returns string representation of the picture. + */ + QString toString() const; + +private: + QSharedDataPointer d; +}; + +/** + * Serializes the @p picture object into the @p stream. + */ +KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &stream, const Picture &picture); + +/** + * Initializes the @p picture object from the @p stream. + */ +KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &stream, Picture &picture); + +} +Q_DECLARE_TYPEINFO(KContacts::Picture, Q_MOVABLE_TYPE); +#endif diff --git a/src/related.cpp b/src/related.cpp new file mode 100644 index 0000000..244ea26 --- /dev/null +++ b/src/related.cpp @@ -0,0 +1,139 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2015 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 "related.h" +#include +#include +#include + +using namespace KContacts; + +class Q_DECL_HIDDEN Related::Private : public QSharedData +{ +public: + Private() + { + } + + Private(const Private &other) + : QSharedData(other) + { + parameters = other.parameters; + relatedTo = other.relatedTo; + } + QMap parameters; + QString relatedTo; +}; + +Related::Related() + : d(new Private) +{ + +} + +Related::Related(const Related &other) + : d(other.d) +{ + +} + +Related::Related(const QString &relatedTo) + : d(new Private) +{ + d->relatedTo = relatedTo; +} + +Related::~Related() +{ + +} + +void Related::setRelated(const QString &relatedTo) +{ + d->relatedTo = relatedTo; +} + +QString Related::related() const +{ + return d->relatedTo; +} + +bool Related::isValid() const +{ + return !d->relatedTo.isEmpty(); +} + +void Related::setParameters(const QMap ¶ms) +{ + d->parameters = params; +} + +QMap Related::parameters() const +{ + return d->parameters; +} + +bool Related::operator==(const Related &other) const +{ + return (d->parameters == other.parameters()) && (d->relatedTo == other.related()); +} + +bool Related::operator!=(const Related &other) const +{ + return !(other == *this); +} + +Related &Related::operator=(const Related &other) +{ + if (this != &other) { + d = other.d; + } + + return *this; +} + +QString Related::toString() const +{ + QString str; + str += QLatin1String("Related {\n"); + str += QStringLiteral(" relatedTo: %1\n").arg(d->relatedTo); + if (!d->parameters.isEmpty()) { + QMapIterator i(d->parameters); + QString param; + while (i.hasNext()) { + i.next(); + param += QStringLiteral("%1 %2").arg(i.key(), i.value().join(QStringLiteral(","))); + } + str += QStringLiteral(" parameters: %1\n").arg(param); + } + str += QLatin1String("}\n"); + return str; +} + +QDataStream &KContacts::operator<<(QDataStream &s, const Related &related) +{ + return s << related.d->parameters << related.d->relatedTo; +} + +QDataStream &KContacts::operator>>(QDataStream &s, Related &related) +{ + s >> related.d->parameters >> related.d->relatedTo; + return s; +} diff --git a/src/related.h b/src/related.h new file mode 100644 index 0000000..0dd314f --- /dev/null +++ b/src/related.h @@ -0,0 +1,68 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2015 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 RELATED_H +#define RELATED_H + +#include "kcontacts_export.h" +#include +#include +#include + +namespace KContacts +{ +class KCONTACTS_EXPORT Related +{ + friend KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &, const Related &); + friend KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &, Related &); +public: + Related(); + Related(const Related &other); + Related(const QString &related); + + ~Related(); + + typedef QVector List; + + void setRelated(const QString &relatedTo); + QString related() const; + + bool isValid() const; + + void setParameters(const QMap ¶ms); + QMap parameters() const; + + bool operator==(const Related &other) const; + bool operator!=(const Related &other) const; + + Related &operator=(const Related &other); + + QString toString() const; +private: + class Private; + QSharedDataPointer d; +}; +KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &stream, const Related &object); + +KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &stream, Related &object); + +} +Q_DECLARE_TYPEINFO(KContacts::Related, Q_MOVABLE_TYPE); +#endif // LANG_H diff --git a/src/resourcelocatorurl.cpp b/src/resourcelocatorurl.cpp new file mode 100644 index 0000000..076aca6 --- /dev/null +++ b/src/resourcelocatorurl.cpp @@ -0,0 +1,133 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2015 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 "resourcelocatorurl.h" +#include +#include +#include +#include + +using namespace KContacts; + +class Q_DECL_HIDDEN ResourceLocatorUrl::Private : public QSharedData +{ +public: + Private() + { + } + + Private(const Private &other) + : QSharedData(other) + { + parameters = other.parameters; + url = other.url; + } + QMap parameters; + QUrl url; +}; + +ResourceLocatorUrl::ResourceLocatorUrl() + : d(new Private) +{ +} + +ResourceLocatorUrl::ResourceLocatorUrl(const ResourceLocatorUrl &other) + : d(other.d) +{ +} + +ResourceLocatorUrl::~ResourceLocatorUrl() +{ + +} + +QMap ResourceLocatorUrl::parameters() const +{ + return d->parameters; +} + +bool ResourceLocatorUrl::operator==(const ResourceLocatorUrl &other) const +{ + return (d->parameters == other.parameters()) && (d->url == other.url()); +} + +bool ResourceLocatorUrl::operator!=(const ResourceLocatorUrl &other) const +{ + return !(other == *this); +} + +ResourceLocatorUrl &ResourceLocatorUrl::operator=(const ResourceLocatorUrl &other) +{ + if (this != &other) { + d = other.d; + } + + return *this; +} + +QString ResourceLocatorUrl::toString() const +{ + QString str; + str += QLatin1String("ResourceLocatorUrl {\n"); + str += QStringLiteral(" url: %1\n").arg(d->url.toString()); + if (!d->parameters.isEmpty()) { + QMapIterator i(d->parameters); + QString param; + while (i.hasNext()) { + i.next(); + param += QStringLiteral("%1 %2").arg(i.key(), i.value().join(QStringLiteral(","))); + } + str += QStringLiteral(" parameters: %1\n").arg(param); + } + str += QLatin1String("}\n"); + return str; +} + +void ResourceLocatorUrl::setParameters(const QMap ¶ms) +{ + d->parameters = params; +} + +bool ResourceLocatorUrl::isValid() const +{ + return (d->url.isValid()); +} + +void ResourceLocatorUrl::setUrl(const QUrl &url) +{ + d->url = url; +} + +QUrl ResourceLocatorUrl::url() const +{ + return d->url; +} + +QDataStream &KContacts::operator<<(QDataStream &s, const ResourceLocatorUrl &calUrl) +{ + return s << calUrl.d->parameters << calUrl.d->url; +} + +QDataStream &KContacts::operator>>(QDataStream &s, ResourceLocatorUrl &calUrl) +{ + s >> calUrl.d->parameters >> calUrl.d->url; + return s; +} + diff --git a/src/resourcelocatorurl.h b/src/resourcelocatorurl.h new file mode 100644 index 0000000..4d7ff13 --- /dev/null +++ b/src/resourcelocatorurl.h @@ -0,0 +1,76 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2015 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 RESOURCELOCATORURL_H +#define RESOURCELOCATORURL_H + +#include "kcontacts_export.h" + +#include +#include +#include +class QUrl; +/** @short Class that holds a Resource Locator + * @since 5.0 + */ + +namespace KContacts +{ + +class KCONTACTS_EXPORT ResourceLocatorUrl +{ + friend KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &, const ResourceLocatorUrl &); + friend KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &, ResourceLocatorUrl &); +public: + + ResourceLocatorUrl(); + ResourceLocatorUrl(const ResourceLocatorUrl &other); + + ~ResourceLocatorUrl(); + + typedef QVector List; + + bool isValid() const; + + void setUrl(const QUrl &url); + QUrl url() const; + + void setParameters(const QMap ¶ms); + QMap parameters() const; + + bool operator==(const ResourceLocatorUrl &other) const; + bool operator!=(const ResourceLocatorUrl &other) const; + + ResourceLocatorUrl &operator=(const ResourceLocatorUrl &other); + + QString toString() const; +private: + class Private; + QSharedDataPointer d; +}; + +KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &stream, const ResourceLocatorUrl &object); + +KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &stream, ResourceLocatorUrl &object); + +} +Q_DECLARE_TYPEINFO(KContacts::ResourceLocatorUrl, Q_MOVABLE_TYPE); + +#endif // RESOURCELOCATORURL_H diff --git a/src/secrecy.cpp b/src/secrecy.cpp new file mode 100644 index 0000000..5f22e40 --- /dev/null +++ b/src/secrecy.cpp @@ -0,0 +1,162 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2002 Tobias Koenig + + 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 "secrecy.h" + +#include + +#include +#include + +using namespace KContacts; + +class Q_DECL_HIDDEN Secrecy::PrivateData : public QSharedData +{ +public: + PrivateData() + : mType(Secrecy::Invalid) + { + } + + PrivateData(const PrivateData &other) + : QSharedData(other) + { + mType = other.mType; + } + + Type mType; +}; + +Secrecy::Secrecy(Type type) + : d(new PrivateData) +{ + d->mType = type; +} + +Secrecy::Secrecy(const Secrecy &other) + : d(other.d) +{ +} + +Secrecy::~Secrecy() +{ +} + +Secrecy &Secrecy::operator=(const Secrecy &other) +{ + if (this != &other) { + d = other.d; + } + + return *this; +} + +bool Secrecy::operator==(const Secrecy &other) const +{ + return d->mType == other.d->mType; +} + +bool Secrecy::operator!=(const Secrecy &other) const +{ + return !(*this == other); +} + +bool Secrecy::isValid() const +{ + return d->mType != Invalid; +} + +void Secrecy::setType(Type type) +{ + d->mType = type; +} + +Secrecy::Type Secrecy::type() const +{ + return d->mType; +} + +Secrecy::TypeList Secrecy::typeList() +{ + static TypeList list; + + if (list.isEmpty()) { + list << Public << Private << Confidential; + } + + return list; +} + +QString Secrecy::typeLabel(Type type) +{ + switch (type) { + case Public: + return i18nc("access is for everyone", "Public"); + break; + case Private: + return i18nc("access is by owner only", "Private"); + break; + case Confidential: + return i18nc("access is by owner and a controlled group", "Confidential"); + break; + default: + return i18nc("unknown secrecy type", "Unknown type"); + break; + } +} + +QString Secrecy::toString() const +{ + QString str; + + str += QLatin1String("Secrecy {\n"); + str += QStringLiteral(" Type: %1\n").arg(typeLabel(d->mType)); + str += QLatin1String("}\n"); + + return str; +} + +QDataStream &KContacts::operator<<(QDataStream &s, const Secrecy &secrecy) +{ + return s << (uint)secrecy.d->mType; +} + +QDataStream &KContacts::operator>>(QDataStream &s, Secrecy &secrecy) +{ + uint type; + s >> type; + + switch (type) { + case 0: + secrecy.d->mType = Secrecy::Public; + break; + case 1: + secrecy.d->mType = Secrecy::Private; + break; + case 2: + secrecy.d->mType = Secrecy::Confidential; + break; + default: + secrecy.d->mType = Secrecy::Invalid; + break; + } + + return s; +} diff --git a/src/secrecy.h b/src/secrecy.h new file mode 100644 index 0000000..33f6fc8 --- /dev/null +++ b/src/secrecy.h @@ -0,0 +1,127 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2002 Tobias Koenig + + 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 KCONTACTS_SECRECY_H +#define KCONTACTS_SECRECY_H + +#include "kcontacts_export.h" +#include +#include + +namespace KContacts +{ + +class KCONTACTS_EXPORT Secrecy +{ + friend KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &, const Secrecy &); + friend KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &, Secrecy &); + +public: + /** + * Secrecy types + * + * @li Public - for public access + * @li Private - only private access + * @li Confidential - access for confidential persons + */ + enum Type { + Public, + Private, + Confidential, + Invalid + }; + + /** + * List of secrecy types. + */ + typedef QVector TypeList; + + /** + * Creates a new secrecy of the given type. + * + * @param type The secrecy type. @see Type + */ + Secrecy(Type type = Invalid); + + /** + * Copy constructor. + */ + Secrecy(const Secrecy &other); + + /** + * Destroys the secrecy. + */ + ~Secrecy(); + + Secrecy &operator=(const Secrecy &other); + + bool operator==(const Secrecy &other) const; + bool operator!=(const Secrecy &other) const; + + /** + * Returns if the Secrecy object has a valid value. + */ + bool isValid() const; + + /** + * Sets the @p type. + * + * @param type The #Type of secrecy + */ + void setType(Type type); + + /** + * Returns the type. + */ + Type type() const; + + /** + * Returns a list of all available secrecy types. + */ + static TypeList typeList(); + + /** + * Returns a translated label for a given secrecy @p type. + */ + static QString typeLabel(Type type); + + /** + * Returns a string representation of the secrecy. + */ + QString toString() const; + +private: + class PrivateData; + QSharedDataPointer d; +}; + +/** + * Serializes the @p secrecy object into the @p stream. + */ +KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &stream, const Secrecy &secrecy); + +/** + * Initializes the @p secrecy object from the @p stream. + */ +KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &stream, Secrecy &secrecy); + +} +Q_DECLARE_TYPEINFO(KContacts::Secrecy, Q_MOVABLE_TYPE); +#endif diff --git a/src/sortmode.cpp b/src/sortmode.cpp new file mode 100644 index 0000000..7775eb7 --- /dev/null +++ b/src/sortmode.cpp @@ -0,0 +1,114 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2004 Tobias Koenig + + 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 "sortmode.h" +#include "field.h" + +using namespace KContacts; + +SortMode::~SortMode() +{ +} + +class Q_DECL_HIDDEN NameSortMode::Private +{ +public: + NameType mNameType; + bool mAscendingOrder; +}; + +NameSortMode::NameSortMode() + : d(new Private) +{ + d->mNameType = FormattedName; + d->mAscendingOrder = true; +} + +NameSortMode::NameSortMode(NameType type, bool ascending) + : d(new Private) +{ + d->mNameType = type; + d->mAscendingOrder = ascending; +} + +NameSortMode::~NameSortMode() +{ + delete d; +} + +bool NameSortMode::lesser(const KContacts::Addressee &first, const KContacts::Addressee &second) const +{ + bool lesser = false; + + switch (d->mNameType) { + case FormattedName: + lesser = QString::localeAwareCompare(first.formattedName(), second.formattedName()) < 0; + break; + case FamilyName: + lesser = QString::localeAwareCompare(first.familyName(), second.familyName()) < 0; + break; + case GivenName: + lesser = QString::localeAwareCompare(first.givenName(), second.givenName()) < 0; + break; + default: + lesser = false; + break; + } + + if (!d->mAscendingOrder) { + lesser = !lesser; + } + + return lesser; +} + +class Q_DECL_HIDDEN FieldSortMode::Private +{ +public: + KContacts::Field *mField; + bool mAscendingOrder; +}; + +FieldSortMode::FieldSortMode(KContacts::Field *field, bool ascending) + : d(new Private) +{ + d->mField = field; + d->mAscendingOrder = ascending; +} + +FieldSortMode::~FieldSortMode() +{ + delete d; +} + +bool FieldSortMode::lesser(const KContacts::Addressee &first, const KContacts::Addressee &second) const +{ + if (!d->mField) { + return false; + } else { + bool lesser = + QString::localeAwareCompare(d->mField->value(first), d->mField->value(second)) < 0; + if (!d->mAscendingOrder) { + lesser = !lesser; + } + + return lesser; + } +} diff --git a/src/sortmode.h b/src/sortmode.h new file mode 100644 index 0000000..e81bc66 --- /dev/null +++ b/src/sortmode.h @@ -0,0 +1,137 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2004 Tobias Koenig + + 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 KCONTACTS_SORTMODE_H +#define KCONTACTS_SORTMODE_H + +#include "kcontacts_export.h" +#include "addressee.h" + +namespace KContacts +{ + +class Field; + +/** + @short Sort method for sorting an addressee list. + + This interface should be reimplemented by classes which shall act as + SortModes for KContacts::AddresseeList. +*/ +class KCONTACTS_EXPORT SortMode +{ +public: + virtual ~SortMode(); + + /** + Reimplement this method and return whether the first contact is 'smaller' + than the second. + */ + virtual bool lesser(const KContacts::Addressee &first, const KContacts::Addressee &second) const = 0; +}; + +/** + @short Implements comparison by name. + + This class implements a comparison of two Addressee objects by name. + */ +class KCONTACTS_EXPORT NameSortMode : public SortMode +{ +public: + /** + Specifies which parts of the name are used for comparison. + */ + enum NameType { + FormattedName, /**< use the formatted name, e.g. "John Doe" */ + FamilyName, /**< use the last name, e.g. "Doe" */ + GivenName /**< use the first name, e.g. "John" */ + }; + + /** + Constructor. + + Creates a NameSortMethod with FormattedName as name type set. + */ + NameSortMode(); + + /** + Constructor. + + Creates a NameSortMethod with the specified name type. + + @param type The name type. + @param ascending if @c true, Addressee object are sorted in + ascending order; if @c false, objects are sorted in + descending order + */ + explicit NameSortMode(NameType type, bool ascending = true); + + virtual ~NameSortMode(); + + /** + Returns whether the first contact is 'smaller' then the second. + */ + bool lesser(const KContacts::Addressee &first, const KContacts::Addressee &second) const Q_DECL_OVERRIDE; + +private: + class Private; + Private *const d; + + Q_DISABLE_COPY(NameSortMode) +}; + +/** + @short Implements comparison by an arbitrary field. + + This class implements a comparison of two Addressee objects by the + value of an arbitrary field. + */ +class KCONTACTS_EXPORT FieldSortMode : public SortMode +{ +public: + /** + Constructor. + + Creates a FieldSortMethod with the specified @p field. + + @param field The field. + @param ascending if @c true, Addressee object are sorted in + ascending order; if @c false, objects are sorted in + descending order + */ + explicit FieldSortMode(KContacts::Field *field, bool ascending = true); + + virtual ~FieldSortMode(); + + /** + Returns whether the first contact is 'smaller' then the second. + */ + bool lesser(const KContacts::Addressee &first, const KContacts::Addressee &second) const Q_DECL_OVERRIDE; + +private: + class Private; + Private *const d; + + Q_DISABLE_COPY(FieldSortMode) +}; + +} + +#endif diff --git a/src/sound.cpp b/src/sound.cpp new file mode 100644 index 0000000..6fd53d5 --- /dev/null +++ b/src/sound.cpp @@ -0,0 +1,171 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2002 Tobias Koenig + + 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 "sound.h" + +#include +#include + +using namespace KContacts; + +class Q_DECL_HIDDEN Sound::Private : public QSharedData +{ +public: + Private() + : mIntern(false) + { + } + + Private(const Private &other) + : QSharedData(other) + { + mUrl = other.mUrl; + mData = other.mData; + mIntern = other.mIntern; + } + + QString mUrl; + QByteArray mData; + + bool mIntern; +}; + +Sound::Sound() + : d(new Private) +{ +} + +Sound::Sound(const QString &url) + : d(new Private) +{ + d->mUrl = url; +} + +Sound::Sound(const QByteArray &data) + : d(new Private) +{ + d->mIntern = true; + d->mData = data; +} + +Sound::Sound(const Sound &other) + : d(other.d) +{ +} + +Sound::~Sound() +{ +} + +Sound &Sound::operator=(const Sound &other) +{ + if (this != &other) { + d = other.d; + } + + return *this; +} + +bool Sound::operator==(const Sound &other) const +{ + if (d->mIntern != other.d->mIntern) { + return false; + } + + if (d->mIntern) { + if (d->mData != other.d->mData) { + return false; + } + } else { + if (d->mUrl != other.d->mUrl) { + return false; + } + } + + return true; +} + +bool Sound::operator!=(const Sound &other) const +{ + return !(other == *this); +} + +void Sound::setUrl(const QString &url) +{ + d->mIntern = false; + d->mUrl = url; +} + +void Sound::setData(const QByteArray &data) +{ + d->mIntern = true; + d->mData = data; +} + +bool Sound::isIntern() const +{ + return d->mIntern; +} + +bool Sound::isEmpty() const +{ + return + ((d->mIntern && d->mData.isEmpty()) || (!d->mIntern && d->mUrl.isEmpty())); +} + +QString Sound::url() const +{ + return d->mUrl; +} + +QByteArray Sound::data() const +{ + return d->mData; +} + +QString Sound::toString() const +{ + QString str; + + str += QLatin1String("Sound {\n"); + str += QStringLiteral(" IsIntern: %1\n"). + arg(d->mIntern ? QStringLiteral("true") : QStringLiteral("false")); + if (d->mIntern) { + str += QStringLiteral(" Data: %1\n"). + arg(QString::fromLatin1(d->mData.toBase64())); + } else { + str += QStringLiteral(" Url: %1\n").arg(d->mUrl); + } + str += QLatin1String("}\n"); + + return str; +} + +QDataStream &KContacts::operator<<(QDataStream &s, const Sound &sound) +{ + return s << sound.d->mIntern << sound.d->mUrl << sound.d->mData; +} + +QDataStream &KContacts::operator>>(QDataStream &s, Sound &sound) +{ + s >> sound.d->mIntern >> sound.d->mUrl >> sound.d->mData; + + return s; +} diff --git a/src/sound.h b/src/sound.h new file mode 100644 index 0000000..f9fb1f3 --- /dev/null +++ b/src/sound.h @@ -0,0 +1,184 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2002 Tobias Koenig + + 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 KCONTACTS_SOUND_H +#define KCONTACTS_SOUND_H + +#include "kcontacts_export.h" +#include +#include + +namespace KContacts +{ + +/** @short Class that holds a Sound clip for a contact. + * + * The sound can be played doing something like this: + * + * \code + * KTempFile tmp; + * if ( sound.isIntern() ) { + * tmp.file()->write( sound.data() ); + * tmp.close(); + * KAudioPlayer::play( tmp.name() ); + * } else if( !sound.url().isEmpty() ) { + * QString tmpFile; + * if ( !KIO::NetAccess::download( QUrl( themeURL.url() ), tmpFile, 0 ) ) { + * KMessageBox::error( 0, + * KIO::NetAccess::lastErrorString(), + * i18n( "Failed to download sound file" ), + * KMessageBox::Notify + * ); + * return; + * } + * KAudioPlayer::play( tmpFile ); + * } + * \endcode + * + * Unfortunately, KAudioPlayer::play is ASync, so to delete the temporary file + * the best you can really do is set a timer. + * + */ +class KCONTACTS_EXPORT Sound +{ + friend KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &, const Sound &); + friend KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &, Sound &); + +public: + + /** + * Creates an empty sound object. + */ + Sound(); + + /** + * Creates a sound object for the given url. + * + * @param url A url that describes the position of the sound file. + */ + Sound(const QString &url); + + /** + * Creates a sound object for the given data. + * + * @param data The raw data of the sound. + */ + Sound(const QByteArray &data); + + /** + * Copy constructor. + */ + Sound(const Sound &other); + + /** + * Destroys the sound object. + */ + ~Sound(); + + typedef QVector List; + /** + * Assignment operator. + * + * @param other The sound object to assign to @c this + */ + Sound &operator=(const Sound &other); + + /** + * Equality operator. + * + * @param other The object to compare with + * + * @return @c true if the two objects are equal, otherwise @c false + */ + bool operator==(const Sound &other) const; + + /** + * Not-Equal operator. + * + * @param other The object to compare with + * + * @return @c true if the two objects are not equal, otherwise @c false + */ + bool operator!=(const Sound &other) const; + + /** + * Sets a URL for the location of the sound file. When using this + * function, isIntern() will return 'false' until you use + * setData(). + * + * @param url The location URL of the sound file. + */ + void setUrl(const QString &url); + + /** + * Returns true, if the sound object is empty. + */ + bool isEmpty() const; + + /** + * Sets the raw data of the sound. When using this function, + * isIntern() will return 'true' until you use setUrl(). + * + * @param data The raw data of the sound. + */ + void setData(const QByteArray &data); + + /** + * Returns whether the sound is described by a URL (extern) or + * by the raw data (intern). + * When this method returns 'true' you can use data() to + * get the raw data. Otherwise you can request the URL of this + * sound by url() and load the raw data from that location. + */ + bool isIntern() const; + + /** + * Returns the location URL of this sound. + */ + QString url() const; + + /** + * Returns the raw data of this sound. + */ + QByteArray data() const; + + /** + * Returns string representation of the sound. + */ + QString toString() const; + +private: + class Private; + QSharedDataPointer d; +}; + +/** + * Serializes the @p sound object into the @p stream. + */ +KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &stream, const Sound &sound); + +/** + * Initializes the @p sound object from the @p stream. + */ +KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &stream, Sound &sound); + +} +Q_DECLARE_TYPEINFO(KContacts::Sound, Q_MOVABLE_TYPE); +#endif diff --git a/src/timezone.cpp b/src/timezone.cpp new file mode 100644 index 0000000..b53a2c9 --- /dev/null +++ b/src/timezone.cpp @@ -0,0 +1,134 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2001 Cornelius Schumacher + + 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 "timezone.h" + +#include +#include + +using namespace KContacts; + +class Q_DECL_HIDDEN TimeZone::Private : public QSharedData +{ +public: + Private(int offset = 0, bool valid = false) + : mOffset(offset), mValid(valid) + { + } + + Private(const Private &other) + : QSharedData(other) + { + mOffset = other.mOffset; + mValid = other.mValid; + } + + int mOffset; + bool mValid; +}; + +TimeZone::TimeZone() + : d(new Private) +{ +} + +TimeZone::TimeZone(int offset) + : d(new Private(offset, true)) +{ +} + +TimeZone::TimeZone(const TimeZone &other) + : d(other.d) +{ +} + +TimeZone::~TimeZone() +{ +} + +void TimeZone::setOffset(int offset) +{ + d->mOffset = offset; + d->mValid = true; +} + +int TimeZone::offset() const +{ + return d->mOffset; +} + +bool TimeZone::isValid() const +{ + return d->mValid; +} + +bool TimeZone::operator==(const TimeZone &t) const +{ + if (!t.isValid() && !isValid()) { + return true; + } + + if (!t.isValid() || !isValid()) { + return false; + } + + if (t.d->mOffset == d->mOffset) { + return true; + } + + return false; +} + +bool TimeZone::operator!=(const TimeZone &t) const +{ + return !(*this == t); +} + +TimeZone &TimeZone::operator=(const TimeZone &other) +{ + if (this != &other) { + d = other.d; + } + + return *this; +} + +QString TimeZone::toString() const +{ + QString str; + + str += QLatin1String("TimeZone {\n"); + str += QStringLiteral(" Offset: %1\n").arg(d->mOffset); + str += QLatin1String("}\n"); + + return str; +} + +QDataStream &KContacts::operator<<(QDataStream &s, const TimeZone &zone) +{ + return s << zone.d->mOffset << zone.d->mValid; +} + +QDataStream &KContacts::operator>>(QDataStream &s, TimeZone &zone) +{ + s >> zone.d->mOffset >> zone.d->mValid; + + return s; +} diff --git a/src/timezone.h b/src/timezone.h new file mode 100644 index 0000000..f562649 --- /dev/null +++ b/src/timezone.h @@ -0,0 +1,108 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2001 Cornelius Schumacher + + 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 KCONTACTS_TIMEZONE_H +#define KCONTACTS_TIMEZONE_H + +#include "kcontacts_export.h" +#include +#include + +namespace KContacts +{ + +/** + * @short Time zone information. + * + * This class stores information about a time zone. + */ +class KCONTACTS_EXPORT TimeZone +{ + friend KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &, const TimeZone &); + friend KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &, TimeZone &); + +public: + /** + * Construct invalid time zone. + */ + TimeZone(); + + /** + * Construct time zone. + * + * @param offset Offset in minutes relative to UTC. + */ + TimeZone(int offset); + + /** + * Copy constructor. + */ + TimeZone(const TimeZone &other); + + /** + * Destroys the time zone. + */ + ~TimeZone(); + + /** + * Set time zone offset relative to UTC. + * + * @param offset Offset in minutes. + */ + void setOffset(int offset); + + /** + * Return offset in minutes relative to UTC. + */ + int offset() const; + + /** + * Return, if this time zone object is valid. + */ + bool isValid() const; + + bool operator==(const TimeZone &other) const; + bool operator!=(const TimeZone &other) const; + TimeZone &operator=(const TimeZone &other); + + /** + * Return string representation of time zone offset. + */ + QString toString() const; + +private: + class Private; + QSharedDataPointer d; +}; + +/** + * Serializes the @p timezone object into the @p stream. + */ +KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &stream, const TimeZone &timeZone); + +/** + * Initializes the @p timezone object from the @p stream. + */ +KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &stream, TimeZone &timeZone); + +} +Q_DECLARE_TYPEINFO(KContacts::TimeZone, Q_MOVABLE_TYPE); + +#endif diff --git a/src/vcarddrag.cpp b/src/vcarddrag.cpp new file mode 100644 index 0000000..7d74634 --- /dev/null +++ b/src/vcarddrag.cpp @@ -0,0 +1,91 @@ +/* + This file is part of the KContacts framework. + + Copyright (c) 2002 Tobias Koenig + + 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 "vcarddrag.h" + +#include "converter/vcardconverter.h" + +#include +#include + +using namespace KContacts; + +static QString findCompatibleMimeType(const QMimeData *md) +{ + // check the canonical MIME type first + if (md->hasFormat(KContacts::Addressee::mimeType())) { + return KContacts::Addressee::mimeType(); + } + + const QStringList mimeTypeOffers = md->formats(); + const QMimeDatabase db; + Q_FOREACH (const QString &mimeType, mimeTypeOffers) { + const QMimeType mimeTypePtr = db.mimeTypeForName(mimeType); + if (mimeTypePtr.isValid() && mimeTypePtr.inherits(KContacts::Addressee::mimeType())) { + return mimeType; + } + } + + return QString(); +} + +bool VCardDrag::populateMimeData(QMimeData *md, const QByteArray &content) +{ + md->setData(KContacts::Addressee::mimeType(), content); + return true; +} + +bool VCardDrag::populateMimeData(QMimeData *md, const KContacts::Addressee::List &addressees) +{ + KContacts::VCardConverter converter; + const QByteArray vcards = converter.createVCards(addressees); + if (!vcards.isEmpty()) { + return populateMimeData(md, vcards); + } else { + return false; + } +} + +bool VCardDrag::canDecode(const QMimeData *md) +{ + return !findCompatibleMimeType(md).isEmpty(); +} + +bool VCardDrag::fromMimeData(const QMimeData *md, QByteArray &content) +{ + const QString mimeOffer = findCompatibleMimeType(md); + if (mimeOffer.isEmpty()) { + return false; + } + content = md->data(mimeOffer); + return !content.isEmpty(); +} + +bool VCardDrag::fromMimeData(const QMimeData *md, KContacts::Addressee::List &addressees) +{ + const QString mimeOffer = findCompatibleMimeType(md); + if (mimeOffer.isEmpty()) { + return false; + } + addressees = KContacts::VCardConverter().parseVCards(md->data(mimeOffer)); + return !addressees.isEmpty(); +} + diff --git a/src/vcarddrag.h b/src/vcarddrag.h new file mode 100644 index 0000000..7d95e66 --- /dev/null +++ b/src/vcarddrag.h @@ -0,0 +1,102 @@ +/* + This file is part of the KContacts framework. + + Copyright (c) 2002-2010 Tobias Koenig + + 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 KCONTACTS_VCARDDRAG_H +#define KCONTACTS_VCARDDRAG_H + +#include "kcontacts_export.h" + +#include +#include + +namespace KContacts +{ + +/** + @brief Utility function for implementing drag&drop for vCards + + See the Qt drag'n'drop documentation. + + @since 4.5 +*/ +namespace VCardDrag +{ + +/** + Adds the vCard representation as data of the drag object. + + @param md the object to set the data on + @param content the vCard data to set + + @return Always @c true +*/ +KCONTACTS_EXPORT bool populateMimeData(QMimeData *md, const QByteArray &content); + +/** + Adds the vCard representation as data of the drag object. + + @param md the object to set the data on + @param contacts list of Addressee objects to serialize to vCard + + @return @c true if serializing of the given list worked, otherwise @c false + + @see VCardConverter::createVCards() +*/ +KCONTACTS_EXPORT bool populateMimeData(QMimeData *md, const KContacts::Addressee::List &contacts); + +/** + Returns if drag&drop object can be decoded to vCard. + + @param md the object to check for vCard data + + @return @c true if the given data object contains a vCard MIME type, otherwise @c false +*/ +KCONTACTS_EXPORT bool canDecode(const QMimeData *md); + +/** + Decodes the drag&drop object to vCard component @p content. + + @param md the object to check for vCard data + @param content where to put the vCard data from @p md + + @return @c true if there was data for the vCard MIME type, otherwise @c false + + @see canDecode() +*/ +KCONTACTS_EXPORT bool fromMimeData(const QMimeData *md, QByteArray &content); + +/** + Decodes the MIME data @p md and puts the resulting vCard into @p contactss. + + @param md the object to check for vCard data + @param contacts where to put the parsed vCards from @p md + + @return @c true if there was data for the vCard MIME type and it could be parsed successfully, + otherwise @c false + + @see canDecode() +*/ +KCONTACTS_EXPORT bool fromMimeData(const QMimeData *md, KContacts::Addressee::List &contacts); +} + +} + +#endif // VCARDDRAG_H diff --git a/src/vcardparser/CMakeLists.txt b/src/vcardparser/CMakeLists.txt new file mode 100644 index 0000000..5ada0ee --- /dev/null +++ b/src/vcardparser/CMakeLists.txt @@ -0,0 +1,10 @@ + + +########### install files ############### +install( + FILES + vcard.h + vcardline.h + vcardparser.h + DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/kcontacts COMPONENT Devel +) diff --git a/src/vcardparser/vcard.cpp b/src/vcardparser/vcard.cpp new file mode 100644 index 0000000..59717b3 --- /dev/null +++ b/src/vcardparser/vcard.cpp @@ -0,0 +1,121 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2003 Tobias Koenig + + 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 "vcard.h" +#include + +using namespace KContacts; + +VCard::VCard() +{ +} + +VCard::VCard(const VCard &vcard) +{ + mLineMap = vcard.mLineMap; +} + +VCard::~VCard() +{ +} + +VCard &VCard::operator=(const VCard &vcard) +{ + if (&vcard == this) { + return *this; + } + + mLineMap = vcard.mLineMap; + + return *this; +} + +void VCard::clear() +{ + mLineMap.clear(); +} + +QStringList VCard::identifiers() const +{ + return mLineMap.keys(); +} + +void VCard::addLine(const VCardLine &line) +{ + mLineMap[ line.identifier() ].append(line); +} + +VCardLine::List VCard::lines(const QString &identifier) const +{ + LineMap::ConstIterator it = mLineMap.find(identifier); + if (it == mLineMap.end()) { + return VCardLine::List(); + } + + return *it; +} + +VCardLine VCard::line(const QString &identifier) const +{ + LineMap::ConstIterator it = mLineMap.find(identifier); + if (it == mLineMap.end()) { + return VCardLine(); + } + + if ((*it).isEmpty()) { + return VCardLine(); + } else { + return (*it).first(); + } +} + +void VCard::setVersion(Version version) +{ + mLineMap.remove(QStringLiteral("VERSION")); + + VCardLine line; + line.setIdentifier(QStringLiteral("VERSION")); + if (version == v2_1) { + line.setIdentifier(QStringLiteral("2.1")); + } else if (version == v3_0) { + line.setIdentifier(QStringLiteral("3.0")); + } else if (version == v4_0) { + line.setIdentifier(QStringLiteral("4.0")); + } + + mLineMap[ QStringLiteral("VERSION") ].append(line); +} + +VCard::Version VCard::version() const +{ + LineMap::ConstIterator versionEntry = mLineMap.find(QStringLiteral("VERSION")); + if (versionEntry == mLineMap.end()) { + return v3_0; + } + + VCardLine line = (*versionEntry)[ 0 ]; + if (line.value() == QLatin1String("2.1")) { + return v2_1; + } else if (line.value() == QLatin1String("3.0")) { + return v3_0; + } else { + return v4_0; + } +} diff --git a/src/vcardparser/vcard.h b/src/vcardparser/vcard.h new file mode 100644 index 0000000..9ca5bd7 --- /dev/null +++ b/src/vcardparser/vcard.h @@ -0,0 +1,92 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2003 Tobias Koenig + + 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 VCARDPARSER_VCARD_H +#define VCARDPARSER_VCARD_H + +#include +#include + +#include "vcardline.h" + +namespace KContacts +{ + +class VCard +{ +public: + typedef QVector List; + typedef QMap LineMap; + + enum Version { + v2_1, + v3_0, + v4_0 + }; + + VCard(); + VCard(const VCard &card); + + ~VCard(); + + VCard &operator=(const VCard &card); + + /** + * Removes all lines from the vCard. + */ + void clear(); + + /** + * Returns a list of all identifiers that exists in the vCard. + */ + QStringList identifiers() const; + + /** + * Adds a VCardLine to the VCard + */ + void addLine(const VCardLine &line); + + /** + * Returns all lines of the vcard with a special identifier. + */ + VCardLine::List lines(const QString &identifier) const; + + /** + * Returns only the first line of the vcard with a special identifier. + */ + VCardLine line(const QString &identifier) const; + + /** + * Set the version of the vCard. + */ + void setVersion(Version version); + + /** + * Returns the version of this vCard. + */ + Version version() const; + +private: + LineMap mLineMap; +}; + +} + +#endif diff --git a/src/vcardparser/vcardline.cpp b/src/vcardparser/vcardline.cpp new file mode 100644 index 0000000..d61a6cb --- /dev/null +++ b/src/vcardparser/vcardline.cpp @@ -0,0 +1,139 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2003 Tobias Koenig + + 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 "vcardline.h" + +using namespace KContacts; + +VCardLine::VCardLine() +{ +} + +VCardLine::VCardLine(const QString &identifier) +{ + mIdentifier = identifier; +} + +VCardLine::VCardLine(const QString &identifier, const QVariant &value) +{ + mIdentifier = identifier; + mValue = value; +} + +VCardLine::VCardLine(const VCardLine &line) +{ + mParamMap = line.mParamMap; + mValue = line.mValue; + mIdentifier = line.mIdentifier; +} + +VCardLine::~VCardLine() +{ +} + +VCardLine &VCardLine::operator=(const VCardLine &line) +{ + if (&line == this) { + return *this; + } + + mParamMap = line.mParamMap; + mValue = line.mValue; + mIdentifier = line.mIdentifier; + + return *this; +} + +void VCardLine::setIdentifier(const QString &identifier) +{ + mIdentifier = identifier; +} + +QString VCardLine::identifier() const +{ + return mIdentifier; +} + +void VCardLine::setValue(const QVariant &value) +{ + mValue = value; +} + +QVariant VCardLine::value() const +{ + return mValue; +} + +void VCardLine::setGroup(const QString &group) +{ + mGroup = group; +} + +QString VCardLine::group() const +{ + return mGroup; +} + +bool VCardLine::hasGroup() const +{ + return !mGroup.isEmpty(); +} + +QStringList VCardLine::parameterList() const +{ + return mParamMap.keys(); +} + +void VCardLine::addParameter(const QString ¶m, const QString &value) +{ + QStringList &list = mParamMap[ param ]; + if (!list.contains(value)) { // not included yet + list.append(value); + } +} + +QStringList VCardLine::parameters(const QString ¶m) const +{ + ParamMap::ConstIterator it = mParamMap.find(param); + if (it == mParamMap.end()) { + return QStringList(); + } else { + return *it; + } +} + +QString VCardLine::parameter(const QString ¶m) const +{ + ParamMap::ConstIterator it = mParamMap.find(param); + if (it == mParamMap.end()) { + return QString(); + } else { + if ((*it).isEmpty()) { + return QString(); + } else { + return (*it).first(); + } + } +} + +VCardLine::ParamMap VCardLine::parameterMap() const +{ + return mParamMap; +} diff --git a/src/vcardparser/vcardline.h b/src/vcardparser/vcardline.h new file mode 100644 index 0000000..a50287d --- /dev/null +++ b/src/vcardparser/vcardline.h @@ -0,0 +1,128 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2003 Tobias Koenig + + 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 VCARDLINE_H +#define VCARDLINE_H + +#include +#include +#include +#include + +namespace KContacts +{ + +class VCardLine +{ +public: + typedef QVector List; + typedef QMap ParamMap; + + VCardLine(); + VCardLine(const QString &identifier); + VCardLine(const QString &identifier, const QVariant &value); + VCardLine(const VCardLine &line); + + ~VCardLine(); + + VCardLine &operator=(const VCardLine &line); + + /** + * Sets the identifier of this line e.g. UID, FN, CLASS + * + * @param identifier The VCard identifier of this line + */ + void setIdentifier(const QString &identifier); + + /** + * Returns the identifier of this line. + */ + QString identifier() const; + + /** + * Sets the value of of this line. + */ + void setValue(const QVariant &value); + + /** + * Returns the value of this line. + */ + QVariant value() const; + + /** + * Sets the group the line belongs to. + */ + void setGroup(const QString &group); + + /** + * Returns the group the line belongs to. + */ + QString group() const; + + /** + * Returns whether the line belongs to a group. + */ + bool hasGroup() const; + + /** + * Returns all parameters. + */ + QStringList parameterList() const; + + /** + * Add a new parameter to the line. + * + * @param param Name of the parameter to insert + * @param value Value of the parameter to insert + */ + void addParameter(const QString ¶m, const QString &value); + + /** + * Returns the values of a special parameter. + * You can get a list of all parameters with paramList(). + * + * @param param Name of the parameter to look for + */ + QStringList parameters(const QString ¶m) const; + + /** + * Returns only the first value of a special parameter. + * You can get a list of all parameters with paramList(). + * + * @param param Name of the parameter to look for + */ + QString parameter(const QString ¶m) const; + + /** + * Returns all parameters + * @since 4.14.5 + */ + ParamMap parameterMap() const; + +private: + ParamMap mParamMap; + QString mIdentifier; + QString mGroup; + QVariant mValue; +}; + +} + +#endif diff --git a/src/vcardparser/vcardparser.cpp b/src/vcardparser/vcardparser.cpp new file mode 100644 index 0000000..894d713 --- /dev/null +++ b/src/vcardparser/vcardparser.cpp @@ -0,0 +1,390 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2003 Tobias Koenig + + 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 "vcardparser.h" +#include +#include "kcontacts_debug.h" +#include + +class StringCache +{ +public: + QString fromLatin1(const QByteArray &value) + { + if (value.isEmpty()) { + return QString(); + } + + QHash::const_iterator it = m_values.constFind(value); + if (it != m_values.constEnd()) { + return it.value(); + } + + QString string = QString::fromLatin1(value); + m_values.insert(value, string); + return string; + } + +private: + QHash m_values; +}; + +#define FOLD_WIDTH 75 + +using namespace KContacts; + +static void addEscapes(QByteArray &str, bool excludeEscapteComma) +{ + str.replace('\\', (char *)"\\\\"); + if (!excludeEscapteComma) { + str.replace(',', (char *)"\\,"); + } + str.replace('\r', (char *)"\\r"); + str.replace('\n', (char *)"\\n"); +} + +static void removeEscapes(QByteArray &str) +{ + str.replace((char *)"\\n", "\n"); + str.replace((char *)"\\N", "\n"); + str.replace((char *)"\\r", "\r"); + str.replace((char *)"\\,", ","); + str.replace((char *)"\\\\", "\\"); +} + +VCardParser::VCardParser() + : d(Q_NULLPTR) +{ +} + +VCardParser::~VCardParser() +{ +} + +VCard::List VCardParser::parseVCards(const QByteArray &text) +{ + VCard currentVCard; + VCard::List vCardList; + QByteArray currentLine; + + QList lines = text.split('\n'); + + bool inVCard = false; + QList::Iterator it(lines.begin()); + QList::Iterator linesEnd(lines.end()); + + StringCache cache; + + for (; it != linesEnd; ++it) { + // remove the trailing \r, left from \r\n + if ((*it).endsWith('\r')) { + (*it).chop(1); + } + + if ((*it).startsWith(' ') || + (*it).startsWith('\t')) { //folded line => append to previous + currentLine.append((*it).mid(1)); + continue; + } else { + if ((*it).trimmed().isEmpty()) { // empty line + continue; + } + if (inVCard && !currentLine.isEmpty()) { // now parse the line + int colon = currentLine.indexOf(':'); + if (colon == -1) { // invalid line + currentLine = (*it); + continue; + } + + VCardLine vCardLine; + const QByteArray key = currentLine.left(colon).trimmed(); + QByteArray value = currentLine.mid(colon + 1); + + QList params = key.split(';'); + + // check for group + int groupPos = params[ 0 ].indexOf('.'); + if (groupPos != -1) { + vCardLine.setGroup(cache.fromLatin1(params[ 0 ].left(groupPos))); + vCardLine.setIdentifier(cache.fromLatin1(params[ 0 ].mid(groupPos + 1))); + } else { + vCardLine.setIdentifier(cache.fromLatin1(params[ 0 ])); + } + + if (params.count() > 1) { // find all parameters + QList::ConstIterator paramIt(params.constBegin()); + for (++paramIt; paramIt != params.constEnd(); ++paramIt) { + QList pair = (*paramIt).split('='); + if (pair.count() == 1) { + // correct the fucking 2.1 'standard' + if (pair[ 0 ].toLower() == "quoted-printable") { + pair[ 0 ] = "encoding"; + pair.append("quoted-printable"); + } else if (pair[ 0 ].toLower() == "base64") { + pair[ 0 ] = "encoding"; + pair.append("base64"); + } else { + pair.prepend("type"); + } + } + if (pair[ 1 ].indexOf(',') != -1) { // parameter in type=x,y,z format + const QList args = pair[ 1 ].split(','); + QList::ConstIterator argIt; + QList::ConstIterator argEnd(args.constEnd()); + for (argIt = args.constBegin(); argIt != argEnd; ++argIt) { + vCardLine.addParameter(cache.fromLatin1(pair[ 0 ].toLower()), + cache.fromLatin1(*argIt)); + } + } else { + vCardLine.addParameter(cache.fromLatin1(pair[ 0 ].toLower()), + cache.fromLatin1(pair[ 1 ])); + } + } + } + + removeEscapes(value); + + QByteArray output; + bool wasBase64Encoded = false; + + if (vCardLine.parameterList().contains(QStringLiteral("encoding"))) { + const QString encoding = vCardLine.parameter(QStringLiteral("encoding")).toLower(); + + // have to decode the data + if (encoding == QLatin1String("b") || encoding == QLatin1String("base64")) { + output = QByteArray::fromBase64(value); + wasBase64Encoded = true; + } else if (encoding == QLatin1String("quoted-printable")) { + // join any qp-folded lines + while (value.endsWith('=') && it != linesEnd) { + value.chop(1); // remove the '=' + value.append(*it); + ++it; + // remove the trailing \r, left from \r\n + if ((*it).endsWith('\r')) { + (*it).chop(1); + } + } + KCodecs::quotedPrintableDecode(value, output); + } else if (encoding == QLatin1String("8bit")) { + output = value; + } else { + qDebug("Unknown vcard encoding type!"); + } + } else { + output = value; + } + + if (vCardLine.parameterList().contains(QStringLiteral("charset"))) { + // have to convert the data + QTextCodec *codec = QTextCodec::codecForName( + vCardLine.parameter(QStringLiteral("charset")).toLatin1()); + if (codec) { + vCardLine.setValue(codec->toUnicode(output)); + } else { + vCardLine.setValue(QString::fromUtf8(output)); + } + } else if (wasBase64Encoded) { + vCardLine.setValue(output); + } else { + vCardLine.setValue(QString::fromUtf8(output)); + } + + currentVCard.addLine(vCardLine); + } + + // we do not save the start and end tag as vcardline + if ((*it).toLower().startsWith("begin:vcard")) { //krazy:exclude=strings + inVCard = true; + currentLine.clear(); + currentVCard.clear(); // flush vcard + continue; + } + + if ((*it).toLower().startsWith("end:vcard")) { //krazy:exclude=strings + inVCard = false; + vCardList.append(currentVCard); + currentLine.clear(); + currentVCard.clear(); // flush vcard + continue; + } + + currentLine = (*it); + } + } + + return vCardList; +} + +QByteArray VCardParser::createVCards(const VCard::List &list) +{ + QByteArray text; + QByteArray textLine; + QString encodingType; + QStringList idents; + QStringList params; + QStringList values; + QStringList::ConstIterator identIt; + QStringList::Iterator paramIt; + QStringList::ConstIterator valueIt; + + VCardLine::List lines; + VCardLine::List::ConstIterator lineIt; + VCard::List::ConstIterator cardIt; + + bool hasEncoding; + + text.reserve(list.size() * 300); // reserve memory to be more efficient + + // iterate over the cards + VCard::List::ConstIterator listEnd(list.end()); + for (cardIt = list.begin(); cardIt != listEnd; ++cardIt) { + text.append("BEGIN:VCARD\r\n"); + + idents = (*cardIt).identifiers(); + //VERSION must be first + if (idents.contains(QStringLiteral("VERSION"))) { + const QString str = idents.takeAt(idents.indexOf(QStringLiteral("VERSION"))); + idents.prepend(str); + } + + for (identIt = idents.constBegin(); identIt != idents.constEnd(); ++identIt) { + lines = (*cardIt).lines((*identIt)); + + // iterate over the lines + for (lineIt = lines.constBegin(); lineIt != lines.constEnd(); ++lineIt) { + QVariant val = (*lineIt).value(); + if (val.isValid()) { + if ((*lineIt).hasGroup()) { + textLine = (*lineIt).group().toLatin1() + '.' + (*lineIt).identifier().toLatin1(); + } else { + textLine = (*lineIt).identifier().toLatin1(); + } + + params = (*lineIt).parameterList(); + hasEncoding = false; + if (!params.isEmpty()) { // we have parameters + for (paramIt = params.begin(); paramIt != params.end(); ++paramIt) { + if ((*paramIt) == QLatin1String("encoding")) { + hasEncoding = true; + encodingType = (*lineIt).parameter(QStringLiteral("encoding")).toLower(); + } + + values = (*lineIt).parameters(*paramIt); + for (valueIt = values.constBegin(); valueIt != values.constEnd(); ++valueIt) { + textLine.append(';' + (*paramIt).toLatin1().toUpper()); + if (!(*valueIt).isEmpty()) { + textLine.append('=' + (*valueIt).toLatin1()); + } + } + } + } + + QByteArray input, output; + bool checkMultibyte = false; // avoid splitting a multibyte character + + // handle charset + if ((*lineIt).parameterList().contains(QStringLiteral("charset"))) { + // have to convert the data + const QString value = (*lineIt).value().toString(); + QTextCodec *codec = QTextCodec::codecForName( + (*lineIt).parameter(QStringLiteral("charset")).toLatin1()); + if (codec) { + input = codec->fromUnicode(value); + } else { + checkMultibyte = true; + input = value.toUtf8(); + } + } else if ((*lineIt).value().type() == QVariant::ByteArray) { + input = (*lineIt).value().toByteArray(); + } else { + checkMultibyte = true; + input = (*lineIt).value().toString().toUtf8(); + } + + // handle encoding + if (hasEncoding) { // have to encode the data + if (encodingType == QLatin1String("b")) { + checkMultibyte = false; + output = input.toBase64(); + } else if (encodingType == QLatin1String("quoted-printable")) { + checkMultibyte = false; + KCodecs::quotedPrintableEncode(input, output, false); + } + } else { + output = input; + } + addEscapes(output, ((*lineIt).identifier() == QLatin1String("CATEGORIES") || (*lineIt).identifier() == QLatin1String("GEO"))); + + if (!output.isEmpty()) { + textLine.append(':' + output); + + if (textLine.length() > FOLD_WIDTH) { // we have to fold the line + if (checkMultibyte) { + // RFC 6350: Multi-octet characters MUST remain contiguous. + // we know that textLine contains UTF-8 encoded characters + int lineLength = 0; + for (int i = 0; i < textLine.length(); ++i) { + if ((textLine[i] & 0xC0) == 0xC0) { // a multibyte sequence follows + int sequenceLength = 2; + if ((textLine[i] & 0xE0) == 0xE0) { + sequenceLength = 3; + } else if ((textLine[i] & 0xF0) == 0xF0) { + sequenceLength = 4; + } + if ((lineLength + sequenceLength) > FOLD_WIDTH) { + // the current line would be too long. fold it + text += "\r\n " + textLine.mid(i, sequenceLength); + lineLength = 1 + sequenceLength; // incl. leading space + } else { + text += textLine.mid(i, sequenceLength); + lineLength += sequenceLength; + } + i += sequenceLength - 1; + } else { + text += textLine[i]; + ++lineLength; + } + if ((lineLength == FOLD_WIDTH) && (i < (textLine.length() - 1))) { + text += "\r\n "; + lineLength = 1; // leading space + } + } + text += "\r\n"; + } else { + for (int i = 0; i <= (textLine.length() / FOLD_WIDTH); ++i) { + text.append( + (i == 0 ? "" : " ") + textLine.mid(i * FOLD_WIDTH, FOLD_WIDTH) + "\r\n"); + } + } + } else { + text.append(textLine + "\r\n"); + } + } + } + } + } + + text.append("END:VCARD\r\n"); + text.append("\r\n"); + } + + return text; +} diff --git a/src/vcardparser/vcardparser.h b/src/vcardparser/vcardparser.h new file mode 100644 index 0000000..4fc62a9 --- /dev/null +++ b/src/vcardparser/vcardparser.h @@ -0,0 +1,47 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2003 Tobias Koenig + + 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 VCARDPARSER_H +#define VCARDPARSER_H + +#include "vcard.h" +#include + +namespace KContacts +{ + +class VCardParser +{ +public: + VCardParser(); + ~VCardParser(); + + static VCard::List parseVCards(const QByteArray &text); + static QByteArray createVCards(const VCard::List &list); + +private: + Q_DISABLE_COPY(VCardParser) + class VCardParserPrivate; + VCardParserPrivate *d; +}; + +} + +#endif diff --git a/src/vcardtool.cpp b/src/vcardtool.cpp new file mode 100644 index 0000000..2c532c3 --- /dev/null +++ b/src/vcardtool.cpp @@ -0,0 +1,1409 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2003 Tobias Koenig + Copyright (c) 2015 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 "vcardtool.h" +#include "key.h" +#include "picture.h" +#include "secrecy.h" +#include "sound.h" +#include "lang.h" +#include "gender.h" +#include "related.h" +#include +#include +#include + +using namespace KContacts; + +static bool needsEncoding(const QString &value) +{ + uint length = value.length(); + for (uint i = 0; i < length; ++i) { + char c = value.at(i).toLatin1(); + if ((c < 33 || c > 126) && c != ' ' && c != '=') { + return true; + } + } + + return false; +} + +VCardTool::VCardTool() +{ + mAddressTypeMap.insert(QStringLiteral("dom"), Address::Dom); + mAddressTypeMap.insert(QStringLiteral("intl"), Address::Intl); + mAddressTypeMap.insert(QStringLiteral("postal"), Address::Postal); + mAddressTypeMap.insert(QStringLiteral("parcel"), Address::Parcel); + mAddressTypeMap.insert(QStringLiteral("home"), Address::Home); + mAddressTypeMap.insert(QStringLiteral("work"), Address::Work); + mAddressTypeMap.insert(QStringLiteral("pref"), Address::Pref); + + mPhoneTypeMap.insert(QStringLiteral("HOME"), PhoneNumber::Home); + mPhoneTypeMap.insert(QStringLiteral("WORK"), PhoneNumber::Work); + mPhoneTypeMap.insert(QStringLiteral("MSG"), PhoneNumber::Msg); + mPhoneTypeMap.insert(QStringLiteral("PREF"), PhoneNumber::Pref); + mPhoneTypeMap.insert(QStringLiteral("VOICE"), PhoneNumber::Voice); + mPhoneTypeMap.insert(QStringLiteral("FAX"), PhoneNumber::Fax); + mPhoneTypeMap.insert(QStringLiteral("CELL"), PhoneNumber::Cell); + mPhoneTypeMap.insert(QStringLiteral("VIDEO"), PhoneNumber::Video); + mPhoneTypeMap.insert(QStringLiteral("BBS"), PhoneNumber::Bbs); + mPhoneTypeMap.insert(QStringLiteral("MODEM"), PhoneNumber::Modem); + mPhoneTypeMap.insert(QStringLiteral("CAR"), PhoneNumber::Car); + mPhoneTypeMap.insert(QStringLiteral("ISDN"), PhoneNumber::Isdn); + mPhoneTypeMap.insert(QStringLiteral("PCS"), PhoneNumber::Pcs); + mPhoneTypeMap.insert(QStringLiteral("PAGER"), PhoneNumber::Pager); +} + +VCardTool::~VCardTool() +{ +} + +QByteArray VCardTool::exportVCards(const Addressee::List &list, VCard::Version version) const +{ + return createVCards(list, version, true /*export vcard*/); +} + +QByteArray VCardTool::createVCards(const Addressee::List &list, VCard::Version version) const +{ + return createVCards(list, version, false /*don't export*/); +} + +void VCardTool::addParameter(VCardLine &line, VCard::Version version, const QString &key, const QStringList &valueStringList) const +{ + if (version == VCard::v2_1) { + Q_FOREACH (const QString &valueStr, valueStringList) { + line.addParameter(valueStr, QString()); + } + } else { + line.addParameter(key, valueStringList.join(QStringLiteral(","))); + } +} + +QByteArray VCardTool::createVCards(const Addressee::List &list, + VCard::Version version, bool exportVcard) const +{ + VCard::List vCardList; + + Addressee::List::ConstIterator addrIt; + Addressee::List::ConstIterator listEnd(list.constEnd()); + for (addrIt = list.constBegin(); addrIt != listEnd; ++addrIt) { + VCard card; + QStringList::ConstIterator strIt; + // VERSION + if (version == VCard::v2_1) { + card.addLine(VCardLine(QStringLiteral("VERSION"), QLatin1String("2.1"))); + } else if (version == VCard::v3_0) { + card.addLine(VCardLine(QStringLiteral("VERSION"), QLatin1String("3.0"))); + } else if (version == VCard::v4_0) { + card.addLine(VCardLine(QStringLiteral("VERSION"), QLatin1String("4.0"))); + } + + // ADR + LABEL + const Address::List addresses = (*addrIt).addresses(); + for (Address::List::ConstIterator it = addresses.begin(); it != addresses.end(); ++it) { + QStringList address; + + const bool isEmpty = ((*it).postOfficeBox().isEmpty() && + (*it).extended().isEmpty() && + (*it).street().isEmpty() && + (*it).locality().isEmpty() && + (*it).region().isEmpty() && + (*it).postalCode().isEmpty() && + (*it).country().isEmpty()); + + address.append((*it).postOfficeBox().replace(QLatin1Char(';'), + QLatin1String("\\;"))); + + address.append((*it).extended().replace(QLatin1Char(';'), + QLatin1String("\\;"))); + + address.append((*it).street().replace(QLatin1Char(';'), + QLatin1String("\\;"))); + + address.append((*it).locality().replace(QLatin1Char(';'), + QLatin1String("\\;"))); + + address.append((*it).region().replace(QLatin1Char(';'), + QLatin1String("\\;"))); + + address.append((*it).postalCode().replace(QLatin1Char(';'), + QLatin1String("\\;"))); + + address.append((*it).country().replace(QLatin1Char(';'), + QLatin1String("\\;"))); + + VCardLine adrLine(QStringLiteral("ADR"), address.join(QStringLiteral(";"))); + if (version == VCard::v2_1 && needsEncoding(address.join(QStringLiteral(";")))) { + adrLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8")); + adrLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE")); + } + + VCardLine labelLine(QStringLiteral("LABEL"), (*it).label()); + if (version == VCard::v2_1 && needsEncoding((*it).label())) { + labelLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8")); + labelLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE")); + } + + const bool hasLabel = !(*it).label().isEmpty(); + QMap::ConstIterator typeIt; + QStringList addreLineType; + QStringList labelLineType; + for (typeIt = mAddressTypeMap.constBegin(); + typeIt != mAddressTypeMap.constEnd(); ++typeIt) { + if (typeIt.value() & (*it).type()) { + addreLineType << typeIt.key(); + if (hasLabel) { + labelLineType << typeIt.key(); + } + } + } + + if (!isEmpty) { + addParameter(adrLine, version, QStringLiteral("TYPE"), addreLineType); + card.addLine(adrLine); + } + if (hasLabel) { + addParameter(labelLine, version, QStringLiteral("TYPE"), labelLineType); + card.addLine(labelLine); + } + } + + // BDAY + card.addLine(VCardLine(QStringLiteral("BDAY"), createDateTime((*addrIt).birthday(), version))); + + //Laurent: 31 Jan 2015. Not necessary to export it. When Categories were changes as AkonadiTag nobody thought that it was break categorie support... + //=> not necessary to export just tag... + // CATEGORIES only > 2.1 + if (!exportVcard) { + if (version != VCard::v2_1) { + QStringList categories = (*addrIt).categories(); + QStringList::Iterator catIt; + QStringList::Iterator catEnd(categories.end()); + for (catIt = categories.begin(); catIt != catEnd; ++catIt) { + (*catIt).replace(QLatin1Char(','), QLatin1String("\\,")); + } + + VCardLine catLine(QStringLiteral("CATEGORIES"), categories.join(QStringLiteral(","))); + card.addLine(catLine); + } + } + // MEMBER (only in 4.0) + if (version == VCard::v4_0) { + // The KIND property must be set to "group" in order to use this property. + if ((*addrIt).kind().toLower() == QLatin1String("group")) { + Q_FOREACH (const QString &member, (*addrIt).members()) { + VCardLine line(QStringLiteral("MEMBER"), member); + card.addLine(line); + } + } + } + // SOURCE + Q_FOREACH (const QUrl &url, (*addrIt).sourcesUrlList()) { + VCardLine line = VCardLine(QStringLiteral("SOURCE"), url.url()); + card.addLine(line); + } + + if (version == VCard::v4_0) { + const Related::List relatedList = (*addrIt).relationShips(); + Related::List::ConstIterator relatedIt; + Related::List::ConstIterator relatedEnd(relatedList.end()); + for (relatedIt = relatedList.begin(); relatedIt != relatedEnd; ++relatedIt) { + VCardLine line(QStringLiteral("RELATED"), (*relatedIt).related()); + QMapIterator i((*relatedIt).parameters()); + while (i.hasNext()) { + i.next(); + line.addParameter(i.key(), i.value().join(QStringLiteral(","))); + } + card.addLine(line); + } + } + // CLASS only for version == 3.0 + if (version == VCard::v3_0) { + card.addLine(createSecrecy((*addrIt).secrecy())); + } + // LANG only for version == 4.0 + if (version == VCard::v4_0) { + const Lang::List langList = (*addrIt).langs(); + Lang::List::ConstIterator langIt; + Lang::List::ConstIterator langEnd(langList.end()); + for (langIt = langList.begin(); langIt != langEnd; ++langIt) { + VCardLine line(QStringLiteral("LANG"), (*langIt).language()); + QMapIterator i((*langIt).parameters()); + while (i.hasNext()) { + i.next(); + line.addParameter(i.key(), i.value().join(QStringLiteral(","))); + } + card.addLine(line); + } + } + // EMAIL + const Email::List emailList = (*addrIt).emailList(); + Email::List::ConstIterator emailIt; + Email::List::ConstIterator emailEnd(emailList.end()); + for (emailIt = emailList.begin(); emailIt != emailEnd; ++emailIt) { + VCardLine line(QStringLiteral("EMAIL"), (*emailIt).mail()); + QMapIterator i((*emailIt).parameters()); + while (i.hasNext()) { + i.next(); + if (version == VCard::v2_1) { + if (i.key().toLower() == QLatin1String("type")) { + QStringList valueStringList = i.value(); + bool hasPreferred = false; + if (valueStringList.contains(QStringLiteral("PREF"))) { + valueStringList.removeAll(QStringLiteral("PREF")); + hasPreferred = true; + } + if (!valueStringList.isEmpty()) { + addParameter(line, version, i.key(), valueStringList); + } + if (hasPreferred) { + line.addParameter(QStringLiteral("PREF"), QString()); + } + } else { + line.addParameter(i.key(), i.value().join(QStringLiteral(","))); + } + } else { + line.addParameter(i.key(), i.value().join(QStringLiteral(","))); + } + } + card.addLine(line); + } + + // FN required for only version > 2.1 + VCardLine fnLine(QStringLiteral("FN"), (*addrIt).formattedName()); + if (version == VCard::v2_1 && needsEncoding((*addrIt).formattedName())) { + fnLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8")); + fnLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE")); + } + card.addLine(fnLine); + + // GEO + const Geo geo = (*addrIt).geo(); + if (geo.isValid()) { + QString str; + if (version == VCard::v4_0) { + str.sprintf("geo:%.6f,%.6f", geo.latitude(), geo.longitude()); + } else { + str.sprintf("%.6f;%.6f", geo.latitude(), geo.longitude()); + } + card.addLine(VCardLine(QStringLiteral("GEO"), str)); + } + + // KEY + const Key::List keys = (*addrIt).keys(); + Key::List::ConstIterator keyIt; + Key::List::ConstIterator keyEnd(keys.end()); + for (keyIt = keys.begin(); keyIt != keyEnd; ++keyIt) { + card.addLine(createKey(*keyIt, version)); + } + + // LOGO + card.addLine(createPicture(QStringLiteral("LOGO"), (*addrIt).logo(), version)); + Q_FOREACH (const Picture &logo, (*addrIt).extraLogoList()) { + card.addLine(createPicture(QStringLiteral("LOGO"), logo, version)); + } + + // MAILER only for version < 4.0 + if (version != VCard::v4_0) { + VCardLine mailerLine(QStringLiteral("MAILER"), (*addrIt).mailer()); + if (version == VCard::v2_1 && needsEncoding((*addrIt).mailer())) { + mailerLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8")); + mailerLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE")); + } + card.addLine(mailerLine); + } + + // N required for only version < 4.0 + QStringList name; + name.append((*addrIt).familyName().replace(QLatin1Char(';'), + QLatin1String("\\;"))); + + name.append((*addrIt).givenName().replace(QLatin1Char(';'), + QLatin1String("\\;"))); + + name.append((*addrIt).additionalName().replace(QLatin1Char(';'), + QLatin1String("\\;"))); + + name.append((*addrIt).prefix().replace(QLatin1Char(';'), + QLatin1String("\\;"))); + + name.append((*addrIt).suffix().replace(QLatin1Char(';'), + QLatin1String("\\;"))); + + VCardLine nLine(QStringLiteral("N"), name.join(QStringLiteral(";"))); + if (version == VCard::v2_1 && needsEncoding(name.join(QStringLiteral(";")))) { + nLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8")); + nLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE")); + } + if (version == VCard::v4_0 && !(*addrIt).sortString().isEmpty()) { + nLine.addParameter(QStringLiteral("SORT-AS"), (*addrIt).sortString()); + } + + card.addLine(nLine); + + // NAME only for version < 4.0 + if (version != VCard::v4_0) { + VCardLine nameLine(QStringLiteral("NAME"), (*addrIt).name()); + if (version == VCard::v2_1 && needsEncoding((*addrIt).name())) { + nameLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8")); + nameLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE")); + } + card.addLine(nameLine); + } + + // NICKNAME only for version > 2.1 + if (version != VCard::v2_1) { + card.addLine(VCardLine(QStringLiteral("NICKNAME"), (*addrIt).nickName())); + } + + // NOTE + VCardLine noteLine(QStringLiteral("NOTE"), (*addrIt).note()); + if (version == VCard::v2_1 && needsEncoding((*addrIt).note())) { + noteLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8")); + noteLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE")); + } + card.addLine(noteLine); + + // ORG + QStringList organization; + organization.append((*addrIt).organization().replace(QLatin1Char(';'), + QLatin1String("\\;"))); + if (!(*addrIt).department().isEmpty()) { + organization.append((*addrIt).department().replace(QLatin1Char(';'), + QLatin1String("\\;"))); + } + VCardLine orgLine(QStringLiteral("ORG"), organization.join(QStringLiteral(";"))); + if (version == VCard::v2_1 && needsEncoding(organization.join(QStringLiteral(";")))) { + orgLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8")); + orgLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE")); + } + card.addLine(orgLine); + + // PHOTO + card.addLine(createPicture(QStringLiteral("PHOTO"), (*addrIt).photo(), version)); + Q_FOREACH (const Picture &photo, (*addrIt).extraPhotoList()) { + card.addLine(createPicture(QStringLiteral("PHOTO"), photo, version)); + } + + // PROID only for version > 2.1 + if (version != VCard::v2_1) { + card.addLine(VCardLine(QStringLiteral("PRODID"), (*addrIt).productId())); + } + + // REV + card.addLine(VCardLine(QStringLiteral("REV"), createDateTime((*addrIt).revision(), version))); + + // ROLE + VCardLine roleLine(QStringLiteral("ROLE"), (*addrIt).role()); + if (version == VCard::v2_1 && needsEncoding((*addrIt).role())) { + roleLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8")); + roleLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE")); + } + card.addLine(roleLine); + + // SORT-STRING + if (version == VCard::v3_0) { + card.addLine(VCardLine(QStringLiteral("SORT-STRING"), (*addrIt).sortString())); + } + + // SOUND + card.addLine(createSound((*addrIt).sound(), version)); + Q_FOREACH (const Sound &sound, (*addrIt).extraSoundList()) { + card.addLine(createSound(sound, version)); + } + + // TEL + const PhoneNumber::List phoneNumbers = (*addrIt).phoneNumbers(); + PhoneNumber::List::ConstIterator phoneIt; + PhoneNumber::List::ConstIterator phoneEnd(phoneNumbers.end()); + for (phoneIt = phoneNumbers.begin(); phoneIt != phoneEnd; ++phoneIt) { + VCardLine line(QStringLiteral("TEL"), (*phoneIt).number()); + + QMap::ConstIterator typeIt; + QMap::ConstIterator typeEnd(mPhoneTypeMap.constEnd()); + QStringList lst; + for (typeIt = mPhoneTypeMap.constBegin(); typeIt != typeEnd; ++typeIt) { + if (typeIt.value() & (*phoneIt).type()) { + lst << typeIt.key(); + + } + } + if (!lst.isEmpty()) { + addParameter(line, version, QStringLiteral("TYPE"), lst); + } + card.addLine(line); + } + + // TITLE + VCardLine titleLine(QStringLiteral("TITLE"), (*addrIt).title()); + if (version == VCard::v2_1 && needsEncoding((*addrIt).title())) { + titleLine.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8")); + titleLine.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE")); + } + card.addLine(titleLine); + + // TZ + // TODO Add vcard4.0 support + const TimeZone timeZone = (*addrIt).timeZone(); + if (timeZone.isValid()) { + QString str; + + int neg = 1; + if (timeZone.offset() < 0) { + neg = -1; + } + + str.sprintf("%c%02d:%02d", (timeZone.offset() >= 0 ? '+' : '-'), + (timeZone.offset() / 60) * neg, + (timeZone.offset() % 60) * neg); + + card.addLine(VCardLine(QStringLiteral("TZ"), str)); + } + + // UID + card.addLine(VCardLine(QStringLiteral("UID"), (*addrIt).uid())); + + // URL + Q_FOREACH (const ResourceLocatorUrl &url, (*addrIt).extraUrlList()) { + VCardLine line(QStringLiteral("URL"), url.url()); + QMapIterator i(url.parameters()); + while (i.hasNext()) { + i.next(); + line.addParameter(i.key(), i.value().join(QStringLiteral(","))); + } + card.addLine(line); + } + if (version == VCard::v4_0) { + // GENDER + const Gender gender = (*addrIt).gender(); + if (gender.isValid()) { + QString genderStr; + if (!gender.gender().isEmpty()) { + genderStr = gender.gender(); + } + if (!gender.comment().isEmpty()) { + genderStr += QLatin1Char(';') + gender.comment(); + } + VCardLine line(QStringLiteral("GENDER"), genderStr); + card.addLine(line); + } + // KIND + if (!(*addrIt).kind().isEmpty()) { + VCardLine line(QStringLiteral("KIND"), (*addrIt).kind()); + card.addLine(line); + } + } + // From vcard4. + if (version == VCard::v4_0) { + Q_FOREACH (const CalendarUrl &url, (*addrIt).calendarUrlList()) { + if (url.isValid()) { + QString type; + switch (url.type()) { + case CalendarUrl::Unknown: + case CalendarUrl::EndCalendarType: + break; + case CalendarUrl::FBUrl: + type = QStringLiteral("FBURL"); + break; + case CalendarUrl::CALUri: + type = QStringLiteral("CALURI"); + break; + case CalendarUrl::CALADRUri: + type = QStringLiteral("CALADRURI"); + break; + + } + if (!type.isEmpty()) { + VCardLine line(type, url.url().toDisplayString()); + QMapIterator i(url.parameters()); + while (i.hasNext()) { + i.next(); + line.addParameter(i.key(), i.value().join(QStringLiteral(","))); + } + card.addLine(line); + } + } + } + } + // IMPP (supported in vcard 3 too) + Q_FOREACH (const Impp &impp, (*addrIt).imppList()) { + VCardLine line(QStringLiteral("IMPP"), impp.address()); + line.addParameter(QStringLiteral("X-SERVICE-TYPE"), Impp::typeToString(impp.type())); + QMapIterator i(impp.parameters()); + while (i.hasNext()) { + i.next(); + if (i.key().toLower() != QStringLiteral("x-service-type")) { + line.addParameter(i.key(), i.value().join(QStringLiteral(","))); + } + } + card.addLine(line); + } + + // X- + const QStringList customs = (*addrIt).customs(); + for (strIt = customs.begin(); strIt != customs.end(); ++strIt) { + QString identifier = QLatin1String("X-") + + (*strIt).left((*strIt).indexOf(QLatin1Char(':'))); + const QString value = (*strIt).mid((*strIt).indexOf(QLatin1Char(':')) + 1); + if (value.isEmpty()) { + continue; + } + //Convert to standard identifier + if (exportVcard) { + if (identifier == QLatin1String("X-messaging/aim-All")) { + identifier = QStringLiteral("X-AIM"); + } else if (identifier == QLatin1String("X-messaging/icq-All")) { + identifier = QStringLiteral("X-ICQ"); + } else if (identifier == QLatin1String("X-messaging/xmpp-All")) { + identifier = QStringLiteral("X-JABBER"); + } else if (identifier == QLatin1String("X-messaging/msn-All")) { + identifier = QStringLiteral("X-MSN"); + } else if (identifier == QLatin1String("X-messaging/yahoo-All")) { + identifier = QStringLiteral("X-YAHOO"); + } else if (identifier == QLatin1String("X-messaging/gadu-All")) { + identifier = QStringLiteral("X-GADUGADU"); + } else if (identifier == QLatin1String("X-messaging/skype-All")) { + identifier = QStringLiteral("X-SKYPE"); + } else if (identifier == QLatin1String("X-messaging/groupwise-All")) { + identifier = QStringLiteral("X-GROUPWISE"); + } else if (identifier == QLatin1String("X-messaging/sms-All")) { + identifier = QStringLiteral("X-SMS"); + } else if (identifier == QLatin1String("X-messaging/meanwhile-All")) { + identifier = QStringLiteral("X-MEANWHILE"); + } else if (identifier == QLatin1String("X-messaging/irc-All")) { + identifier = QStringLiteral("X-IRC"); //Not defined by rfc but need for fixing #300869 + } else if (identifier == QLatin1String("X-messaging/googletalk-All")) { + //Not defined by rfc but need for fixing #300869 + identifier = QStringLiteral("X-GTALK"); + } else if (identifier == QLatin1String("X-messaging/twitter-All")) { + identifier = QStringLiteral("X-TWITTER"); + } + } + if (identifier.toLower() == QLatin1String("x-kaddressbook-x-anniversary") && version == VCard::v4_0) { + // ANNIVERSARY + if (!value.isEmpty()) { + const QDate date = QDate::fromString(value, Qt::ISODate); + QDateTime dt = QDateTime(date); + dt.setTime(QTime()); + card.addLine(VCardLine(QStringLiteral("ANNIVERSARY"), createDateTime(dt, version))); + } + } else { + VCardLine line(identifier, value); + if (version == VCard::v2_1 && needsEncoding(value)) { + line.addParameter(QStringLiteral("charset"), QStringLiteral("UTF-8")); + line.addParameter(QStringLiteral("encoding"), QStringLiteral("QUOTED-PRINTABLE")); + } + card.addLine(line); + } + } + + vCardList.append(card); + } + + return VCardParser::createVCards(vCardList); +} + +Addressee::List VCardTool::parseVCards(const QByteArray &vcard) const +{ + static const QLatin1Char semicolonSep(';'); + static const QLatin1Char commaSep(','); + QString identifier; + + Addressee::List addrList; + const VCard::List vCardList = VCardParser::parseVCards(vcard); + + VCard::List::ConstIterator cardIt; + VCard::List::ConstIterator listEnd(vCardList.end()); + for (cardIt = vCardList.begin(); cardIt != listEnd; ++cardIt) { + Addressee addr; + + const QStringList idents = (*cardIt).identifiers(); + QStringList::ConstIterator identIt; + QStringList::ConstIterator identEnd(idents.end()); + for (identIt = idents.begin(); identIt != identEnd; ++identIt) { + const VCardLine::List lines = (*cardIt).lines((*identIt)); + VCardLine::List::ConstIterator lineIt; + + // iterate over the lines + for (lineIt = lines.begin(); lineIt != lines.end(); ++lineIt) { + identifier = (*lineIt).identifier().toLower(); + // ADR + if (identifier == QLatin1String("adr")) { + Address address; + const QStringList addrParts = splitString(semicolonSep, (*lineIt).value().toString()); + if (addrParts.count() > 0) { + address.setPostOfficeBox(addrParts.at(0)); + } + if (addrParts.count() > 1) { + address.setExtended(addrParts.at(1)); + } + if (addrParts.count() > 2) { + address.setStreet(addrParts.at(2)); + } + if (addrParts.count() > 3) { + address.setLocality(addrParts.at(3)); + } + if (addrParts.count() > 4) { + address.setRegion(addrParts.at(4)); + } + if (addrParts.count() > 5) { + address.setPostalCode(addrParts.at(5)); + } + if (addrParts.count() > 6) { + address.setCountry(addrParts.at(6)); + } + + Address::Type type; + + const QStringList types = (*lineIt).parameters(QStringLiteral("type")); + QStringList::ConstIterator end(types.end()); + for (QStringList::ConstIterator it = types.begin(); it != end; ++it) { + type |= mAddressTypeMap[(*it).toLower() ]; + } + + address.setType(type); + if (!(*lineIt).parameter(QStringLiteral("label")).isEmpty()) { + address.setLabel((*lineIt).parameter(QStringLiteral("label"))); + } + addr.insertAddress(address); + } + // ANNIVERSARY + else if (identifier == QLatin1String("anniversary")) { + const QString t = (*lineIt).value().toString(); + const QDateTime dt(parseDateTime(t)); + addr.insertCustom(QStringLiteral("KADDRESSBOOK"), QStringLiteral("X-Anniversary"), dt.date().toString(Qt::ISODate)); + } + // BDAY + else if (identifier == QLatin1String("bday")) { + addr.setBirthday(parseDateTime((*lineIt).value().toString())); + } + + // CATEGORIES + else if (identifier == QLatin1String("categories")) { + const QStringList categories = splitString(commaSep, (*lineIt).value().toString()); + addr.setCategories(categories); + } + // FBURL + else if (identifier == QLatin1String("fburl")) { + CalendarUrl calurl; + calurl.setType(CalendarUrl::FBUrl); + const QUrl url = QUrl((*lineIt).value().toString()); + calurl.setUrl(url); + calurl.setParameters((*lineIt).parameterMap()); + addr.insertCalendarUrl(calurl); + } + // CALADRURI + else if (identifier == QLatin1String("caladruri")) { + CalendarUrl calurl; + calurl.setType(CalendarUrl::CALADRUri); + const QUrl url = QUrl((*lineIt).value().toString()); + calurl.setUrl(url); + calurl.setParameters((*lineIt).parameterMap()); + addr.insertCalendarUrl(calurl); + } + // CALURI + else if (identifier == QLatin1String("caluri")) { + CalendarUrl calurl; + calurl.setType(CalendarUrl::CALUri); + const QUrl url = QUrl((*lineIt).value().toString()); + calurl.setUrl(url); + calurl.setParameters((*lineIt).parameterMap()); + addr.insertCalendarUrl(calurl); + } + //IMPP + else if (identifier == QLatin1String("impp")) { + QString imppStr = (*lineIt).value().toString(); + Impp impp; + impp.setAddress(imppStr); + impp.setParameters((*lineIt).parameterMap()); + if (!(*lineIt).parameter(QStringLiteral("x-service-type")).isEmpty()) { + const QString serviceType = (*lineIt).parameter(QStringLiteral("x-service-type")).toLower(); + if (serviceType == QLatin1String("facebook")) { + impp.setType(KContacts::Impp::Facebook); + } else if (serviceType == QLatin1String("jabber")) { + impp.setType(KContacts::Impp::Jabber); + } else if (serviceType == QLatin1String("sip")) { + impp.setType(KContacts::Impp::Sip); + } else if (serviceType == QLatin1String("aim")) { + impp.setType(KContacts::Impp::Aim); + } else if (serviceType == QLatin1String("msn")) { + impp.setType(KContacts::Impp::Msn); + } else if (serviceType == QLatin1String("twitter")) { + impp.setType(KContacts::Impp::Twitter); + } else if (serviceType == QLatin1String("googletalk")) { + impp.setType(KContacts::Impp::GoogleTalk); + } else if (serviceType == QLatin1String("xmpp")) { + impp.setType(KContacts::Impp::Xmpp); + } else if (serviceType == QLatin1String("icq")) { + impp.setType(KContacts::Impp::Icq); + } else if (serviceType == QLatin1String("yahoo")) { + impp.setType(KContacts::Impp::Yahoo); + } else if (serviceType == QLatin1String("qq")) { + impp.setType(KContacts::Impp::Qq); + } else if (serviceType == QLatin1String("gadugadu")) { + impp.setType(KContacts::Impp::GaduGadu); + } else if (serviceType == QLatin1String("owncloud-handle")) { + impp.setType(KContacts::Impp::Ownclound); + } else if (serviceType == QLatin1String("skype")) { + impp.setType(KContacts::Impp::Skype); + } else { + qDebug() << "unknown service type " << serviceType; + } + } + addr.insertImpp(impp); + } + // CLASS + else if (identifier == QLatin1String("class")) { + addr.setSecrecy(parseSecrecy(*lineIt)); + } + // GENDER + else if (identifier == QLatin1String("gender")) { + QString genderStr = (*lineIt).value().toString(); + if (!genderStr.isEmpty()) { + Gender gender; + if (genderStr.at(0) != QLatin1Char(';')) { + gender.setGender(genderStr.at(0)); + if (genderStr.length() > 2 && (genderStr.at(1) == QLatin1Char(';'))) { + gender.setComment(genderStr.right(genderStr.length() - 2)); + } + } else { + gender.setComment(genderStr.right(genderStr.length() - 1)); + } + addr.setGender(gender); + } + } + // LANG + else if (identifier == QLatin1String("lang")) { + Lang lang; + lang.setLanguage((*lineIt).value().toString()); + lang.setParameters((*lineIt).parameterMap()); + addr.insertLang(lang); + } + // EMAIL + else if (identifier == QLatin1String("email")) { + const QStringList types = (*lineIt).parameters(QStringLiteral("type")); + addr.insertEmail((*lineIt).value().toString(), + types.contains(QStringLiteral("PREF")), (*lineIt).parameterMap()); + } + // KIND + else if (identifier == QLatin1String("kind")) { + addr.setKind((*lineIt).value().toString()); + } + // FN + else if (identifier == QLatin1String("fn")) { + addr.setFormattedName((*lineIt).value().toString()); + } + + // GEO + else if (identifier == QLatin1String("geo")) { + Geo geo; + QString lineStr = (*lineIt).value().toString(); + if (lineStr.startsWith(QLatin1String("geo:"))) { //VCard 4.0 + lineStr.remove(QStringLiteral("geo:")); + const QStringList geoParts = + lineStr.split(QLatin1Char(','), QString::KeepEmptyParts); + if (geoParts.size() >= 2) { + geo.setLatitude(geoParts.at(0).toFloat()); + geo.setLongitude(geoParts.at(1).toFloat()); + addr.setGeo(geo); + } + } else { + const QStringList geoParts = + lineStr.split(QLatin1Char(';'), QString::KeepEmptyParts); + if (geoParts.size() >= 2) { + geo.setLatitude(geoParts.at(0).toFloat()); + geo.setLongitude(geoParts.at(1).toFloat()); + addr.setGeo(geo); + } + } + } + + // KEY + else if (identifier == QLatin1String("key")) { + addr.insertKey(parseKey(*lineIt)); + } + + // LABEL + else if (identifier == QLatin1String("label")) { + Address::Type type; + + const QStringList types = (*lineIt).parameters(QStringLiteral("type")); + QStringList::ConstIterator end(types.end()); + for (QStringList::ConstIterator it = types.begin(); it != end; ++it) { + type |= mAddressTypeMap[(*it).toLower() ]; + } + + bool available = false; + KContacts::Address::List addressList = addr.addresses(); + for (KContacts::Address::List::Iterator it = addressList.begin(); + it != addressList.end(); ++it) { + if ((*it).type() == type) { + (*it).setLabel((*lineIt).value().toString()); + addr.insertAddress(*it); + available = true; + break; + } + } + + if (!available) { // a standalone LABEL tag + KContacts::Address address(type); + address.setLabel((*lineIt).value().toString()); + addr.insertAddress(address); + } + } + + // LOGO + else if (identifier == QLatin1String("logo")) { + Picture picture = parsePicture(*lineIt); + if (addr.logo().isEmpty()) { + addr.setLogo(picture); + } else { + addr.insertExtraLogo(picture); + } + } + + // MAILER + else if (identifier == QLatin1String("mailer")) { + addr.setMailer((*lineIt).value().toString()); + } + + // N + else if (identifier == QLatin1String("n")) { + const QStringList nameParts = splitString(semicolonSep, (*lineIt).value().toString()); + const int numberOfParts(nameParts.count()); + if (numberOfParts > 0) { + addr.setFamilyName(nameParts.at(0)); + } + if (numberOfParts > 1) { + addr.setGivenName(nameParts.at(1)); + } + if (numberOfParts > 2) { + addr.setAdditionalName(nameParts.at(2)); + } + if (numberOfParts > 3) { + addr.setPrefix(nameParts.at(3)); + } + if (numberOfParts > 4) { + addr.setSuffix(nameParts.at(4)); + } + if (!(*lineIt).parameter(QStringLiteral("sort-as")).isEmpty()) { + addr.setSortString((*lineIt).parameter(QStringLiteral("sort-as"))); + } + } + + // NAME + else if (identifier == QLatin1String("name")) { + addr.setName((*lineIt).value().toString()); + } + + // NICKNAME + else if (identifier == QLatin1String("nickname")) { + addr.setNickName((*lineIt).value().toString()); + } + + // NOTE + else if (identifier == QLatin1String("note")) { + addr.setNote((*lineIt).value().toString()); + } + + // ORGANIZATION + else if (identifier == QLatin1String("org")) { + const QStringList orgParts = splitString(semicolonSep, (*lineIt).value().toString()); + if (orgParts.count() > 0) { + addr.setOrganization(orgParts.at(0)); + } + if (orgParts.count() > 1) { + addr.setDepartment(orgParts.at(1)); + } + if (!(*lineIt).parameter(QStringLiteral("sort-as")).isEmpty()) { + addr.setSortString((*lineIt).parameter(QStringLiteral("sort-as"))); + } + } + + // PHOTO + else if (identifier == QLatin1String("photo")) { + Picture picture = parsePicture(*lineIt); + if (addr.photo().isEmpty()) { + addr.setPhoto(picture); + } else { + addr.insertExtraPhoto(picture); + } + } + + // PROID + else if (identifier == QLatin1String("prodid")) { + addr.setProductId((*lineIt).value().toString()); + } + + // REV + else if (identifier == QLatin1String("rev")) { + addr.setRevision(parseDateTime((*lineIt).value().toString())); + } + + // ROLE + else if (identifier == QLatin1String("role")) { + addr.setRole((*lineIt).value().toString()); + } + + // SORT-STRING + else if (identifier == QLatin1String("sort-string")) { + addr.setSortString((*lineIt).value().toString()); + } + + // SOUND + else if (identifier == QLatin1String("sound")) { + Sound sound = parseSound(*lineIt); + if (addr.sound().isEmpty()) { + addr.setSound(sound); + } else { + addr.insertExtraSound(sound); + } + } + + // TEL + else if (identifier == QLatin1String("tel")) { + PhoneNumber phone; + phone.setNumber((*lineIt).value().toString()); + + PhoneNumber::Type type; + bool foundType = false; + const QStringList types = (*lineIt).parameters(QStringLiteral("type")); + QStringList::ConstIterator typeEnd(types.end()); + for (QStringList::ConstIterator it = types.begin(); it != typeEnd; ++it) { + type |= mPhoneTypeMap[(*it).toUpper()]; + foundType = true; + } + phone.setType(foundType ? type : PhoneNumber::Undefined); + + addr.insertPhoneNumber(phone); + } + + // TITLE + else if (identifier == QLatin1String("title")) { + addr.setTitle((*lineIt).value().toString()); + } + + // TZ + else if (identifier == QLatin1String("tz")) { + TimeZone tz; + const QString date = (*lineIt).value().toString(); + + if (!date.isEmpty()) { + int hours = date.midRef(1, 2).toInt(); + int minutes = date.midRef(4, 2).toInt(); + int offset = (hours * 60) + minutes; + offset = offset * (date[ 0 ] == QLatin1Char('+') ? 1 : -1); + + tz.setOffset(offset); + addr.setTimeZone(tz); + } + } + + // UID + else if (identifier == QLatin1String("uid")) { + addr.setUid((*lineIt).value().toString()); + } + + // URL + else if (identifier == QLatin1String("url")) { + const QUrl url = QUrl((*lineIt).value().toString()); + ResourceLocatorUrl resourceLocatorUrl; + resourceLocatorUrl.setUrl(url); + resourceLocatorUrl.setParameters((*lineIt).parameterMap()); + addr.insertExtraUrl(resourceLocatorUrl); + } + // SOURCE + else if (identifier == QLatin1String("source")) { + const QUrl url = QUrl((*lineIt).value().toString()); + addr.insertSourceUrl(url); + } + // MEMBER (vcard 4.0) + else if (identifier == QLatin1String("member")) { + addr.insertMember((*lineIt).value().toString()); + } + // RELATED (vcard 4.0) + else if (identifier == QLatin1String("related")) { + Related related; + related.setRelated((*lineIt).value().toString()); + related.setParameters((*lineIt).parameterMap()); + addr.insertRelationShip(related); + } + // X- + //TODO import X-GENDER + else if (identifier.startsWith(QLatin1String("x-"))) { + QString ident = (*lineIt).identifier(); + //X-Evolution + if (identifier == QLatin1String("x-evolution-spouse") || + identifier == QLatin1String("x-spouse")) { + ident = QStringLiteral("X-KADDRESSBOOK-X-SpousesName"); + } else if (identifier == QLatin1String("x-evolution-blog-url")) { + ident = QStringLiteral("X-KADDRESSBOOK-BlogFeed"); + } else if (identifier == QLatin1String("x-evolution-assistant") || + identifier == QLatin1String("x-assistant")) { + ident = QStringLiteral("X-KADDRESSBOOK-X-AssistantsName"); + } else if (identifier == QLatin1String("x-evolution-anniversary") || + identifier == QLatin1String("x-anniversary")) { + ident = QStringLiteral("X-KADDRESSBOOK-X-Anniversary"); + } else if (identifier == QLatin1String("x-evolution-manager") || + identifier == QLatin1String("x-manager")) { + ident = QStringLiteral("X-KADDRESSBOOK-X-ManagersName"); + } else if (identifier == QLatin1String("x-aim")) { + ident = QStringLiteral("X-messaging/aim-All"); + } else if (identifier == QLatin1String("x-icq")) { + ident = QStringLiteral("X-messaging/icq-All"); + } else if (identifier == QLatin1String("x-jabber")) { + ident = QStringLiteral("X-messaging/xmpp-All"); + } else if (identifier == QLatin1String("x-jabber")) { + ident = QStringLiteral("X-messaging/xmpp-All"); + } else if (identifier == QLatin1String("x-msn")) { + ident = QStringLiteral("X-messaging/msn-All"); + } else if (identifier == QLatin1String("x-yahoo")) { + ident = QStringLiteral("X-messaging/yahoo-All"); + } else if (identifier == QLatin1String("x-gadugadu")) { + ident = QStringLiteral("X-messaging/gadu-All"); + } else if (identifier == QLatin1String("x-skype")) { + ident = QStringLiteral("X-messaging/skype-All"); + } else if (identifier == QLatin1String("x-groupwise")) { + ident = QStringLiteral("X-messaging/groupwise-All"); + } else if (identifier == QLatin1String("x-sms")) { + ident = QStringLiteral("X-messaging/sms-All"); + } else if (identifier == QLatin1String("x-meanwhile")) { + ident = QStringLiteral("X-messaging/meanwhile-All"); + } else if (identifier == QLatin1String("x-irc")) { + ident = QStringLiteral("X-messaging/irc-All"); + } else if (identifier == QLatin1String("x-gtalk")) { + ident = QStringLiteral("X-messaging/googletalk-All"); + } else if (identifier == QLatin1String("x-twitter")) { + ident = QStringLiteral("X-messaging/twitter-All"); + } + + const QString key = ident.mid(2); + const int dash = key.indexOf(QLatin1Char('-')); + addr.insertCustom(key.left(dash), key.mid(dash + 1), + (*lineIt).value().toString()); + } + } + } + + addrList.append(addr); + } + + return addrList; +} + +QDateTime VCardTool::parseDateTime(const QString &str) const +{ + QDate date; + QTime time; + + if (str.indexOf(QLatin1Char('-')) == -1) { // is base format (yyyymmdd) + date = QDate(str.leftRef(4).toInt(), str.midRef(4, 2).toInt(), + str.midRef(6, 2).toInt()); + } else { // is extended format yyyy-mm-dd + date = QDate(str.leftRef(4).toInt(), str.midRef(5, 2).toInt(), + str.midRef(8, 2).toInt()); + } + + // does it also contain a time ? (Note: mm, ss are optional according ISO-8601) + int timeStart = str.indexOf(QLatin1Char('T')); + if (timeStart >= 0) { + int hour = 0, minute = 0, second = 0; + + hour = str.midRef(timeStart + 1, 2).toInt(); // hour must always be given + + if (str.indexOf(QLatin1Char(':'), timeStart + 1) > 0) { // extended format (hh:mm:ss) + if (str.length() >= (timeStart + 5)) { + minute = str.midRef(timeStart + 4, 2).toInt(); + if (str.length() >= (timeStart + 8)) { + second = str.midRef(timeStart + 7, 2).toInt(); + } + } + } else { // basic format (hhmmss) + if (str.length() >= (timeStart + 4)) { + minute = str.midRef(timeStart + 3, 2).toInt(); + if (str.length() >= (timeStart + 6)) { + second = str.midRef(timeStart + 5, 2).toInt(); + } + } + } + + time = QTime(hour, minute, second); + } + + Qt::TimeSpec spec = (str.right(1) == QLatin1String("Z")) ? Qt::UTC : Qt::LocalTime; + + QDateTime dateTime(date); + + if (time.isValid()) { + dateTime.setTime(time); + } + + dateTime.setTimeSpec(spec); + return dateTime; +} + +QString VCardTool::createDateTime(const QDateTime &dateTime, VCard::Version version) const +{ + QString str; + if (version == VCard::v4_0) { + if (dateTime.date().isValid()) { + str.sprintf("%4d%02d%02d", dateTime.date().year(), dateTime.date().month(), + dateTime.date().day()); + if (dateTime.time().isValid()) { + QString tmp; + tmp.sprintf("T%02d%02d%02d", dateTime.time().hour(), dateTime.time().minute(), + dateTime.time().second()); + str += tmp; + + if (dateTime.timeSpec() == Qt::UTC) { + str += QLatin1Char('Z'); + } + } + } + + } else { + if (dateTime.date().isValid()) { + str.sprintf("%4d-%02d-%02d", dateTime.date().year(), dateTime.date().month(), + dateTime.date().day()); + if (dateTime.time().isValid()) { + QString tmp; + tmp.sprintf("T%02d:%02d:%02d", dateTime.time().hour(), dateTime.time().minute(), + dateTime.time().second()); + str += tmp; + + if (dateTime.timeSpec() == Qt::UTC) { + str += QLatin1Char('Z'); + } + } + } + } + return str; +} + +Picture VCardTool::parsePicture(const VCardLine &line) const +{ + Picture pic; + + const QStringList params = line.parameterList(); + QString type; + if (params.contains(QStringLiteral("type"))) { + type = line.parameter(QStringLiteral("type")); + } + if (params.contains(QStringLiteral("encoding"))) { + pic.setRawData(line.value().toByteArray(), type); + } else if (params.contains(QStringLiteral("value"))) { + if (line.parameter(QStringLiteral("value")).toLower() == QLatin1String("uri")) { + pic.setUrl(line.value().toString()); + } + } + + return pic; +} + +VCardLine VCardTool::createPicture(const QString &identifier, const Picture &pic, VCard::Version version) const +{ + VCardLine line(identifier); + + if (pic.isEmpty()) { + return line; + } + + if (pic.isIntern()) { + line.setValue(pic.rawData()); + if (version == VCard::v2_1) { + line.addParameter(QStringLiteral("ENCODING"), QStringLiteral("BASE64")); + line.addParameter(pic.type(), QString()); + } else { + line.addParameter(QStringLiteral("encoding"), QStringLiteral("b")); + line.addParameter(QStringLiteral("type"), pic.type()); + } + } else { + line.setValue(pic.url()); + line.addParameter(QStringLiteral("value"), QStringLiteral("URI")); + } + + return line; +} + +Sound VCardTool::parseSound(const VCardLine &line) const +{ + Sound snd; + + const QStringList params = line.parameterList(); + if (params.contains(QStringLiteral("encoding"))) { + snd.setData(line.value().toByteArray()); + } else if (params.contains(QStringLiteral("value"))) { + if (line.parameter(QStringLiteral("value")).toLower() == QLatin1String("uri")) { + snd.setUrl(line.value().toString()); + } + } + + /* TODO: support sound types + if ( params.contains( "type" ) ) + snd.setType( line.parameter( "type" ) ); + */ + + return snd; +} + +VCardLine VCardTool::createSound(const Sound &snd, VCard::Version version) const +{ + Q_UNUSED(version); + VCardLine line(QStringLiteral("SOUND")); + + if (snd.isIntern()) { + if (!snd.data().isEmpty()) { + line.setValue(snd.data()); + if (version == VCard::v2_1) { + line.addParameter(QStringLiteral("ENCODING"), QStringLiteral("BASE64")); + } else { + line.addParameter(QStringLiteral("encoding"), QStringLiteral("b")); + } + // TODO: need to store sound type!!! + } + } else if (!snd.url().isEmpty()) { + line.setValue(snd.url()); + line.addParameter(QStringLiteral("value"), QStringLiteral("URI")); + } + + return line; +} + +Key VCardTool::parseKey(const VCardLine &line) const +{ + Key key; + + const QStringList params = line.parameterList(); + if (params.contains(QStringLiteral("encoding"))) { + key.setBinaryData(line.value().toByteArray()); + } else { + key.setTextData(line.value().toString()); + } + + if (params.contains(QStringLiteral("type"))) { + if (line.parameter(QStringLiteral("type")).toLower() == QLatin1String("x509")) { + key.setType(Key::X509); + } else if (line.parameter(QStringLiteral("type")).toLower() == QLatin1String("pgp")) { + key.setType(Key::PGP); + } else { + key.setType(Key::Custom); + key.setCustomTypeString(line.parameter(QStringLiteral("type"))); + } + } + + return key; +} + +VCardLine VCardTool::createKey(const Key &key, VCard::Version version) const +{ + VCardLine line(QStringLiteral("KEY")); + + if (key.isBinary()) { + if (!key.binaryData().isEmpty()) { + line.setValue(key.binaryData()); + if (version == VCard::v2_1) { + line.addParameter(QStringLiteral("ENCODING"), QStringLiteral("BASE64")); + } else { + line.addParameter(QStringLiteral("encoding"), QStringLiteral("b")); + } + } + } else if (!key.textData().isEmpty()) { + line.setValue(key.textData()); + } + + if (key.type() == Key::X509) { + line.addParameter(QStringLiteral("type"), QStringLiteral("X509")); + } else if (key.type() == Key::PGP) { + line.addParameter(QStringLiteral("type"), QStringLiteral("PGP")); + } else if (key.type() == Key::Custom) { + line.addParameter(QStringLiteral("type"), key.customTypeString()); + } + + return line; +} + +Secrecy VCardTool::parseSecrecy(const VCardLine &line) const +{ + Secrecy secrecy; + + const QString value = line.value().toString().toLower(); + if (value == QLatin1String("public")) { + secrecy.setType(Secrecy::Public); + } else if (value == QLatin1String("private")) { + secrecy.setType(Secrecy::Private); + } else if (value == QLatin1String("confidential")) { + secrecy.setType(Secrecy::Confidential); + } + + return secrecy; +} + +VCardLine VCardTool::createSecrecy(const Secrecy &secrecy) const +{ + VCardLine line(QStringLiteral("CLASS")); + + int type = secrecy.type(); + + if (type == Secrecy::Public) { + line.setValue(QLatin1String("PUBLIC")); + } else if (type == Secrecy::Private) { + line.setValue(QLatin1String("PRIVATE")); + } else if (type == Secrecy::Confidential) { + line.setValue(QLatin1String("CONFIDENTIAL")); + } + + return line; +} + +QStringList VCardTool::splitString(QChar sep, const QString &str) const +{ + QStringList list; + QString value(str); + + int start = 0; + int pos = value.indexOf(sep, start); + + while (pos != -1) { + if (pos == 0 || value[ pos - 1 ] != QLatin1Char('\\')) { + if (pos > start && pos <= (int)value.length()) { + list << value.mid(start, pos - start); + } else { + list << QString(); + } + + start = pos + 1; + pos = value.indexOf(sep, start); + } else { + value.replace(pos - 1, 2, sep); + pos = value.indexOf(sep, pos); + } + } + + int l = value.length() - 1; + const QString mid = value.mid(start, l - start + 1); + if (!mid.isEmpty()) { + list << mid; + } else { + list << QString(); + } + + return list; +} diff --git a/src/vcardtool.h b/src/vcardtool.h new file mode 100644 index 0000000..816b47c --- /dev/null +++ b/src/vcardtool.h @@ -0,0 +1,99 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2003 Tobias Koenig + + 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 KCONTACTS_VCARDTOOL_H +#define KCONTACTS_VCARDTOOL_H + +#include "kcontacts_export.h" +#include "addressee.h" +#include "vcardparser/vcardparser.h" + +class QDateTime; + +namespace KContacts +{ + +class Key; +class Picture; +class Secrecy; +class Sound; + +class KCONTACTS_EXPORT VCardTool +{ +public: + VCardTool(); + ~VCardTool(); + + /** + Creates a string that contains the addressees from the list in + the vCard format. + */ + QByteArray createVCards(const Addressee::List &list, + VCard::Version version = VCard::v3_0) const; + + /** + * @since 4.9.1 + */ + QByteArray exportVCards(const Addressee::List &list, + VCard::Version version = VCard::v3_0) const; + /** + Parses the string and returns a list of addressee objects. + */ + Addressee::List parseVCards(const QByteArray &vcard) const; + +private: + + QByteArray createVCards(const Addressee::List &list, + VCard::Version version, bool exportVcard) const; + + /** + Split a string and replaces escaped separators on the fly with + unescaped ones. + */ + QStringList splitString(QChar sep, const QString &value) const; + + QDateTime parseDateTime(const QString &str) const; + QString createDateTime(const QDateTime &dateTime, VCard::Version version) const; + + Picture parsePicture(const VCardLine &line) const; + VCardLine createPicture(const QString &identifier, const Picture &pic, VCard::Version version) const; + + Sound parseSound(const VCardLine &line) const; + VCardLine createSound(const Sound &snd, VCard::Version version) const; + + Key parseKey(const VCardLine &line) const; + VCardLine createKey(const Key &key, VCard::Version version) const; + + Secrecy parseSecrecy(const VCardLine &line) const; + VCardLine createSecrecy(const Secrecy &secrecy) const; + + void addParameter(VCardLine &line, VCard::Version version, const QString &key, const QStringList &valueStringList) const; + + QMap mAddressTypeMap; + QMap mPhoneTypeMap; + + Q_DISABLE_COPY(VCardTool) + class VCardToolPrivate; + VCardToolPrivate *d; +}; + +} + +#endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..f774782 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,24 @@ +# FIXME: Make it build with this flag +remove_definitions(-DQT_NO_CAST_FROM_BYTEARRAY) + +include(ECMMarkAsTest) + +########### next target ############### + +# FIXME: Build fails +set(testread_SRCS testread.cpp) +add_executable(testread ${testread_SRCS}) +target_link_libraries(testread KF5Contacts KF5::I18n Qt5::Gui) + +########### next target ############### + +# FIXME: Build fails +set(testwrite_SRCS testwrite.cpp) +add_executable(testwrite ${testwrite_SRCS}) +target_link_libraries(testwrite KF5Contacts Qt5::Gui KF5::I18n) + +########### next target ############### + +set(testread2_SRCS testread2.cpp testutils.cpp) +add_executable(testread2 ${testread2_SRCS}) +target_link_libraries(testread2 KF5Contacts Qt5::Gui) diff --git a/tests/README.testing b/tests/README.testing new file mode 100644 index 0000000..1a70685 --- /dev/null +++ b/tests/README.testing @@ -0,0 +1,12 @@ +For testing the vcardparser there are some test files and a small testsuite +automatically checking for regressions. The tests directory contains some vCard +files and correpsonding reference output files (with an additional ".ref" +suffix). For running the geression test do "./testroundtrip" or simply run "ctest". + +For creating a new test put a vCard file to be parsed into the tests directory. +Create a reference file by running "testread" on the test file. It will put out +the parsed data as vCard again on stdout. Carefully check the output, manually +correct any errors and save the result as reference file in the tests directory. +Now add the filename to the testroundtrip.qrc resource file and run +"make && ./roundtriptest" If the check fails adapt the reference file or fix the bugs +in the parser, whatever is appropriate. diff --git a/tests/checkvcard.pl b/tests/checkvcard.pl new file mode 100755 index 0000000..5965c89 --- /dev/null +++ b/tests/checkvcard.pl @@ -0,0 +1,79 @@ +#!/usr/bin/perl + +if ( @ARGV != 1 ) { + print STDERR "Missing arg: filename\n"; + system "touch FAILED"; + exit 1; +} + +$file = $ARGV[0]; + +if ( !open( IN, "$file" ) ) { + print STDERR "Unable to open '$file'\n"; + system "touch FAILED"; + exit 1; +} + +while( ) { + if (/^VERSION:(.*)$/ ) { + $version = $1; + if ( $version eq "2.1" ) { $options = "--vcard21"; } + } +} + +close IN; + +$ref = "$file.ref"; + +if ( !open( REF, "$ref" ) ) { + print STDERR "Unable to open $ref\n"; + system "touch FAILED"; + exit 1; +} + +while( ) { + push @ref, $_; +} + +close REF; + +if ( !open( READ, "./testread $file $options 2> /dev/null |" ) ) { + print STDERR "Unable to open testread\n"; + system "touch FAILED"; + exit 1; +} + +print "Checking '$file':\n"; + +$gotsomething = 0; +$error = 0; +$i = 0; +while( ) { + $gotsomething = 1; + $out = $_; + $ref = @ref[$i++]; + + if ( $out ne $ref ) { + if ( $ref =~ /^UID/ && $out =~ /^UID/ ) { next; } + $error++; + print " Expected : $ref"; + print " Parser output : $out"; + } +} + +close READ; + +if ( $gotsomething == 0 ) { + print "\n FAILED: testread didn't output anything\n"; + system "touch FAILED"; + exit 1; +} +if ( $error > 0 ) { + print "\n FAILED: $error errors found.\n"; + system "touch FAILED"; + exit 1; +} else { + print " OK\n"; +} + +exit 0; diff --git a/tests/testread.cpp b/tests/testread.cpp new file mode 100644 index 0000000..3856282 --- /dev/null +++ b/tests/testread.cpp @@ -0,0 +1,81 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2007 KDE-PIM team + + 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 +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "converter/kcontacts/vcardconverter.h" +#include "vcard.h" + +int main(int argc, char **argv) +{ + KAboutData aboutData(QStringLiteral("testread"), i18n("vCard test reader"), QStringLiteral("0.1")); + aboutData.addAuthor(i18n("Cornelius Schumacher"), QString(), QStringLiteral("schumacher@kde.org")); + + QCoreApplication app(argc, argv); + QCommandLineParser parser; + parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("vcard21"), i18n("vCard 2.1"))); + parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("+inputfile"), i18n("Input file"))); + + KAboutData::setApplicationData(aboutData); + parser.addVersionOption(); + parser.addHelpOption(); + aboutData.setupCommandLine(&parser); + parser.process(app); + aboutData.processCommandLine(&parser); + + if (parser.positionalArguments().count() != 1) { + std::cerr << "Missing argument" << std::endl; + return 1; + } + + QString inputFile(parser.positionalArguments().at(0)); + + QFile file(inputFile); + if (!file.open(QIODevice::ReadOnly)) { + qDebug("Unable to open file '%s' for reading!", qPrintable(file.fileName())); + return 1; + } + + QByteArray text = file.readAll(); + file.close(); + + KContacts::VCardConverter converter; + KContacts::Addressee::List list = converter.parseVCards(text); + + if (parser.isSet(QStringLiteral("vcard21"))) { + text = converter.createVCards(list, KContacts::VCardConverter::v2_1); // uses version 2.1 + } else { + text = converter.createVCards(list); // uses version 3.0 + } + + std::cout << text.data(); + + return 0; +} diff --git a/tests/testread2.cpp b/tests/testread2.cpp new file mode 100644 index 0000000..37c2f75 --- /dev/null +++ b/tests/testread2.cpp @@ -0,0 +1,61 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2007 KDE-PIM team + + 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 "testutils.h" +#include +#include +#include + +using namespace KContacts; + +int main() +{ + Addressee::List l = vCardsAsAddresseeList(); + QByteArray vcards = vCardsAsText(); + + VCardConverter vct; + + Addressee::List parsed = vct.parseVCards(vcards); + + if (l.size() != parsed.size()) { + qDebug() << "\tSize - FAILED :" << l.size() << "vs. parsed" << parsed.size(); + } else { + qDebug() << "\tSize - PASSED"; + } + + Addressee::List::iterator itr1; + Addressee::List::iterator itr2; + for (itr1 = l.begin(), itr2 = parsed.begin(); + itr1 != l.end() && itr2 != parsed.end(); ++itr1, ++itr2) { + if ((*itr1).fullEmail() == (*itr2).fullEmail() && + (*itr1).organization() == (*itr2).organization() && + (*itr1).phoneNumbers() == (*itr2).phoneNumbers() && + (*itr1).emails() == (*itr2).emails() && + (*itr1).role() == (*itr2).role()) { + qDebug() << "\tAddressee - PASSED"; + qDebug() << "\t\t" << (*itr1).fullEmail() << "VS." << (*itr2).fullEmail(); + } else { + qDebug() << "\tAddressee - FAILED"; + qDebug() << (*itr1).toString(); + qDebug() << (*itr2).toString(); + //qDebug()<<"\t\t"<< (*itr1).fullEmail() << "VS." << (*itr2).fullEmail(); + } + } +} diff --git a/tests/testutils.cpp b/tests/testutils.cpp new file mode 100644 index 0000000..0acb44c --- /dev/null +++ b/tests/testutils.cpp @@ -0,0 +1,117 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2007 KDE-PIM team + + 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 + +#include + +#include "vcardparser.h" + +using namespace KContacts; + +Addressee vcard1() +{ + Addressee addr; + + addr.setName(QStringLiteral("Frank Dawson")); + addr.setOrganization(QStringLiteral("Lotus Development Corporation")); + KContacts::ResourceLocatorUrl url; + url.setUrl(QUrl(QStringLiteral("http://home.earthlink.net/~fdawson"))); + addr.setUrl(url); + addr.insertEmail(QStringLiteral("fdawson@earthlink.net")); + addr.insertEmail(QStringLiteral("Frank_Dawson@Lotus.com"), true); + addr.insertPhoneNumber(PhoneNumber(QStringLiteral("+1-919-676-9515"), + PhoneNumber::Voice | PhoneNumber::Msg | PhoneNumber::Work)); + addr.insertPhoneNumber(PhoneNumber(QStringLiteral("+1-919-676-9564"), + PhoneNumber::Fax | PhoneNumber::Work)); + Address a(Address::Work | Address::Postal | Address::Parcel); + a.setStreet(QStringLiteral("6544 Battleford Drive")); + a.setLocality(QStringLiteral("Raleigh")); + a.setRegion(QStringLiteral("NC")); + a.setPostalCode(QStringLiteral("27613-3502")); + a.setCountry(QStringLiteral("U.S.A.")); + addr.insertAddress(a); + return addr; +} + +Addressee vcard2() +{ + Addressee addr; + + addr.setName(QStringLiteral("Tim Howes")); + addr.setOrganization(QStringLiteral("Netscape Communications Corp.")); + addr.insertEmail(QStringLiteral("howes@netscape.com")); + addr.insertPhoneNumber(PhoneNumber(QStringLiteral("+1-415-937-3419"), + PhoneNumber::Voice | PhoneNumber::Msg | PhoneNumber::Work)); + addr.insertPhoneNumber(PhoneNumber(QStringLiteral("+1-415-528-4164"), + PhoneNumber::Fax | PhoneNumber::Work)); + Address a(Address::Work); + a.setStreet(QStringLiteral("501 E. Middlefield Rd.")); + a.setLocality(QStringLiteral("Mountain View")); + a.setRegion(QStringLiteral("CA")); + a.setPostalCode(QStringLiteral("94043")); + a.setCountry(QStringLiteral("U.S.A.")); + addr.insertAddress(a); + return addr; +} + +Addressee vcard3() +{ + Addressee addr; + + addr.setName(QStringLiteral("ian geiser")); + addr.setOrganization(QStringLiteral("Source eXtreme")); + addr.insertEmail(QStringLiteral("geiseri@yahoo.com")); + addr.setTitle(QStringLiteral("VP of Engineering")); + return addr; +} + +QByteArray vcardAsText(const QString &location) +{ + QByteArray text; + + QFile file(location); + if (file.open(QIODevice::ReadOnly)) { + text = file.readAll(); + file.close(); + } + + return text; +} + +Addressee::List vCardsAsAddresseeList() +{ + Addressee::List l; + + l.append(vcard1()); + l.append(vcard2()); + l.append(vcard3()); + + return l; +} + +QByteArray vCardsAsText() +{ + QByteArray vcards = vcardAsText(QStringLiteral("tests/vcard1.vcf")); + vcards += vcardAsText(QStringLiteral("tests/vcard2.vcf")); + vcards += vcardAsText(QStringLiteral("tests/vcard3.vcf")); + + return vcards; +} diff --git a/tests/testutils.h b/tests/testutils.h new file mode 100644 index 0000000..d299563 --- /dev/null +++ b/tests/testutils.h @@ -0,0 +1,36 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2007 KDE-PIM team + + 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 TESTUTILS_H +#define TESTUTILS_H + +#include +#include + +#include + +KContacts::Addressee vcard1(); +KContacts::Addressee vcard2(); +KContacts::Addressee vcard3(); +KContacts::Addressee::List vCardsAsAddresseeList(); +QByteArray vCardAsText(const QString &location); +QByteArray vCardsAsText(); + +#endif diff --git a/tests/testwrite.cpp b/tests/testwrite.cpp new file mode 100644 index 0000000..4983682 --- /dev/null +++ b/tests/testwrite.cpp @@ -0,0 +1,129 @@ +/* + This file is part of the KContacts framework. + Copyright (c) 2007 KDE-PIM team + + 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 + +#include +#include + +#include +#include +#include + +#include "kcontacts/addressee.h" +#include "kcontacts/phonenumber.h" +#include "kcontacts/address.h" +#include "kcontacts/key.h" +#include "kcontacts/picture.h" +#include "kcontacts/sound.h" +#include "kcontacts/secrecy.h" +#include "converter/kcontacts/vcardconverter.h" + +int main(int argc, char **argv) +{ + KAboutData aboutData(QLatin1String("testwrite"), i18n("vCard test writer"), QLatin1String("0.1")); + + QCoreApplication app(argc, argv); + QCommandLineParser parser; + KAboutData::setApplicationData(aboutData); + parser.addVersionOption(); + parser.addHelpOption(); + aboutData.setupCommandLine(&parser); + parser.process(app); + aboutData.processCommandLine(&parser); + + KContacts::Addressee addressee; + + addressee.setNameFromString(QLatin1String("Mr. Tobias Koenig Jr.")); + addressee.setNickName(QLatin1String("tokoe")); + addressee.setBirthday(QDateTime(QDate(1982, 7, 19))); + addressee.setMailer(QLatin1String("mutt1.2")); + addressee.setTimeZone(KContacts::TimeZone(+2)); + + KContacts::Geo geo; + geo.setLatitude(30); + geo.setLongitude(51); + addressee.setGeo(geo); + + addressee.setTitle(QLatin1String("nerd")); + addressee.setRole(QLatin1String("Maintainer")); + addressee.setOrganization(QLatin1String("KDE")); + addressee.setNote(QLatin1String("nerver\ntouch a running system")); + addressee.setProductId(QLatin1String("testId")); + addressee.setRevision(QDateTime::currentDateTime()); + addressee.setSortString(QLatin1String("koenig")); + KContacts::ResourceLocatorUrl url; + url.setUrl(QUrl(QLatin1String("http://wgess16.dyndns.org"))); + addressee.setUrl(url); + addressee.setSecrecy(KContacts::Secrecy(KContacts::Secrecy::Confidential)); + + addressee.insertEmail(QLatin1String("tokoe@kde.org"), true); + addressee.insertEmail(QLatin1String("tokoe82@yahoo.de"), true); + + KContacts::PhoneNumber phone1(QLatin1String("3541523475"), + KContacts::PhoneNumber::Pref | KContacts::PhoneNumber::Home); + KContacts::PhoneNumber phone2(QLatin1String("+46745673475"), + KContacts::PhoneNumber::Work); + addressee.insertPhoneNumber(phone1); + addressee.insertPhoneNumber(phone2); + + KContacts::Key key(QLatin1String("secret key"), KContacts::Key::X509); + addressee.insertKey(key); + + QStringList categories; + categories << QLatin1String("Friends") << QLatin1String("School") << QLatin1String("KDE"); + addressee.setCategories(categories); + + KContacts::Address a(KContacts::Address::Work | KContacts::Address::Postal | KContacts::Address::Parcel); + a.setStreet(QLatin1String("6544 Battleford Drive")); + a.setLocality(QLatin1String("Raleigh")); + a.setRegion(QLatin1String("NC")); + a.setPostalCode(QLatin1String("27613-3502")); + a.setCountry(QLatin1String("U.S.A.")); + addressee.insertAddress(a); + + addressee.insertCustom(QLatin1String("1hsdf"), QLatin1String("ertuer"), + QLatin1String("iurt")); + addressee.insertCustom(QLatin1String("2hsdf"), QLatin1String("ertuer"), + QLatin1String("iurt")); + addressee.insertCustom(QLatin1String("3hsdf"), QLatin1String("ertuer"), + QLatin1String("iurt")); + + KContacts::Addressee::List list; + for (int i = 0; i < 1000; ++i) { + KContacts::Addressee addr = addressee; + addr.setUid(QString::number(i)); + list.append(addr); + } + + KContacts::VCardConverter converter; + QByteArray txt = converter.createVCards(list); + + QFile file(QLatin1String("out.vcf")); + if (!file.open(QIODevice::WriteOnly)) { + qDebug("Can't open file '%s' fro writing", qPrintable(file.fileName())); + return 1; + } + + file.write(txt); + file.close(); + + return 0; +} -- 2.30.2