From: Maximiliano Curia Date: Sat, 18 Jun 2016 07:32:47 +0000 (+0100) Subject: Import kcontacts_16.04.2.orig.tar.xz X-Git-Tag: archive/raspbian/5%5.97.0-1+rpi1~1^2^2^2^2~1 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=71228bac1999b0e0fc781d58e176c37a30d76ded;p=kcontacts.git Import kcontacts_16.04.2.orig.tar.xz [dgit import orig kcontacts_16.04.2.orig.tar.xz] --- 71228bac1999b0e0fc781d58e176c37a30d76ded 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 0000000..6560135 Binary files /dev/null and b/autotests/data/vcard12.vcf.2_1ref differ diff --git a/autotests/data/vcard12.vcf.ref b/autotests/data/vcard12.vcf.ref new file mode 100644 index 0000000..980372e --- /dev/null +++ b/autotests/data/vcard12.vcf.ref @@ -0,0 +1,16 @@ +BEGIN:VCARD +VERSION:3.0 +EMAIL;TYPE=WORK;X-EVOLUTION-UI-SLOT=1:goodlooking@example.com +FN:Good Looking +N:Looking;Good;;; +PHOTO;ENCODING=b;TYPE=WORK:iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAA + CXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wELCiUrjAUGmgAAABl0RVh0Q29tbWVudABDcmV + hdGVkIHdpdGggR0lNUFeBDhcAAAAZSURBVAjXY/zPAAVMDAwMDP//MzAwMMLFAEMrBAHo3Yr/AA + AAAElFTkSuQmCC +PHOTO;ENCODING=b;TYPE=HOME:iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAA + CXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wELCiQG0MFrrgAAABl0RVh0Q29tbWVudABDcmV + hdGVkIHdpdGggR0lNUFeBDhcAAAAUSURBVAjXY/j//z8DAwOEhAG4GACzagv1unIx3wAAAABJRU + 5ErkJggg== +UID:pas-id-54B2522600000001 +END:VCARD + diff --git a/autotests/data/vcard13.vcf b/autotests/data/vcard13.vcf new file mode 100644 index 0000000..5e31757 --- /dev/null +++ b/autotests/data/vcard13.vcf @@ -0,0 +1,12 @@ +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 +URL:test1.url +URL:test2.url +VERSION:3.0 +END:VCARD + diff --git a/autotests/data/vcard13.vcf.ref b/autotests/data/vcard13.vcf.ref new file mode 100644 index 0000000..ce0cba0 --- /dev/null +++ b/autotests/data/vcard13.vcf.ref @@ -0,0 +1,12 @@ +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 +URL:test1.url +URL:test2.url +END:VCARD + diff --git a/autotests/data/vcard14.vcf b/autotests/data/vcard14.vcf new file mode 100644 index 0000000..8fe5db3 --- /dev/null +++ b/autotests/data/vcard14.vcf @@ -0,0 +1,12 @@ +BEGIN:VCARD +VERSION:3.0 +CLASS:PUBLIC +EMAIL;TYPE=HOME,PREF;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 +SOURCE:http://www.kde.org +SOURCE:http://www.kde1.org +END:VCARD + diff --git a/autotests/data/vcard14.vcf.2_1ref b/autotests/data/vcard14.vcf.2_1ref new file mode 100644 index 0000000..367e523 --- /dev/null +++ b/autotests/data/vcard14.vcf.2_1ref @@ -0,0 +1,11 @@ +BEGIN:VCARD +VERSION:2.1 +EMAIL;HOME;PREF;X-EVOLUTION-UI-SLOT=2:thejoe@abc.com +EMAIL;WORK;X-EVOLUTION-UI-SLOT=1:johndoe@abc.com +FN:Test User +N:User;Test;;; +SOURCE:http://www.kde.org +SOURCE:http://www.kde1.org +UID:uJTkVqH5Qt +END:VCARD + diff --git a/autotests/data/vcard14.vcf.ref b/autotests/data/vcard14.vcf.ref new file mode 100644 index 0000000..2488a73 --- /dev/null +++ b/autotests/data/vcard14.vcf.ref @@ -0,0 +1,12 @@ +BEGIN:VCARD +VERSION:3.0 +CLASS:PUBLIC +EMAIL;TYPE=HOME,PREF;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;;; +SOURCE:http://www.kde.org +SOURCE:http://www.kde1.org +UID:uJTkVqH5Qt +END:VCARD + diff --git a/autotests/data/vcard2.vcf b/autotests/data/vcard2.vcf new file mode 100644 index 0000000..13cd72e --- /dev/null +++ b/autotests/data/vcard2.vcf @@ -0,0 +1,12 @@ +BEGIN:vCard +VERSION:3.0 +UID:1UgvYejJMs +FN:Tim Howes +ORG:Netscape Communications Corp. +ADR;TYPE=WORK:;;501 E. Middlefield Rd.;Mountain View; + CA; 94043;U.S.A. +TEL;TYPE=VOICE,MSG,WORK:+1-415-937-3419 +TEL;TYPE=FAX,WORK:+1-415-528-4164 +EMAIL;TYPE=INTERNET:howes@netscape.com +END:vCard + diff --git a/autotests/data/vcard2.vcf.2_1ref b/autotests/data/vcard2.vcf.2_1ref new file mode 100644 index 0000000..0af201c --- /dev/null +++ b/autotests/data/vcard2.vcf.2_1ref @@ -0,0 +1,12 @@ +BEGIN:VCARD +VERSION:2.1 +ADR;WORK:;;501 E. Middlefield Rd.;Mountain View;CA; 94043;U.S.A. +EMAIL;INTERNET:howes@netscape.com +FN:Tim Howes +N:;;;; +ORG:Netscape Communications Corp. +TEL;MSG;VOICE;WORK:+1-415-937-3419 +TEL;FAX;WORK:+1-415-528-4164 +UID:1UgvYejJMs +END:VCARD + diff --git a/autotests/data/vcard2.vcf.ref b/autotests/data/vcard2.vcf.ref new file mode 100644 index 0000000..0cf6003 --- /dev/null +++ b/autotests/data/vcard2.vcf.ref @@ -0,0 +1,12 @@ +BEGIN:VCARD +VERSION:3.0 +ADR;TYPE=work:;;501 E. Middlefield Rd.;Mountain View;CA; 94043;U.S.A. +EMAIL;TYPE=INTERNET:howes@netscape.com +FN:Tim Howes +N:;;;; +ORG:Netscape Communications Corp. +TEL;TYPE=MSG,VOICE,WORK:+1-415-937-3419 +TEL;TYPE=FAX,WORK:+1-415-528-4164 +UID:1UgvYejJMs +END:VCARD + diff --git a/autotests/data/vcard3.vcf b/autotests/data/vcard3.vcf new file mode 100644 index 0000000..579e2da --- /dev/null +++ b/autotests/data/vcard3.vcf @@ -0,0 +1,12 @@ +begin:vcard +uid:ebvq9Wo9rO +n:geiser;ian +x-mozilla-html:FALSE +org:Source eXtreme +version:2.1 +email;internet:geiseri@yahoo.com +title:VP of Engineering +x-mozilla-cpt:;0 +fn:ian geiser +end:vcard + diff --git a/autotests/data/vcard3.vcf.2_1ref b/autotests/data/vcard3.vcf.2_1ref new file mode 100644 index 0000000..0a81e62 --- /dev/null +++ b/autotests/data/vcard3.vcf.2_1ref @@ -0,0 +1,12 @@ +BEGIN:VCARD +VERSION:2.1 +EMAIL;INTERNET: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/vcard3.vcf.ref b/autotests/data/vcard3.vcf.ref new file mode 100644 index 0000000..0eeeec2 --- /dev/null +++ b/autotests/data/vcard3.vcf.ref @@ -0,0 +1,12 @@ +BEGIN:VCARD +VERSION:3.0 +EMAIL;TYPE=internet: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/vcard4.vcf b/autotests/data/vcard4.vcf new file mode 100644 index 0000000..7152ceb --- /dev/null +++ b/autotests/data/vcard4.vcf @@ -0,0 +1,14 @@ +BEGIN:VCARD +X-EVOLUTION-FILE-AS:Ximian, Inc. +FN +N: +LABEL;QUOTED-PRINTABLE;WORK:401 Park Drive 3 West=0ABoston, MA 02215=0AUSA +TEL;WORK;VOICE:(617) 236-0442 +TEL;WORK;FAX:(617) 236-8630 +EMAIL;INTERNET:hello@ximian.com +URL:www.ximian.com/ +ORG:Ximian, Inc. +NOTE:Welcome to the Ximian Addressbook. +UID:pas-id-3E136F9B00000000 +END:VCARD + diff --git a/autotests/data/vcard4.vcf.ref b/autotests/data/vcard4.vcf.ref new file mode 100644 index 0000000..28e0b58 --- /dev/null +++ b/autotests/data/vcard4.vcf.ref @@ -0,0 +1,14 @@ +BEGIN:VCARD +VERSION:3.0 +EMAIL;TYPE=INTERNET:hello@ximian.com +LABEL;TYPE=work:401 Park Drive 3 West\nBoston\, MA 02215\nUSA +N:;;;; +NOTE:Welcome to the Ximian Addressbook. +ORG:Ximian\, Inc. +TEL;TYPE=VOICE,WORK:(617) 236-0442 +TEL;TYPE=FAX,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/vcard5.vcf b/autotests/data/vcard5.vcf new file mode 100644 index 0000000..957a1e5 --- /dev/null +++ b/autotests/data/vcard5.vcf @@ -0,0 +1,313 @@ +BEGIN:VCARD +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/ +VERSION:3.0 +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/vcard5.vcf.ref b/autotests/data/vcard5.vcf.ref new file mode 100644 index 0000000..531271f --- /dev/null +++ b/autotests/data/vcard5.vcf.ref @@ -0,0 +1,312 @@ +BEGIN:VCARD +VERSION:3.0 +ADR;TYPE=home,pref:;;Buehlauer Strasse 45;Dresden;Sachsen;01327;Germany +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/vcard6.vcf b/autotests/data/vcard6.vcf new file mode 100644 index 0000000..92339c7 --- /dev/null +++ b/autotests/data/vcard6.vcf @@ -0,0 +1,10 @@ +BEGIN:VCARD +CLASS:PUBLIC +EMAIL;TYPE=PREF:email1@abc.de +EMAIL:email2@abc.de +FN:Test User +N:User;Test;;; +UID:uJTkVqH5Qt +VERSION:3.0 +END:VCARD + diff --git a/autotests/data/vcard6.vcf.2_1ref b/autotests/data/vcard6.vcf.2_1ref new file mode 100644 index 0000000..d5a5a9b --- /dev/null +++ b/autotests/data/vcard6.vcf.2_1ref @@ -0,0 +1,9 @@ +BEGIN:VCARD +VERSION:2.1 +EMAIL;PREF:email1@abc.de +EMAIL:email2@abc.de +FN:Test User +N:User;Test;;; +UID:uJTkVqH5Qt +END:VCARD + diff --git a/autotests/data/vcard6.vcf.ref b/autotests/data/vcard6.vcf.ref new file mode 100644 index 0000000..712afe7 --- /dev/null +++ b/autotests/data/vcard6.vcf.ref @@ -0,0 +1,10 @@ +BEGIN:VCARD +VERSION:3.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/vcard7.vcf b/autotests/data/vcard7.vcf new file mode 100644 index 0000000..8b5be8e --- /dev/null +++ b/autotests/data/vcard7.vcf @@ -0,0 +1,7 @@ +BEGIN:VCARD +N: +LABEL;QUOTED-PRINTABLE;WORK:401 Park Drive 3 West=0ABoston, MA 02215=0AUSA=0A= +Herecomesyetanotherline +UID:pas-id-3E136F9B00000000 +END:VCARD + diff --git a/autotests/data/vcard7.vcf.2_1ref b/autotests/data/vcard7.vcf.2_1ref new file mode 100644 index 0000000..5d4e702 --- /dev/null +++ b/autotests/data/vcard7.vcf.2_1ref @@ -0,0 +1,8 @@ +BEGIN:VCARD +VERSION:2.1 +LABEL;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE;WORK:401 Park Drive 3 West\n + Boston\, MA 02215\nUSA\nHerecomesyetanotherline +N:;;;; +UID:pas-id-3E136F9B00000000 +END:VCARD + diff --git a/autotests/data/vcard7.vcf.ref b/autotests/data/vcard7.vcf.ref new file mode 100644 index 0000000..b099b98 --- /dev/null +++ b/autotests/data/vcard7.vcf.ref @@ -0,0 +1,8 @@ +BEGIN:VCARD +VERSION:3.0 +LABEL;TYPE=work:401 Park Drive 3 West\nBoston\, MA 02215\nUSA\nHerecomesye + tanotherline +N:;;;; +UID:pas-id-3E136F9B00000000 +END:VCARD + diff --git a/autotests/data/vcard8.vcf b/autotests/data/vcard8.vcf new file mode 100644 index 0000000..eff34b8 --- /dev/null +++ b/autotests/data/vcard8.vcf @@ -0,0 +1,8 @@ +BEGIN:VCARD +FN:test +N:test;;;; +NOTE:line one\Nline two\Nline three\N +UID:8OD165Pope +VERSION:3.0 +END:VCARD + diff --git a/autotests/data/vcard8.vcf.ref b/autotests/data/vcard8.vcf.ref new file mode 100644 index 0000000..54f7dbc --- /dev/null +++ b/autotests/data/vcard8.vcf.ref @@ -0,0 +1,8 @@ +BEGIN:VCARD +VERSION:3.0 +FN:test +N:test;;;; +NOTE:line one\nline two\nline three\n +UID:8OD165Pope +END:VCARD + diff --git a/autotests/data/vcard9.vcf b/autotests/data/vcard9.vcf new file mode 100644 index 0000000..c38153b --- /dev/null +++ b/autotests/data/vcard9.vcf @@ -0,0 +1,14 @@ +BEGIN:VCARD +FN:βγδεαβγδ1βγδεαβγδ1βγδεαβγδ1βγδεαβγδ1βγ + δεαβγδ1βγδεαβγδ1βγδεαβγδ1βγδεαβγδ1βγδεα + βγδ1βγδεαβγδ1βγδεαβγδ1 +N:123ㄓㄕㄖbcdeαβγδαβγδαβγδαβγδαβγδαβγδαβㄤ + ㄓㄕㄖ;;;; +NOTE:Длинный комментарий на русском языке\, + чтобы в результате получилась строка боР+ »ÐµÐµ 70 символов. +PRODID:-//ownCloud//NONSGML Contacts 0.3//EN +UID:20140316T155019.877e370c11@martin +VERSION:3.0 +END:VCARD + diff --git a/autotests/data/vcard9.vcf.ref b/autotests/data/vcard9.vcf.ref new file mode 100644 index 0000000..cbb9ed8 --- /dev/null +++ b/autotests/data/vcard9.vcf.ref @@ -0,0 +1,14 @@ +BEGIN:VCARD +VERSION:3.0 +FN:βγδεαβγδ1βγδεαβγδ1βγδεαβγδ1βγδεαβγδ1βγ + δεαβγδ1βγδεαβγδ1βγδεαβγδ1βγδεαβγδ1βγδεα + βγδ1βγδεαβγδ1βγδεαβγδ1 +N:123ㄓㄕㄖbcdeαβγδαβγδαβγδαβγδαβγδαβγδαβㄤ + ㄓㄕㄖ;;;; +NOTE:Длинный комментарий на русском языке\, + чтобы в результате получилась строка бо + лее 70 символов. +PRODID:-//ownCloud//NONSGML Contacts 0.3//EN +UID:20140316T155019.877e370c11@martin +END:VCARD + diff --git a/autotests/emailtest.cpp b/autotests/emailtest.cpp new file mode 100644 index 0000000..f8e5374 --- /dev/null +++ b/autotests/emailtest.cpp @@ -0,0 +1,187 @@ +/* + 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 "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; +}