pax_global_header00006660000000000000000000000064126253161660014522gustar00rootroot0000000000000052 comment=b41907eec821e2f9b9ec63d003f2d1f9747374a2 libkolab-1.0.2/000077500000000000000000000000001262531616600133015ustar00rootroot00000000000000libkolab-1.0.2/.gitignore000066400000000000000000000000231262531616600152640ustar00rootroot00000000000000build/* *.kdev4 *~ libkolab-1.0.2/CMakeLists.txt000066400000000000000000000163611262531616600160500ustar00rootroot00000000000000project(Libkolab) cmake_minimum_required(VERSION 2.8.9) option(BUILD_TESTS "Build the tests" TRUE) option(PYTHON_BINDINGS "Build bindings for python" FALSE) option(PHP_BINDINGS "Build bindings for php" FALSE) set(Libkolab_MODULE_DIR ${Libkolab_SOURCE_DIR}/cmake/modules) set(CMAKE_MODULE_PATH ${Libkolab_MODULE_DIR}) # only available from cmake-2.8.0 if(${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} GREATER 7) cmake_policy(SET CMP0012 NEW) endif() # only available from cmake-2.8.4 if(${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} GREATER 7 AND ${CMAKE_PATCH_VERSION} GREATER 3) cmake_policy(SET CMP0017 NEW) endif() # Versioning # x.y.z scheme # Development versions are only x.y # # i.e. # 0.1 (0.1 development version towards 0.1.0) # 0.1.0 (first release) # 0.1.1 (patch release for 0.1.0) # 0.2 (0.2 development version towards 0.2.0) set(Libkolab_VERSION_MAJOR 1) set(Libkolab_VERSION_MINOR 0) # Enable the full x.y.z version only for release versions set(Libkolab_VERSION_PATCH 2) #set(Libkolab_VERSION ${Libkolab_VERSION_MAJOR}.${Libkolab_VERSION_MINOR}.${Libkolab_VERSION_PATCH}) set(Libkolab_VERSION ${Libkolab_VERSION_MAJOR}.${Libkolab_VERSION_MINOR}) set(Libkolab_VERSION_STRING ${CMAKE_PROJECT_NAME}-${Libkolab_VERSION}) # set up install directories. set(LIB_INSTALL_DIR lib${LIB_SUFFIX} CACHE STRING "The directories where to install libraries to") set(INCLUDE_INSTALL_DIR include CACHE STRING "The directory where to install headers to") set(INCLUDE_INSTALL_DIR ${INCLUDE_INSTALL_DIR}/kolab) set(CMAKECONFIG_INSTALL_DIR ${LIB_INSTALL_DIR}/cmake/Libkolab) # Make relative paths absolute (needed later on) foreach(p LIB INCLUDE CMAKECONFIG) set(var ${p}_INSTALL_DIR) if(NOT IS_ABSOLUTE "${${var}}") set(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}") endif() endforeach() include(MacroLogFeature) find_package(Qt5Core REQUIRED) # Do the building find_package(Libkolabxml 1.1.1 REQUIRED) macro_log_feature(Libkolabxml_FOUND "Libkolabxml" "Kolab XML Format 3 serializing library" "https://git.kolab.org/diffusion/LKX/" TRUE "1.1.1" "Required for reading/writing Kolab XML Objects") set(QT_REQUIRED_VERSION "5.2.0") if (Qt5_POSITION_INDEPENDENT_CODE) #Requires cmake 2.8.9 (same as -fPIC on gcc) set(CMAKE_POSITION_INDEPENDENT_CODE ON) endif() set(KDEPIMLIBS_LIB_VERSION "4.71.0") set(KMIME_LIB_VERSION "4.84.0") find_package(KF5CoreAddons CONFIG REQUIRED) find_package(KF5Akonadi ${KDEPIMLIBS_LIB_VERSION} CONFIG REQUIRED) find_package(KF5Contacts ${KDEPIMLIBS_LIB_VERSION} CONFIG REQUIRED) find_package(KF5CalendarCore ${KDEPIMLIBS_LIB_VERSION} CONFIG REQUIRED) find_package(KF5CalendarUtils ${KDEPIMLIBS_LIB_VERSION} CONFIG REQUIRED) find_package(KF5Mime ${KMIME_LIB_VERSION} CONFIG REQUIRED) find_package(KF5AkonadiNotes ${KDEPIMLIBS_LIB_VERSION} CONFIG REQUIRED) find_package(SWIG) #Show summary of found libraries macro_display_feature_log() # add_definitions(-DKDEPIMLIBS_VERSION=((${KdepimLibs_VERSION_MAJOR}<<16)|(${KdepimLibs_VERSION_MINOR}<<8)|(${KDEPIMLIBS_VERSION_PATCH}))) add_definitions(-DKDEPIMLIBS_VERSION_MAJOR=${KdepimLibs_VERSION_MAJOR}) add_definitions(-DKDEPIMLIBS_VERSION_MINOR=${KdepimLibs_VERSION_MINOR}) add_definitions(-DKDEPIMLIBS_VERSION_PATCH=${KdepimLibs_VERSION_PATCH}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor -Wno-long-long -ansi -Wundef -Wcast-align -Wchar-subscripts -Wall -W -Wpointer-arith -Wformat-security -fno-exceptions -DQT_NO_EXCEPTIONS -fno-common -Woverloaded-virtual -fno-threadsafe-statics -fvisibility=hidden -Werror=return-type -fvisibility-inlines-hidden -fexceptions -UQT_NO_EXCEPTIONS -fPIC -g -std=c++11") # message("${CMAKE_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DQT_NO_DEBUG") set(KDE_INCLUDES ${KDEPIMLIBS_INCLUDE_DIRS} ${KDE4_INCLUDES}) set(KDE_LIBRARIES KF5::CalendarCore KF5::CalendarUtils KF5::Contacts KF5::Mime KF5::AkonadiCore KF5::AkonadiNotes ) find_package(Boost REQUIRED) include_directories( ${QT_INCLUDES} ${KDE_INCLUDES} ${CMAKE_BINARY_DIR} ${Boost_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/kolabformatV2 ${Libkolabxml_INCLUDES} ./ ) configure_file(libkolab-version.h.cmake "${CMAKE_BINARY_DIR}/libkolab-version.h" @ONLY) add_subdirectory(kolabformatV2) add_subdirectory(conversion) add_subdirectory(calendaring) add_subdirectory(icalendar) add_subdirectory(freebusy) add_subdirectory(utils) QT5_WRAP_CPP(CALENDARING_MOC calendaring/event.h) # QT5_WRAP_CPP(CONVERSION_MOC conversion/qtevent.h conversion/qtduration.h) set(KOLAB_SRCS kolabformat/kolabobject.cpp kolabformat/xmlobject.cpp kolabformat/formathelpers.cpp kolabformat/errorhandler.cpp kolabformat/v2helpers.cpp kolabformat/mimeobject.cpp mime/mimeutils.cpp ${CONVERSION_SRCS} ${kolabformatv2_SRCS} ${CALENDARING_SRCS} ${ICALENDAR_SRCS} ${CALENDARING_MOC} ${CONVERSION_MOC} ${FREEBUSY_SRCS} ) set(KOLAB_LINK_LIBRARIES ${Libkolabxml_LIBRARIES} ${KDE_LIBRARIES} Qt5::Core Qt5::Xml Qt5::Gui Qt5::Widgets ) if(BUILD_TESTS) find_package(Qt5Test REQUIRED) #for tests only enable_testing() add_library(kolab_static STATIC ${KOLAB_SRCS}) target_link_libraries(kolab_static ${KOLAB_LINK_LIBRARIES} Qt5::Test) add_subdirectory(tests) endif(BUILD_TESTS) add_library(kolab SHARED ${KOLAB_SRCS}) target_link_libraries(kolab ${KOLAB_LINK_LIBRARIES}) set_target_properties(kolab PROPERTIES VERSION ${Libkolab_VERSION} SOVERSION ${Libkolab_VERSION_MAJOR}) install(TARGETS kolab EXPORT LibkolabExport RUNTIME DESTINATION ${BIN_INSTALL_DIR} LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} ) install(FILES kolab_export.h kolabformat/kolabdefinitions.h kolabformat/formathelpers.h kolabformat/kolabobject.h kolabformat/errorhandler.h kolabformat/xmlobject.h kolabformat/mimeobject.h conversion/kcalconversion.h conversion/kabcconversion.h conversion/commonconversion.h freebusy/freebusy.h DESTINATION ${INCLUDE_INSTALL_DIR} ) #Get the include directory relative to CMAKECONFIG_INSTALL_DIR file(RELATIVE_PATH REL_INCLUDE_DIR "${CMAKECONFIG_INSTALL_DIR}" "${INCLUDE_INSTALL_DIR}") #Assemble the full relative path. This will be used in the LibkolabConfig.cmake, which will be installed in CMAKECONFIG_INSTALL_DIR set(CONF_INCLUDE_DIRS "\${Libkolab_CMAKE_DIR}/${REL_INCLUDE_DIR}") install(EXPORT LibkolabExport DESTINATION ${CMAKECONFIG_INSTALL_DIR} FILE LibkolabTargets.cmake) configure_file(${Libkolab_MODULE_DIR}/LibkolabConfig.cmake.in ${Libkolab_BINARY_DIR}/LibkolabConfig.cmake @ONLY) configure_file(${Libkolab_MODULE_DIR}/LibkolabConfigVersion.cmake.in ${Libkolab_BINARY_DIR}/LibkolabConfigVersion.cmake @ONLY) # Install these two files into the same directory as the generated exports-file. install(FILES ${Libkolab_BINARY_DIR}/LibkolabConfig.cmake ${Libkolab_BINARY_DIR}/LibkolabConfigVersion.cmake DESTINATION ${CMAKECONFIG_INSTALL_DIR}) include(SWIGUtils) if(PYTHON_BINDINGS) generatePythonBindings(shared shared.i) add_subdirectory(kolabformat/python) endif(PYTHON_BINDINGS) if(PHP_BINDINGS) generatePHPBindings(kolabshared shared.i) generatePHPBindings(dummy dummy.i) add_subdirectory(kolabformat/php) endif(PHP_BINDINGS) libkolab-1.0.2/COPYING000066400000000000000000000001011262531616600143240ustar00rootroot00000000000000kolabformatV2/*: LGPLv2 or later Everything else: LGPLv3 or laterlibkolab-1.0.2/COPYING.LIB000066400000000000000000000636431262531616600147550ustar00rootroot00000000000000 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! libkolab-1.0.2/COPYING.lgplv3000066400000000000000000001045221262531616600155460ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, 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 them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU 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 Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state 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 program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . libkolab-1.0.2/README000066400000000000000000000017001262531616600141570ustar00rootroot00000000000000= About = Libkolab provides advanced calendaring functionality including: * recurrence handling * timezone handling * iTip/iMip parsing/generating * Freebusy generating To implement most of the functionality, the kdepim libraries are used. The functionality of this library can be exposed via SWIG bindings to other languages. Structure: * kolabformatv2: Kolabformat v2 implementation from kdepim-runtime (moved here) * kolabformat: Kolab object reading/writing (mime message + kolab-format). Handles v2/v3 transparently. Currently this interface uses the KDE Containers, eventually we'd want one that uses the Kolab Containers and can be wrapped in SWIG bindings. * conversion: Conversions from KDE to Kolab containers and vice verca. * mime: Mime message handling used by kolabformat * icalendar: Exposes iCalendar functionality: iCal reading/writing, iTip, iMip * calendaring: Some general calendaring functions * freebusy: Freebusy generating functions.libkolab-1.0.2/RELEASE-NOTES000066400000000000000000000001431262531616600151700ustar00rootroot00000000000000 == Attention to Distributors == * 0.3: Headers are now installed into $INCLUDE_INSTALL_DIR/kolab libkolab-1.0.2/autogen.sh000077500000000000000000000043311262531616600153030ustar00rootroot00000000000000#!/bin/bash dobuild=0 doprep=0 dotest=0 doinstall=0 srcdir=$(pwd) while [ $# -gt 0 ]; do case "$1" in --build|-b) dobuild=1 shift ;; --prep|-p) doprep=1 shift ;; --test|-t) dotest=1 shift ;; --install|-i) doinstall=1 shift ;; esac done if [ ${dobuild} -eq 0 -a ${doprep} -eq 0 -a ${dotest} -eq 0 -a ${doinstall} -eq 0 ]; then dobuild=1 doprep=1 dotest=1 doinstall=1 fi version_major=`grep -E "^set\s*\(Libkolab_VERSION_MAJOR [0-9]+\)" CMakeLists.txt | sed -r -e 's/^set\s*\(Libkolab_VERSION_MAJOR ([0-9]+)\)/\1/g'` version_minor=`grep -E "^set\s*\(Libkolab_VERSION_MINOR [0-9]+\)" CMakeLists.txt | sed -r -e 's/^set\s*\(Libkolab_VERSION_MINOR ([0-9]+)\)/\1/g'` version_patch=`grep -E "^set\s*\(Libkolab_VERSION_PATCH [0-9]+\)" CMakeLists.txt | sed -r -e 's/^set\s*\(Libkolab_VERSION_PATCH ([0-9]+)\)/\1/g'` if [ -z "${version_patch}" ]; then version="${version_major}.${version_minor}" else version="${version_major}.${version_minor}.${version_patch}" fi # Rebuilds the entire foo in one go. One shot, one kill. rm -rf build/ mkdir -p build cd build if [ ${doprep} -eq 1 ]; then cmake \ -DCMAKE_VERBOSE_MAKEFILE=ON \ -DCMAKE_INSTALL_PREFIX=/usr \ -DLIB_INSTALL_DIR=/usr/lib64 \ -DINCLUDE_INSTALL_DIR=/usr/include \ -DUSE_LIBCALENDARING=ON \ -DPHP_BINDINGS=ON \ -DPHP_INSTALL_DIR=/usr/lib64/php/modules \ -DPYTHON_BINDINGS=ON \ -DCMAKE_BUILD_TYPE=Release \ .. fi if [ ${dobuild} -eq 1 ]; then make fi if [ ${dotest} -eq 1 ]; then # Execute some tests? pushd tests unset DISPLAY ./benchmarktest ./calendaringtest ./formattest ./freebusytest ./icalendartest ./kcalconversiontest ./upgradetest popd fi if [ ${doinstall} -eq 1 ]; then make install DESTDIR=${TMPDIR:-/tmp} fi cd .. rm -rf libkolab-${version}.tar.gz git archive --prefix=libkolab-${version}/ HEAD | gzip -c > libkolab-${version}.tar.gz rm -rf `rpm --eval='%{_sourcedir}'`/libkolab-${version}.tar.gz cp libkolab-${version}.tar.gz `rpm --eval='%{_sourcedir}'` libkolab-1.0.2/calendaring/000077500000000000000000000000001262531616600155505ustar00rootroot00000000000000libkolab-1.0.2/calendaring/CMakeLists.txt000066400000000000000000000006121262531616600203070ustar00rootroot00000000000000set (CALENDARING_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/calendaring.cpp ${CMAKE_CURRENT_SOURCE_DIR}/event.cpp ${CMAKE_CURRENT_SOURCE_DIR}/datetimeutils.cpp PARENT_SCOPE) if(PYTHON_BINDINGS) message("building python bindings") add_subdirectory(python) endif(PYTHON_BINDINGS) if(PHP_BINDINGS) message("building php bindings") add_subdirectory(php) endif(PHP_BINDINGS) libkolab-1.0.2/calendaring/calendaring.cpp000066400000000000000000000077611262531616600205360ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include "calendaring.h" #include #include #include #include #include #include "conversion/kcalconversion.h" #include "conversion/commonconversion.h" namespace Kolab { namespace Calendaring { bool conflicts(const Kolab::Event &e1, const Kolab::Event &e2) { KCalCore::Event::Ptr k1 = Kolab::Conversion::toKCalCore(e1); KCalCore::Event::Ptr k2 = Kolab::Conversion::toKCalCore(e2); if (k2->dtEnd().compare(k1->dtStart()) == KDateTime::Before) { return false; } else if (k1->dtEnd().compare(k2->dtStart()) == KDateTime::Before) { return false; } return true; } std::vector< std::vector< Event > > getConflictingSets(const std::vector< Event > &events, const std::vector< Event > &events2) { std::vector< std::vector< Kolab::Event > > ret; for(std::size_t i = 0; i < events.size(); i++) { std::vector set; const Kolab::Event &event = events.at(i); set.push_back(event); for(std::size_t q = i+1; q < events.size(); q++) { const Kolab::Event &e2 = events.at(q); if (conflicts(event, e2)) { set.push_back(e2); } } for(std::size_t m = 0; m < events2.size(); m++) { const Kolab::Event &e2 = events2.at(m); if (conflicts(event, e2)) { set.push_back(e2); } } if (set.size() > 1) { ret.push_back(set); } } return ret; } std::vector timeInInterval(const Kolab::Event &e, const Kolab::cDateTime &start, const Kolab::cDateTime &end) { KCalCore::Event::Ptr k = Kolab::Conversion::toKCalCore(e); KCalCore::DateTimeList list = k->recurrence()->timesInInterval(Kolab::Conversion::toDate(start), Kolab::Conversion::toDate(end)); std::vector dtList; foreach(const KDateTime &dt, list) { dtList.push_back(Kolab::Conversion::fromDate(dt)); } return dtList; } Calendar::Calendar() : mCalendar(new KCalCore::MemoryCalendar(Kolab::Conversion::getTimeSpec(true, std::string()))) //Always utc as it doesn't change anything anyways { } void Calendar::addEvent(const Kolab::Event &event) { KCalCore::Event::Ptr k = Kolab::Conversion::toKCalCore(event); if (!mCalendar->addEvent(k)) { qWarning() << "failed to add event"; } } std::vector Calendar::getEvents(const Kolab::cDateTime& start, const Kolab::cDateTime& end, bool sort) { const KDateTime s = Kolab::Conversion::toDate(start); const KDateTime e = Kolab::Conversion::toDate(end); const KDateTime::Spec timeSpec = s.timeSpec(); KCalCore::Event::List list = mCalendar->events(s.date(), e.date(), timeSpec, true); if (sort) { list = mCalendar->sortEvents(list, KCalCore::EventSortStartDate, KCalCore::SortDirectionAscending); } std::vector eventlist; foreach (const KCalCore::Event::Ptr &event, list) { //We have to filter the list by time if (event->dtEnd().compare(s) != KDateTime::Before && e.compare(event->dtStart()) != KDateTime::Before) { eventlist.push_back(Kolab::Conversion::fromKCalCore(*event)); } } return eventlist; } } //Namespace } //Namespace libkolab-1.0.2/calendaring/calendaring.h000066400000000000000000000055431262531616600201770ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef KOLABCALENDARING_H #define KOLABCALENDARING_H #ifndef SWIG #include "kolab_export.h" #else /* No export/import SWIG interface files */ #define KOLAB_EXPORT #endif #include #include #include #include namespace Kolab { namespace Calendaring { /** * Returns true if the events conflict (overlap) * Start and end date/time is inclusive. * * Does not take recurrences into account. */ KOLAB_EXPORT bool conflicts(const Kolab::Event &, const Kolab::Event &); /** * Returns sets of the events which are directly conflicting with each other. * The same event may appear in multiple sets. * Non-conflicting events are not returned. * conflicts() is used for conflict detection. * * If the second list is given, each event from the first list is additionally checked against each event of the second set. * Conflicts within the second list are not detected. * * The checked event from the first list comes always first in the returned set. */ KOLAB_EXPORT std::vector< std::vector > getConflictingSets(const std::vector &, const std::vector & = std::vector()); /** * Returns the dates in which the event recurs within the specified timespan. */ KOLAB_EXPORT std::vector timeInInterval(const Kolab::Event &, const Kolab::cDateTime &start, const Kolab::cDateTime &end); /** * In-Memory Calendar Cache */ class KOLAB_EXPORT Calendar { public: explicit Calendar(); /** * Add an event to the in-memory calendar. */ void addEvent(const Kolab::Event &); /** * Returns all events within the specified interval (start and end inclusive). * * @param sort controls if the resulting event set is sorted in ascending order according to the start date */ std::vector getEvents(const Kolab::cDateTime &start, const Kolab::cDateTime &end, bool sort); private: Calendar(const Calendar &); void operator=(const Calendar &); boost::scoped_ptr mCalendar; }; }; //Namespace }; //Namespace #endif libkolab-1.0.2/calendaring/calendaring.i000066400000000000000000000010401262531616600201640ustar00rootroot00000000000000%{ /* This macro ensures that return vectors remain a vector also in python and are not converted to tuples */ #define SWIG_PYTHON_EXTRA_NATIVE_CONTAINERS #include "../calendaring/calendaring.h" #include "../calendaring/event.h" %} %include "std_string.i" %include "std_vector.i" %import(module="kolabformat") %import "../shared.i" %rename(EventCal) Kolab::Calendaring::Event; %rename(KolabCalendar) Kolab::Calendaring::Calendar; %include "../calendaring/calendaring.h" %include "../calendaring/event.h" libkolab-1.0.2/calendaring/datetimeutils.cpp000066400000000000000000000021011262531616600211230ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include "datetimeutils.h" #include #include #include "conversion/commonconversion.h" namespace Kolab { namespace DateTimeUtils { KOLAB_EXPORT std::string getLocalTimezone() { const QString tz = QTimeZone::systemTimeZoneId(); return tz.toStdString(); } } //Namespace } //Namespace libkolab-1.0.2/calendaring/datetimeutils.h000066400000000000000000000020731262531616600206000ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef KOLABDATETIMEUTILS_H #define KOLABDATETIMEUTILS_H #ifndef SWIG #include "kolab_export.h" #else /* No export/import SWIG interface files */ #define KOLAB_EXPORT #endif #include namespace Kolab { namespace DateTimeUtils { KOLAB_EXPORT std::string getLocalTimezone(); }; //Namespace }; //Namespace #endif libkolab-1.0.2/calendaring/event.cpp000066400000000000000000000161531262531616600174030ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include "event.h" #include #include #include #include #include #include #include namespace Kolab { namespace Calendaring { Event::Event() : Kolab::Event() { setUid(Kolab::generateUID()); } Event::Event(const Kolab::Event &e) : Kolab::Event(e) { } Event::~Event() { } bool Event::read(const std::string &string) { const Kolab::Event &e = Kolab::readEvent(string, false); if (Kolab::error()) { return false; } Kolab::Event::operator=(e); return true; } std::string Event::write() const { return Kolab::writeEvent(*this); } bool Event::fromMime(const std::string &input) { KMime::Message::Ptr msg = KMime::Message::Ptr(new KMime::Message); msg->setContent( KMime::CRLFtoLF(Kolab::Conversion::fromStdString(input).toUtf8()) ); msg->parse(); msg->content(KMime::ContentIndex()); KolabObjectReader reader(msg); if (reader.getType() != EventObject) { std::cout << "not an event "; return false; } const Kolab::Event &e = Kolab::Conversion::fromKCalCore(*reader.getEvent()); Kolab::Event::operator=(e); return true; } std::string Event::toMime() const { return std::string(QString(KolabObjectWriter::writeEvent(Kolab::Conversion::toKCalCore(*this))->encodedContent()).toUtf8().constData()); } bool Event::fromICal(const std::string &input) { std::vector list = fromICalEvents(input); if (list.size() != 1) { std::cout << "invalid number of events: " << list.size(); return false; } Kolab::Event::operator=(list.at(0)); return true; } std::string Event::toICal() const { std::vector list; list.push_back(*this); return Kolab::toICal(list); } bool Event::fromIMip(const std::string &input) { std::vector list = mITipHandler.fromIMip(input); if (list.size() != 1) { std::cout << "invalid number of events: " << list.size(); return false; } Kolab::Event::operator=(list.at(0)); return true; } std::string Event::toIMip(ITipMethod method) const { std::vector list; list.push_back(*this); return mITipHandler.toIMip(*this, static_cast(method), organizer().email()); } Calendaring::Event::ITipMethod Event::getSchedulingMethod() const { Q_ASSERT((int)iTIPPublish == (int)ITipHandler::iTIPPublish); Q_ASSERT((int)iTIPNoMethod == (int)ITipHandler::iTIPNoMethod); return static_cast(mITipHandler.method()); } bool contains(const Kolab::ContactReference &delegatorRef, const std::vector &list) { foreach (const Kolab::ContactReference &ref, list) { if (delegatorRef.uid() == ref.uid() || delegatorRef.email() == ref.email() || delegatorRef.name() == ref.name()) { return true; } } return false; } void Event::delegate(const std::vector< Attendee >& delegators, const std::vector< Attendee >& delegatees) { //First build a list of attendee references, and insert any missing attendees std::vector delegateesRef; foreach(const Attendee &a, delegatees) { if (Attendee *attendee = getAttendee(a.contact())) { delegateesRef.push_back(attendee); } else { d->attendees.push_back(a); delegateesRef.push_back(&d->attendees.back()); } } std::vector delegatorsRef; foreach(const Attendee& a, delegators) { if (Attendee *attendee = getAttendee(a.contact())) { delegatorsRef.push_back(attendee); } else { std::cout << "missing delegator"; } } foreach (Attendee *delegatee, delegateesRef) { std::vector delegatedFrom = delegatee->delegatedFrom(); foreach (Attendee *delegator, delegatorsRef) { //Set the delegator on each delegatee const ContactReference &delegatorRef = delegator->contact(); if (!contains(delegatorRef, delegatedFrom)) { delegatedFrom.push_back(Kolab::ContactReference(Kolab::ContactReference::EmailReference, delegatorRef.email(), delegatorRef.name())); } //Set the delegatee on each delegator std::vector delegatedTo = delegator->delegatedTo(); const ContactReference &delegaeeRef = delegatee->contact(); if (!contains(delegaeeRef, delegatedTo)) { delegatedTo.push_back(Kolab::ContactReference(Kolab::ContactReference::EmailReference, delegaeeRef.email(), delegaeeRef.name())); } delegator->setDelegatedTo(delegatedTo); } delegatee->setDelegatedFrom(delegatedFrom); } } Attendee *Event::getAttendee(const ContactReference &ref) { for(std::vector ::iterator it = d->attendees.begin(); it != d->attendees.end(); it++) { if (it->contact().uid() == ref.uid() || it->contact().email() == ref.email() || it->contact().name() == ref.name()) { return &*it; } } return 0; } Attendee Event::getAttendee(const std::string &s) { foreach(const Attendee &a, attendees()) { if (a.contact().uid() == s || a.contact().email() == s || a.contact().name() == s) { return a; } } return Attendee(); } cDateTime Calendaring::Event::getNextOccurence(const cDateTime &date) { KCalCore::Event::Ptr event = Kolab::Conversion::toKCalCore(*this); if (!event->recurs()) { return cDateTime(); } const KDateTime nextDate = event->recurrence()->getNextDateTime(Kolab::Conversion::toDate(date)); return Kolab::Conversion::fromDate(nextDate); } cDateTime Calendaring::Event::getOccurenceEndDate(const cDateTime &startDate) { KCalCore::Event::Ptr event = Kolab::Conversion::toKCalCore(*this); const KDateTime start = Kolab::Conversion::toDate(startDate); return Kolab::Conversion::fromDate(event->endDateForStart(start)); } cDateTime Calendaring::Event::getLastOccurrence() const { KCalCore::Event::Ptr event = Kolab::Conversion::toKCalCore(*this); if (!event->recurs()) { return cDateTime(); } const KDateTime endDate = event->recurrence()->endDateTime(); return Kolab::Conversion::fromDate(endDate); } }; }; libkolab-1.0.2/calendaring/event.h000066400000000000000000000076261262531616600170550ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef EVENT_H #define EVENT_H #include #ifndef SWIG #include "kolab_export.h" #include #else /* No export/import SWIG interface files */ #define KOLAB_EXPORT #endif namespace Kolab { namespace Calendaring { class KOLAB_EXPORT Event: public Kolab::Event { public: Event(); Event(const Kolab::Event &); ~Event(); bool read(const std::string &); /** * Convert to kolab xml format. */ std::string write() const; bool fromMime(const std::string &); /** * Convert to kolab mime format. */ std::string toMime() const; enum ITipMethod { iTIPPublish, /**< Event, to-do, journal or freebusy posting */ iTIPRequest, /**< Event, to-do or freebusy scheduling request */ iTIPReply, /**< Event, to-do or freebusy reply to request */ iTIPAdd, /**< Event, to-do or journal additional property request */ iTIPCancel, /**< Event, to-do or journal cancellation notice */ iTIPRefresh, /**< Event or to-do description update request */ iTIPCounter, /**< Event or to-do submit counter proposal */ iTIPDeclineCounter,/**< Event or to-do decline a counter proposal */ iTIPNoMethod /**< No method */ }; bool fromICal(const std::string &); std::string toICal() const; bool fromIMip(const std::string &); std::string toIMip(ITipMethod method) const; /** * Returns the scheduling method from the last fromIMip call */ ITipMethod getSchedulingMethod() const; /** * Updates the delegators and delegatees of the event. * * Creates a new attendee for each missing delegatee (delegators are expected to be existing), and then updates each delegatee with the delegator (delegatedFrom). * Delegators delegatedTo is updated accordingly. * Existing attendees are tried to be found by uid/email/name (in this order). * */ void delegate(const std::vector &delegators, const std::vector &delegatees); /** * Get attendee by uid/email/name (in this order) */ Kolab::Attendee getAttendee(const std::string &); /** * Returns the next occurence for a recurring event. * * If the start date of the event is passed in, the second occurence is returned (so it can be used in a for loop to loop through all occurences). * * If there is no next occurence or the event is not recurring at all an invalid cDateTime is returned. */ Kolab::cDateTime getNextOccurence(const Kolab::cDateTime &); /** * Returns the corresponding end date-time for a specific occurence. * @param start is the start date of the occurence. */ Kolab::cDateTime getOccurenceEndDate(const Kolab::cDateTime &start); /** * Returns the last occurrence, or and invalid cDateTime if the event is not recurring or recurring idenfinitely. */ Kolab::cDateTime getLastOccurrence() const; private: Kolab::Attendee *getAttendee(const ContactReference &); Kolab::ITipHandler mITipHandler; }; }; }; #endif // EVENT_H libkolab-1.0.2/calendaring/php/000077500000000000000000000000001262531616600163375ustar00rootroot00000000000000libkolab-1.0.2/calendaring/php/CMakeLists.txt000066400000000000000000000001711262531616600210760ustar00rootroot00000000000000#Generate PHP wrapper include_directories(../) include(SWIGUtils) generatePHPBindings(kolabcalendaring ../calendaring.i) libkolab-1.0.2/calendaring/php/test.php000066400000000000000000000147531262531616600200410ustar00rootroot00000000000000 Libkolab-0.4 Libkolabxml-0.9 2.0 3.0dev1 DDDEBE616DB7480A003725D1D7C4C2FE-8C02E7EEB49870A2 2012-10-23T11:04:53Z 2012-10-23T13:04:53Z 0 PUBLIC /kolab.org/Europe/Paris 2012-10-23T14:00:00 /kolab.org/Europe/Paris 2012-10-23T15:30:00 DAILY 4 2 Recurring with libkolab EOF; $rdates = << Roundcube-libkolab-0.9 Libkolabxml-1.1 2.0 3.1.0 49961C572093EC3FC125799C004A200F-Lotus_Notes_Generated 2014-02-28T12:57:42Z 2014-02-28T12:57:42Z 0 PUBLIC /kolab.org/Europe/Amsterdam 2012-03-30T04:00:00 /kolab.org/Europe/Amsterdam 2012-03-30T20:00:00 TRANSPARENT 2012-03-30 2013-03-30 2014-03-30 2015-03-30 2016-03-30 2017-03-30 2018-03-30 2019-03-30 2020-03-30 2021-03-30 Geburtstag Jane Doe (30.03.1969) EOF; $e = kolabformat::readEvent($xml, false); $ec = new EventCal($e); $rstart = new cDateTime(2012,8,1, 0,0,0); # asserttrue($ec->getNextOccurence($rstart) instanceof cDateTime, "EventCal::getNextOccurence() returning cDateTime instance"); $next = new cDateTime($ec->getNextOccurence($rstart)); assertequal( sprintf("%d-%d-%d %02d:%02d:%02d", $next->year(), $next->month(), $next->day(), $next->hour(), $next->minute(), $next->second()), "2012-10-23 14:00:00", "EventCal first recurrence" ); $next = new cDateTime($ec->getNextOccurence($next)); assertequal( sprintf("%d-%d-%d %02d:%02d:%02d", $next->year(), $next->month(), $next->day(), $next->hour(), $next->minute(), $next->second()), "2012-10-25 14:00:00", "EventCal second recurrence" ); $end = new cDateTime($ec->getOccurenceEndDate($next)); assertequal( sprintf("%d-%d-%d %02d:%02d:%02d", $end->year(), $end->month(), $end->day(), $end->hour(), $end->minute(), $end->second()), "2012-10-25 15:30:00", "EventCal::getOccurenceEndDate" ); $last = new cDateTime($ec->getLastOccurrence()); assertequal( sprintf("%d-%d-%d %02d:%02d:%02d", $last->year(), $last->month(), $last->day(), $last->hour(), $last->minute(), $last->second()), "2012-10-29 14:00:00", "EventCal::getLastOccurence" ); // test event with RDATE list $e = kolabformat::readEvent($rdates, false); $ec = new EventCal($e); $rstart = new cDateTime(2012,3,1, 0,0,0); $next = new cDateTime($ec->getNextOccurence($rstart)); assertequal( sprintf("%d-%02d-%02d %02d:%02d:%02d", $next->year(), $next->month(), $next->day(), $next->hour(), $next->minute(), $next->second()), "2012-03-30 04:00:00", "RDATE first recurrence" ); $next = new cDateTime($ec->getNextOccurence($next)); assertequal( sprintf("%d-%02d-%02d %02d:%02d:%02d", $next->year(), $next->month(), $next->day(), $next->hour(), $next->minute(), $next->second()), "2013-03-30 04:00:00", "RDATE next recurrence" ); $last = new cDateTime($ec->getLastOccurrence()); assertequal( sprintf("%d-%02d-%d %02d:%02d:%02d", $last->year(), $last->month(), $last->day(), $last->hour(), $last->minute(), $last->second()), "2021-03-30 04:00:00", "RDATE last occurence" ); // terminate with error status exit($errors); libkolab-1.0.2/calendaring/python/000077500000000000000000000000001262531616600170715ustar00rootroot00000000000000libkolab-1.0.2/calendaring/python/CMakeLists.txt000066400000000000000000000001401262531616600216240ustar00rootroot00000000000000include_directories(../) include(SWIGUtils) generatePythonBindings(calendaring ../calendaring.i)libkolab-1.0.2/cmake/000077500000000000000000000000001262531616600143615ustar00rootroot00000000000000libkolab-1.0.2/cmake/modules/000077500000000000000000000000001262531616600160315ustar00rootroot00000000000000libkolab-1.0.2/cmake/modules/COPYING-CMAKE-SCRIPTS000066400000000000000000000024571262531616600210370ustar00rootroot00000000000000Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. libkolab-1.0.2/cmake/modules/FindLibcalendaring.cmake000066400000000000000000000023751262531616600225410ustar00rootroot00000000000000find_package(PkgConfig) include(FindPackageHandleStandardArgs) find_library(CALENDARING_KDECORE NAMES calendaring-kdecore) find_library(CALENDARING_KCALCORE NAMES calendaring-kcalcore) find_library(CALENDARING_KMIME NAMES calendaring-kmime) find_library(CALENDARING_KIMAP NAMES calendaring-kimap) find_library(CALENDARING_KABC NAMES calendaring-kabc) find_library(CALENDARING_NOTES NAMES calendaring-akonadi-notes) find_library(CALENDARING_KCALUTILS NAMES calendaring-kcalutils) find_library(CALENDARING_KPIMUTILS NAMES calendaring-kpimutils) find_path(CALENDARING_INCLUDE_DIRS NAMES calendaring/kdatetime.h) set( Libcalendaring_INCLUDE_DIRS "${CALENDARING_INCLUDE_DIRS}/calendaring" ) set( Libcalendaring_LIBRARIES ${CALENDARING_KDECORE} ${CALENDARING_KCALCORE} ${CALENDARING_KMIME} ${CALENDARING_KIMAP} ${CALENDARING_KABC} ${CALENDARING_NOTES} ${CALENDARING_KCALUTILS} ${CALENDARING_KPIMUTILS}) set(KdepimLibs_VERSION_MAJOR 4) set(KdepimLibs_VERSION_MINOR 10) set(KdepimLibs_VERSION_PATCH 0) find_package_handle_standard_args(Libcalendaring DEFAULT_MSG CALENDARING_KDECORE CALENDARING_KCALCORE CALENDARING_KMIME CALENDARING_KIMAP CALENDARING_KABC CALENDARING_NOTES CALENDARING_KCALUTILS CALENDARING_KPIMUTILS CALENDARING_INCLUDE_DIRS) libkolab-1.0.2/cmake/modules/FindSWIG.cmake000066400000000000000000000002071262531616600204040ustar00rootroot00000000000000find_program(SWIG swig /usr/bin/) #abort if any of the requireds are missing find_package_handle_standard_args(SWIG DEFAULT_MSG SWIG) libkolab-1.0.2/cmake/modules/LibkolabConfig.cmake.in000066400000000000000000000012031262531616600223010ustar00rootroot00000000000000get_filename_component(Libkolab_CMAKE_DIR ${CMAKE_CURRENT_LIST_FILE} PATH) #get the directory where this *Config.cmake file is installed # set the version set(Libkolab_VERSION_MAJOR @Libkolab_VERSION_MAJOR@) set(Libkolab_VERSION_MINOR @Libkolab_VERSION_MINOR@) set(Libkolab_VERSION_PATCH @Libkolab_VERSION_PATCH@) set(Libkolab_VERSION ${Libkolab_VERSION_MAJOR}.${Libkolab_VERSION_MINOR}.${Libkolab_VERSION_PATCH} ) # Set the include directory set(Libkolab_INCLUDES "@CONF_INCLUDE_DIRS@") # import the exported targets include(${Libkolab_CMAKE_DIR}/LibkolabTargets.cmake) # set the expected library variable set(Libkolab_LIBRARIES kolab ) libkolab-1.0.2/cmake/modules/LibkolabConfigVersion.cmake.in000066400000000000000000000013601262531616600236530ustar00rootroot00000000000000# Sets PACKAGE_VERSION_EXACT if the current version string and the requested # version string are exactly the same and it sets PACKAGE_VERSION_COMPATIBLE # if the current version is >= requested version. set(PACKAGE_VERSION @Libkolab_VERSION_MAJOR@.@Libkolab_VERSION_MINOR@.@Libkolab_VERSION_PATCH@) if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" ) set(PACKAGE_VERSION_COMPATIBLE FALSE) else("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" ) set(PACKAGE_VERSION_COMPATIBLE TRUE) if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}") set(PACKAGE_VERSION_EXACT TRUE) endif( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}") endif("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" ) libkolab-1.0.2/cmake/modules/MacroLogFeature.cmake000066400000000000000000000140101262531616600220460ustar00rootroot00000000000000# This file defines the Feature Logging macros. # # MACRO_LOG_FEATURE(VAR FEATURE DESCRIPTION URL [REQUIRED [MIN_VERSION [COMMENTS]]]) # Logs the information so that it can be displayed at the end # of the configure run # VAR : TRUE or FALSE, indicating whether the feature is supported # FEATURE: name of the feature, e.g. "libjpeg" # DESCRIPTION: description what this feature provides # URL: home page # REQUIRED: TRUE or FALSE, indicating whether the featue is required # MIN_VERSION: minimum version number. empty string if unneeded # COMMENTS: More info you may want to provide. empty string if unnecessary # # MACRO_DISPLAY_FEATURE_LOG() # Call this to display the collected results. # Exits CMake with a FATAL error message if a required feature is missing # # Example: # # INCLUDE(MacroLogFeature) # # FIND_PACKAGE(JPEG) # MACRO_LOG_FEATURE(JPEG_FOUND "libjpeg" "Support JPEG images" "http://www.ijg.org" TRUE "3.2a" "") # ... # MACRO_DISPLAY_FEATURE_LOG() # Copyright (c) 2006, Alexander Neundorf, # Copyright (c) 2006, Allen Winter, # Copyright (c) 2009, Sebastian Trueg, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. IF (NOT _macroLogFeatureAlreadyIncluded) SET(_file ${CMAKE_BINARY_DIR}/MissingRequirements.txt) IF (EXISTS ${_file}) FILE(REMOVE ${_file}) ENDIF (EXISTS ${_file}) SET(_file ${CMAKE_BINARY_DIR}/EnabledFeatures.txt) IF (EXISTS ${_file}) FILE(REMOVE ${_file}) ENDIF (EXISTS ${_file}) SET(_file ${CMAKE_BINARY_DIR}/DisabledFeatures.txt) IF (EXISTS ${_file}) FILE(REMOVE ${_file}) ENDIF (EXISTS ${_file}) SET(_macroLogFeatureAlreadyIncluded TRUE) INCLUDE(FeatureSummary) ENDIF (NOT _macroLogFeatureAlreadyIncluded) MACRO(MACRO_LOG_FEATURE _var _package _description _url ) # _required _minvers _comments) STRING(TOUPPER "${ARGV4}" _required) SET(_minvers "${ARGV5}") SET(_comments "${ARGV6}") IF (${_var}) SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/EnabledFeatures.txt) ELSE (${_var}) IF ("${_required}" STREQUAL "TRUE") SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/MissingRequirements.txt) ELSE ("${_required}" STREQUAL "TRUE") SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/DisabledFeatures.txt) ENDIF ("${_required}" STREQUAL "TRUE") ENDIF (${_var}) SET(_logtext " * ${_package}") IF (NOT ${_var}) IF (${_minvers} MATCHES ".*") SET(_logtext "${_logtext} (${_minvers} or higher)") ENDIF (${_minvers} MATCHES ".*") SET(_logtext "${_logtext} <${_url}>\n ") ELSE (NOT ${_var}) SET(_logtext "${_logtext} - ") ENDIF (NOT ${_var}) SET(_logtext "${_logtext}${_description}") IF (NOT ${_var}) IF (${_comments} MATCHES ".*") SET(_logtext "${_logtext}\n ${_comments}") ENDIF (${_comments} MATCHES ".*") # SET(_logtext "${_logtext}\n") #double-space missing features? ENDIF (NOT ${_var}) FILE(APPEND "${_LOGFILENAME}" "${_logtext}\n") IF(COMMAND SET_PACKAGE_INFO) # in FeatureSummary.cmake since CMake 2.8.3 SET_PACKAGE_INFO("${_package}" "\"${_description}\"" "${_url}" "\"${_comments}\"") ENDIF(COMMAND SET_PACKAGE_INFO) ENDMACRO(MACRO_LOG_FEATURE) MACRO(MACRO_DISPLAY_FEATURE_LOG) IF(COMMAND FEATURE_SUMMARY) # in FeatureSummary.cmake since CMake 2.8.3 FEATURE_SUMMARY(FILENAME ${CMAKE_CURRENT_BINARY_DIR}/FindPackageLog.txt WHAT ALL) ENDIF(COMMAND FEATURE_SUMMARY) SET(_missingFile ${CMAKE_BINARY_DIR}/MissingRequirements.txt) SET(_enabledFile ${CMAKE_BINARY_DIR}/EnabledFeatures.txt) SET(_disabledFile ${CMAKE_BINARY_DIR}/DisabledFeatures.txt) IF (EXISTS ${_missingFile} OR EXISTS ${_enabledFile} OR EXISTS ${_disabledFile}) SET(_printSummary TRUE) ENDIF (EXISTS ${_missingFile} OR EXISTS ${_enabledFile} OR EXISTS ${_disabledFile}) IF(_printSummary) SET(_missingDeps 0) IF (EXISTS ${_enabledFile}) FILE(READ ${_enabledFile} _enabled) FILE(REMOVE ${_enabledFile}) SET(_summary "${_summary}\n-----------------------------------------------------------------------------\n-- The following external packages were located on your system.\n-- This installation will have the extra features provided by these packages.\n-----------------------------------------------------------------------------\n${_enabled}") ENDIF (EXISTS ${_enabledFile}) IF (EXISTS ${_disabledFile}) SET(_missingDeps 1) FILE(READ ${_disabledFile} _disabled) FILE(REMOVE ${_disabledFile}) SET(_summary "${_summary}\n-----------------------------------------------------------------------------\n-- The following OPTIONAL packages could NOT be located on your system.\n-- Consider installing them to enable more features from this software.\n-----------------------------------------------------------------------------\n${_disabled}") ENDIF (EXISTS ${_disabledFile}) IF (EXISTS ${_missingFile}) SET(_missingDeps 1) FILE(READ ${_missingFile} _requirements) SET(_summary "${_summary}\n-----------------------------------------------------------------------------\n-- The following REQUIRED packages could NOT be located on your system.\n-- You must install these packages before continuing.\n-----------------------------------------------------------------------------\n${_requirements}") FILE(REMOVE ${_missingFile}) SET(_haveMissingReq 1) ENDIF (EXISTS ${_missingFile}) IF (NOT ${_missingDeps}) SET(_summary "${_summary}\n-----------------------------------------------------------------------------\n-- Congratulations! All external packages have been found.") ENDIF (NOT ${_missingDeps}) MESSAGE(${_summary}) MESSAGE("-----------------------------------------------------------------------------\n") IF(_haveMissingReq) MESSAGE(FATAL_ERROR "Exiting: Missing Requirements") ENDIF(_haveMissingReq) ENDIF(_printSummary) ENDMACRO(MACRO_DISPLAY_FEATURE_LOG) libkolab-1.0.2/cmake/modules/SWIGUtils.cmake000066400000000000000000000124201262531616600206240ustar00rootroot00000000000000 macro (generatePHPBindings MODULE_NAME INTERFACE_FILE) set(KOLAB_SWIG_PHP_SOURCE_FILE php_${MODULE_NAME}_wrapper.cpp) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${KOLAB_SWIG_PHP_SOURCE_FILE} ${CMAKE_CURRENT_BINARY_DIR}/${MODULE_NAME}.php COMMAND ${SWIG} -v -c++ -php -I${Libkolabxml_INCLUDES} -module ${MODULE_NAME} -o ${CMAKE_CURRENT_BINARY_DIR}/${KOLAB_SWIG_PHP_SOURCE_FILE} ${INTERFACE_FILE} COMMENT "Generating php bindings" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${INTERFACE_FILE} kolab VERBATIM ) SET_SOURCE_FILES_PROPERTIES(${KOLAB_SWIG_PHP_SOURCE_FILE} PROPERTIES GENERATED 1) ADD_CUSTOM_TARGET(generate_${MODULE_NAME}_php_bindings ALL DEPENDS ${KOLAB_SWIG_PHP_SOURCE_FILE}) #Compile PHP Bindings # Since there is no php library we can't compile with -Wl,--no-undefined set(CMAKE_SHARED_LINKER_FLAGS "") if (APPLE) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flat_namespace -undefined suppress" ) else() set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused" ) endif() set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-missing-field-initializers -Wno-undef" ) # Try to find PHP5 find_path(PHP_INCLUDE_DIR NAMES main/php.h PATH_SUFFIXES php php5) find_program(PHP_EXECUTABLE NAMES php) # Libkolab needs PHP >= 5.3 set(PHP_MIN_VERSION 50300) # Find where to install the extension files if it's not defined if(NOT DEFINED PHP_INSTALL_DIR) find_program(PHP_CONFIG_EXECUTABLE NAMES php-config) if(PHP_CONFIG_EXECUTABLE) execute_process(COMMAND ${PHP_CONFIG_EXECUTABLE} --extension-dir OUTPUT_VARIABLE _php_extensions_dir ) string(REGEX REPLACE "\n" "" _php_extensions_dir "${_php_extensions_dir}") set(PHP_INSTALL_DIR ${_php_extensions_dir} CACHE STRING "Install directory for PHP bindings.") else() set(PHP_INSTALL_DIR ${LIB_INSTALL_DIR}/extensions) endif() endif() if(PHP_INCLUDE_DIR AND PHP_EXECUTABLE) file(READ ${PHP_INCLUDE_DIR}/main/php_version.h PHP_VERSION_CONTENT) string(REGEX MATCH "#define PHP_VERSION_ID[ ]*[0-9]*\n" _PHP_VERSION_ID_MATCH ${PHP_VERSION_CONTENT}) if(_PHP_VERSION_ID_MATCH) string(REGEX REPLACE "#define PHP_VERSION_ID[ ]*([0-9]*)\n" "\\1" PHP_VERSION_ID ${_PHP_VERSION_ID_MATCH}) endif() # Include the needed PHP5 subdirs set(PHP_INCLUDE_DIRS ${PHP_INCLUDE_DIR} ${PHP_INCLUDE_DIR}/main ${PHP_INCLUDE_DIR}/TSRM ${PHP_INCLUDE_DIR}/Zend ) endif() if(NOT PHP_VERSION_ID VERSION_LESS ${PHP_MIN_VERSION}) include_directories(${PHP_INCLUDE_DIRS}) add_library(${MODULE_NAME}_phpbindings SHARED ${KOLAB_SWIG_PHP_SOURCE_FILE}) target_link_libraries(${MODULE_NAME}_phpbindings kolab) set_target_properties(${MODULE_NAME}_phpbindings PROPERTIES OUTPUT_NAME ${MODULE_NAME}) set_target_properties(${MODULE_NAME}_phpbindings PROPERTIES PREFIX "") # configure_file(test.php ${CMAKE_CURRENT_BINARY_DIR} COPYONLY) install(TARGETS ${MODULE_NAME}_phpbindings LIBRARY DESTINATION ${PHP_INSTALL_DIR}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${MODULE_NAME}.php DESTINATION ${PHP_INSTALL_DIR} ) else() message(WARNING "not building php bindings because php was not found") endif() endmacro() macro(generatePythonBindings MODULE_NAME INTERFACE_FILE) find_package(SWIG REQUIRED) # Compile Python Bindings find_package(PythonLibs) if (NOT PYTHONLIBS_FOUND) message("python libs not found, not building python bindings") return() endif() message("found python include dirs: ${PYTHON_INCLUDE_DIRS} ${PYTHON_INCLUDE_PATH}") set(KOLAB_SWIG_PYTHON_SOURCE_FILE ${CMAKE_CURRENT_BINARY_DIR}/python_${MODULE_NAME}_wrapper.cpp) set(KOLAB_SWIG_PYTHON_HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/${MODULE_NAME}.py) add_custom_command(OUTPUT ${KOLAB_SWIG_PYTHON_SOURCE_FILE} ${KOLAB_SWIG_PYTHON_HEADER_FILE} COMMAND ${SWIG} -v -c++ -python -module ${MODULE_NAME} -I${Libkolabxml_INCLUDES} -o ${KOLAB_SWIG_PYTHON_SOURCE_FILE} ${INTERFACE_FILE} COMMENT "Generating python bindings" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${INTERFACE_FILE} kolab VERBATIM ) SET_SOURCE_FILES_PROPERTIES(${KOLAB_SWIG_PYTHON_SOURCE_FILE} PROPERTIES GENERATED 1) #${PYTHON_INCLUDE_PATH} is for backwards compatibility (el6) include_directories(${PYTHON_INCLUDE_DIRS} ${PYTHON_INCLUDE_PATH}) set(PYTHON_MODULE_PREFIX "_") python_add_module(${MODULE_NAME} ${KOLAB_SWIG_PYTHON_SOURCE_FILE}) #cmake 2.6.4 fails to respect the module prefix SET_TARGET_PROPERTIES(${MODULE_NAME} PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}") target_link_libraries(${MODULE_NAME} kolab ${PYTHON_LIBRARIES}) # configure_file(test.py ${CMAKE_CURRENT_BINARY_DIR} COPYONLY) set(PYTHON_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/pythonbindings" CACHE STRING "Install directory for python bindings.") install(TARGETS ${MODULE_NAME} LIBRARY DESTINATION ${PYTHON_INSTALL_DIR}/kolab) install( FILES ${KOLAB_SWIG_PYTHON_HEADER_FILE} DESTINATION ${PYTHON_INSTALL_DIR}/kolab ) endmacro() libkolab-1.0.2/conversion/000077500000000000000000000000001262531616600154665ustar00rootroot00000000000000libkolab-1.0.2/conversion/CMakeLists.txt000066400000000000000000000004541262531616600202310ustar00rootroot00000000000000 set (CONVERSION_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/kcalconversion.cpp ${CMAKE_CURRENT_SOURCE_DIR}/kabcconversion.cpp ${CMAKE_CURRENT_SOURCE_DIR}/commonconversion.cpp ${CMAKE_CURRENT_SOURCE_DIR}/kolabconversion.cpp ${CMAKE_CURRENT_SOURCE_DIR}/timezoneconverter.cpp PARENT_SCOPE) libkolab-1.0.2/conversion/commonconversion.cpp000066400000000000000000000137601262531616600215770ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include "commonconversion.h" #include "timezoneconverter.h" #include #include #include #include #include #include namespace Kolab { namespace Conversion { KDateTime::Spec getTimeSpec(bool isUtc, const std::string& timezone) { if (isUtc) { //UTC return KDateTime::Spec(KDateTime::UTC); } if (timezone.empty()) { //Floating return KDateTime::Spec(KDateTime::ClockTime); } //Convert non-olson timezones if necessary const QString normalizedTz = TimezoneConverter::normalizeTimezone(QString::fromStdString(timezone)); if (!QTimeZone::isTimeZoneIdAvailable(normalizedTz.toLatin1())) { Warning() << "invalid timezone: " << QString::fromStdString(timezone) << ", assuming floating time"; return KDateTime::Spec(KDateTime::ClockTime); } //FIXME convert this to a proper KTimeZone return KDateTime::Spec(KSystemTimeZones::zone(normalizedTz)); } KDateTime toDate(const Kolab::cDateTime &dt) { KDateTime date; if (!dt.isValid()) { //We rely on this codepath, so it's not an error // qDebug() << "invalid datetime converted"; return KDateTime(); } if (dt.isDateOnly()) { //Date only date.setDateOnly(true); date.setDate(QDate(dt.year(), dt.month(), dt.day())); date.setTimeSpec(KDateTime::Spec(KDateTime::ClockTime)); } else { date.setDate(QDate(dt.year(), dt.month(), dt.day())); date.setTime(QTime(dt.hour(), dt.minute(), dt.second())); date.setTimeSpec(getTimeSpec(dt.isUTC(), dt.timezone())); } Q_ASSERT(date.timeSpec().isValid()); Q_ASSERT(date.isValid()); return date; } cDateTime fromDate(const KDateTime &dt) { if (!dt.isValid()) { // qDebug() << "invalid datetime converted"; return cDateTime(); } cDateTime date; if (dt.isDateOnly()) { //Date only const QDate &d = dt.date(); date.setDate(d.year(), d.month(), d.day()); } else { const QDate &d = dt.date(); date.setDate(d.year(), d.month(), d.day()); const QTime &t = dt.time(); date.setTime(t.hour(), t.minute(), t.second()); if (dt.timeType() == KDateTime::UTC) { //UTC date.setUTC(true); } else if (dt.timeType() == KDateTime::OffsetFromUTC) { const KDateTime utcDate = dt.toUtc(); const QDate &d = utcDate.date(); date.setDate(d.year(), d.month(), d.day()); const QTime &t = utcDate.time(); date.setTime(t.hour(), t.minute(), t.second()); date.setUTC(true); } else if (dt.timeType() == KDateTime::TimeZone) { //Timezone //TODO handle local timezone? //Convert non-olson timezones if necessary const QString timezone = TimezoneConverter::normalizeTimezone(dt.timeZone().name()); if (!timezone.isEmpty()) { date.setTimezone(toStdString(timezone)); } else { Warning() << "invalid timezone: " << dt.timeZone().name() << ", assuming floating time"; return date; } } else if (dt.timeType() != KDateTime::ClockTime) { Error() << "invalid timespec, assuming floating time. Type: " << dt.timeType() << "dt: " << dt.toString(); return date; } } Q_ASSERT(date.isValid()); return date; } QStringList toStringList(const std::vector &l) { QStringList list; foreach(const std::string &s, l) { list.append(Conversion::fromStdString(s)); } return list; } std::vector fromStringList(const QStringList &l) { std::vector list; foreach(const QString &s, l) { list.push_back(toStdString(s)); } return list; } QUrl toMailto(const std::string &email, const std::string &name) { std::string mailto; if (!name.empty()) { mailto.append(name); } mailto.append("<"); mailto.append(email); mailto.append(">"); return QUrl(QString::fromStdString(std::string("mailto:")+mailto)); } std::string fromMailto(const QUrl &mailtoUri, std::string &name) { const QPair pair = fromMailto(toStdString(mailtoUri.toString())); name = pair.second; return pair.first; } QPair fromMailto(const std::string &mailto) { const std::string &decoded = toStdString(QUrl::fromPercentEncoding(QByteArray(mailto.c_str()))); if (decoded.substr(0, 7).compare("mailto:")) { // WARNING("no mailto address"); // std::cout << decoded << std::endl; return qMakePair(decoded, std::string()); } std::size_t begin = decoded.find('<',7); if (begin == std::string::npos) { WARNING("no mailto address"); std::cout << decoded << std::endl; return qMakePair(decoded, std::string()); } std::size_t end = decoded.find('>', begin); if (end == std::string::npos) { WARNING("no mailto address"); std::cout << decoded << std::endl; return qMakePair(decoded, std::string()); } const std::string name = decoded.substr(7, begin-7); const std::string email = decoded.substr(begin+1, end-begin-1); return qMakePair(email, name); } } } libkolab-1.0.2/conversion/commonconversion.h000066400000000000000000000035751262531616600212470ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef KOLABCOMMONCONVERSION_H #define KOLABCOMMONCONVERSION_H #include "kolab_export.h" #include #include #include namespace Kolab { namespace Conversion { KOLAB_EXPORT KDateTime toDate(const Kolab::cDateTime &dt); KOLAB_EXPORT cDateTime fromDate(const KDateTime &dt); QStringList toStringList(const std::vector &l); std::vector fromStringList(const QStringList &l); /** * Returns a UTC, Floating Time or Timezone */ KDateTime::Spec getTimeSpec(bool isUtc, const std::string &timezone); QUrl toMailto(const std::string &email, const std::string &name = std::string()); std::string fromMailto(const QUrl &mailtoUri, std::string &name); QPair fromMailto(const std::string &mailto); inline std::string toStdString(const QString &s) { return std::string(s.toUtf8().constData()); } inline QString fromStdString(const std::string &s) { return QString::fromUtf8(s.c_str()); } }; }; #endif libkolab-1.0.2/conversion/kabcconversion.cpp000066400000000000000000000775451262531616600212220ustar00rootroot00000000000000/* * Copyright (C) 2011 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include "kabcconversion.h" #include "commonconversion.h" #include #include #include "kolabformat/errorhandler.h" namespace Kolab { namespace Conversion { //The following was copied from kdepim/libkleo/kleo/enum.h,.cpp enum CryptoMessageFormat { InlineOpenPGPFormat = 1, OpenPGPMIMEFormat = 2, SMIMEFormat = 4, SMIMEOpaqueFormat = 8, AnyOpenPGP = InlineOpenPGPFormat|OpenPGPMIMEFormat, AnySMIME = SMIMEOpaqueFormat|SMIMEFormat, AutoFormat = AnyOpenPGP|AnySMIME }; enum EncryptionPreference { UnknownPreference = 0, NeverEncrypt = 1, AlwaysEncrypt = 2, AlwaysEncryptIfPossible = 3, AlwaysAskForEncryption = 4, AskWheneverPossible = 5, MaxEncryptionPreference = AskWheneverPossible }; enum SigningPreference { UnknownSigningPreference = 0, NeverSign = 1, AlwaysSign = 2, AlwaysSignIfPossible = 3, AlwaysAskForSigning = 4, AskSigningWheneverPossible = 5, MaxSigningPreference = AskSigningWheneverPossible }; static const struct { CryptoMessageFormat format; const char * displayName; const char * configName; } cryptoMessageFormats[] = { { InlineOpenPGPFormat, ("Inline OpenPGP (deprecated)"), "inline openpgp" }, { OpenPGPMIMEFormat, ("OpenPGP/MIME"), "openpgp/mime" }, { SMIMEFormat, ("S/MIME"), "s/mime" }, { SMIMEOpaqueFormat, ("S/MIME Opaque"), "s/mime opaque" }, }; static const unsigned int numCryptoMessageFormats = sizeof cryptoMessageFormats / sizeof *cryptoMessageFormats ; const char * cryptoMessageFormatToString( CryptoMessageFormat f ) { if ( f == AutoFormat ) return "auto"; for ( unsigned int i = 0 ; i < numCryptoMessageFormats ; ++i ) if ( f == cryptoMessageFormats[i].format ) return cryptoMessageFormats[i].configName; return 0; } QStringList cryptoMessageFormatsToStringList( unsigned int f ) { QStringList result; for ( unsigned int i = 0 ; i < numCryptoMessageFormats ; ++i ) if ( f & cryptoMessageFormats[i].format ) result.push_back( cryptoMessageFormats[i].configName ); return result; } CryptoMessageFormat stringToCryptoMessageFormat( const QString & s ) { const QString t = s.toLower(); for ( unsigned int i = 0 ; i < numCryptoMessageFormats ; ++i ) if ( t == cryptoMessageFormats[i].configName ) return cryptoMessageFormats[i].format; return AutoFormat; } unsigned int stringListToCryptoMessageFormats( const QStringList & sl ) { unsigned int result = 0; for ( QStringList::const_iterator it = sl.begin() ; it != sl.end() ; ++it ) result |= stringToCryptoMessageFormat( *it ); return result; } // For the config values used below, see also kaddressbook/editors/cryptowidget.cpp const char* encryptionPreferenceToString( EncryptionPreference pref ) { switch( pref ) { case UnknownPreference: return 0; case NeverEncrypt: return "never"; case AlwaysEncrypt: return "always"; case AlwaysEncryptIfPossible: return "alwaysIfPossible"; case AlwaysAskForEncryption: return "askAlways"; case AskWheneverPossible: return "askWhenPossible"; } return 0; // keep the compiler happy } EncryptionPreference stringToEncryptionPreference( const QString& str ) { if ( str == "never" ) return NeverEncrypt; if ( str == "always" ) return AlwaysEncrypt; if ( str == "alwaysIfPossible" ) return AlwaysEncryptIfPossible; if ( str == "askAlways" ) return AlwaysAskForEncryption; if ( str == "askWhenPossible" ) return AskWheneverPossible; return UnknownPreference; } const char* signingPreferenceToString( SigningPreference pref ) { switch( pref ) { case UnknownSigningPreference: return 0; case NeverSign: return "never"; case AlwaysSign: return "always"; case AlwaysSignIfPossible: return "alwaysIfPossible"; case AlwaysAskForSigning: return "askAlways"; case AskSigningWheneverPossible: return "askWhenPossible"; } return 0; // keep the compiler happy } SigningPreference stringToSigningPreference( const QString& str ) { if ( str == "never" ) return NeverSign; if ( str == "always" ) return AlwaysSign; if ( str == "alwaysIfPossible" ) return AlwaysSignIfPossible; if ( str == "askAlways" ) return AlwaysAskForSigning; if ( str == "askWhenPossible" ) return AskSigningWheneverPossible; return UnknownSigningPreference; } int fromAddressType(int kabcType, bool &pref) { int type = 0; if (kabcType & KContacts::Address::Dom) { Warning() << "domestic address is not supported"; } if (kabcType & KContacts::Address::Intl) { Warning() << "international address is not supported"; } if (kabcType & KContacts::Address::Pref) { pref = true; } if (kabcType & KContacts::Address::Postal) { Warning() << "postal address is not supported"; } if (kabcType & KContacts::Address::Parcel) { Warning() << "parcel is not supported"; } if (kabcType & KContacts::Address::Home) { type |= Kolab::Address::Home; } if (kabcType & KContacts::Address::Work) { type |= Kolab::Address::Work; } return type; } KContacts::Address::Type toAddressType(int types, bool pref) { KContacts::Address::Type type = 0; if (pref) { type |= KContacts::Address::Pref; } if (types & Kolab::Address::Home) { type |= KContacts::Address::Home; } if (types & Kolab::Address::Work) { type |= KContacts::Address::Work; } return type; } int fromPhoneType(int kabcType, bool &pref) { int type = 0; if (kabcType & KContacts::PhoneNumber::Home) { type |= Kolab::Telephone::Home; } if (kabcType & KContacts::PhoneNumber::Work) { type |= Kolab::Telephone::Work; } if (kabcType & KContacts::PhoneNumber::Msg) { type |= Kolab::Telephone::Text; } if (kabcType & KContacts::PhoneNumber::Pref) { pref = true; } if (kabcType & KContacts::PhoneNumber::Voice) { type |= Kolab::Telephone::Voice; } if (kabcType & KContacts::PhoneNumber::Fax) { type |= Kolab::Telephone::Fax; } if (kabcType & KContacts::PhoneNumber::Cell) { type |= Kolab::Telephone::Cell; } if (kabcType & KContacts::PhoneNumber::Video) { type |= Kolab::Telephone::Video; } if (kabcType & KContacts::PhoneNumber::Bbs) { Warning() << "mailbox number is not supported"; } if (kabcType & KContacts::PhoneNumber::Modem) { Warning() << "modem is not supported"; } if (kabcType & KContacts::PhoneNumber::Car) { type |= Kolab::Telephone::Car; } if (kabcType & KContacts::PhoneNumber::Isdn) { Warning() << "isdn number is not supported"; } if (kabcType & KContacts::PhoneNumber::Pcs) { type |= Kolab::Telephone::Text; } if (kabcType & KContacts::PhoneNumber::Pager) { type |= Kolab::Telephone::Pager; } return type; } KContacts::PhoneNumber::Type toPhoneType(int types, bool pref) { KContacts::PhoneNumber::Type type = 0; if (types & Kolab::Telephone::Home) { type |= KContacts::PhoneNumber::Home; } if (types & Kolab::Telephone::Work) { type |= KContacts::PhoneNumber::Work; } if (types & Kolab::Telephone::Text) { type |= KContacts::PhoneNumber::Msg; } if (pref) { type |= KContacts::PhoneNumber::Pref; } if (types & Kolab::Telephone::Voice) { type |= KContacts::PhoneNumber::Voice; } if (types & Kolab::Telephone::Fax) { type |= KContacts::PhoneNumber::Fax; } if (types & Kolab::Telephone::Cell) { type |= KContacts::PhoneNumber::Cell; } if (types & Kolab::Telephone::Video) { type |= KContacts::PhoneNumber::Video; } if (types & Kolab::Telephone::Car) { type |= KContacts::PhoneNumber::Car; } if (types & Kolab::Telephone::Text) { type |= KContacts::PhoneNumber::Pcs; } if (types & Kolab::Telephone::Pager) { type |= KContacts::PhoneNumber::Pager; } return type; } std::string fromPicture(const KContacts::Picture &pic, std::string &mimetype) { QByteArray input; QBuffer buffer( &input ); buffer.open( QIODevice::WriteOnly ); QImage img; if ( pic.isIntern() ) { if ( !pic.data().isNull() ) { img = pic.data(); } } else if ( !pic.url().isEmpty() ) { QString tmpFile; qWarning() << "external pictures are currently not supported"; //FIXME add kio support to libcalendaring or use libcurl // if ( KIO::NetAccess::download( pic.url(), tmpFile, 0 /*no widget known*/ ) ) { // img.load( tmpFile ); // KIO::NetAccess::removeTempFile( tmpFile ); // } } if (img.isNull()) { Error() << "invalid picture"; return std::string(); } if ( !img.hasAlphaChannel() ) { if (!img.save( &buffer, "JPEG" )) { Error() << "error on jpeg save"; return std::string(); } mimetype = "image/jpeg"; } else { if (!img.save( &buffer, "PNG" )) { Error() << "error on png save"; return std::string(); } mimetype = "image/png"; } return std::string(input.data(), input.size()); } KContacts::Picture toPicture(const std::string &data, const std::string &mimetype) { QImage img; bool ret = false; QByteArray type(mimetype.data(), mimetype.size()); type = type.split('/').last(); // extract "jpeg" from "image/jpeg" if (QImageReader::supportedImageFormats().contains(type)) { ret = img.loadFromData(QByteArray::fromRawData(data.data(), data.size()), type.constData()); } else { ret = img.loadFromData(QByteArray::fromRawData(data.data(), data.size())); } if (!ret) { Warning() << "failed to load picture"; return KContacts::Picture(); } KContacts::Picture logo(img); if (logo.isEmpty()) { Warning() << "failed to read picture"; return KContacts::Picture(); } return logo; } template void setCustom(const std::string &value, const std::string &id, T &object) { std::vector properties = object.customProperties(); properties.push_back(CustomProperty(id, value)); object.setCustomProperties(properties); } template std::string getCustom(const std::string &id, T &object) { const std::vector &properties = object.customProperties(); foreach(const Kolab::CustomProperty &prop, properties) { if (prop.identifier == id) { return prop.value; } } return std::string(); } static QString emailTypesToStringList(int emailTypes) { QStringList types; if (emailTypes & Kolab::Email::Home) { types << "home"; } if (emailTypes & Kolab::Email::Work) { types << "work"; } return types.join(","); } static int emailTypesFromStringlist(const QString &types) { int emailTypes = Kolab::Email::NoType; if (types.contains("home")) { emailTypes |= Kolab::Email::Home; } if (types.contains("work")) { emailTypes |= Kolab::Email::Work; } return emailTypes; } KContacts::Addressee toKABC(const Kolab::Contact &contact) { KContacts::Addressee addressee; addressee.setUid(fromStdString(contact.uid())); addressee.setCategories(toStringList(contact.categories())); //addressee.setName(fromStdString(contact.name()));//This one is only for compatiblity (and results in a non-existing name property) addressee.setFormattedName(fromStdString(contact.name())); //This on corresponds to fn const Kolab::NameComponents &nc = contact.nameComponents(); if (!nc.surnames().empty()) { addressee.setFamilyName(fromStdString(nc.surnames().front())); } if (!nc.given().empty()) { addressee.setGivenName(fromStdString(nc.given().front())); } if (!nc.additional().empty()) { addressee.setAdditionalName(fromStdString(nc.additional().front())); } if (!nc.prefixes().empty()) { addressee.setPrefix(fromStdString(nc.prefixes().front())); } if (!nc.suffixes().empty()) { addressee.setSuffix(fromStdString(nc.suffixes().front())); } addressee.setNote(fromStdString(contact.note())); addressee.setSecrecy(KContacts::Secrecy::Public); //We don't have any privacy setting in xCard QString preferredEmail; if (!contact.emailAddresses().empty()) { QStringList emails; foreach( const Kolab::Email &email, contact.emailAddresses()) { emails << fromStdString(email.address()); const QString types = emailTypesToStringList(email.types()); if (!types.isEmpty()) { addressee.insertCustom(QLatin1String("KOLAB"), QString::fromLatin1("EmailTypes%1").arg(fromStdString(email.address())), types); } } addressee.setEmails(emails); if ((contact.emailAddressPreferredIndex() >= 0) && (contact.emailAddressPreferredIndex() < static_cast(contact.emailAddresses().size()))) { preferredEmail = fromStdString(contact.emailAddresses().at(contact.emailAddressPreferredIndex()).address()); } else { preferredEmail = fromStdString(contact.emailAddresses().at(0).address()); } addressee.insertEmail(preferredEmail, true); } if (!contact.freeBusyUrl().empty()) { if (preferredEmail.isEmpty()) { Error() << "f/b url is set but no email address available, skipping"; } else { addressee.insertCustom("KOLAB", "FreebusyUrl", fromStdString(contact.freeBusyUrl())); } } if (!contact.nickNames().empty()) { addressee.setNickName(fromStdString(contact.nickNames().at(0))); //TODO support multiple } if (contact.bDay().isValid()) { addressee.setBirthday(toDate(contact.bDay()).dateTime()); } if (!contact.titles().empty()) { addressee.setTitle(fromStdString(contact.titles().at(0))); //TODO support multiple } if (!contact.urls().empty()) { KContacts::ResourceLocatorUrl url; url.setUrl(QUrl(fromStdString(contact.urls().at(0).url()))); //TODO support multiple addressee.setUrl(url); foreach(const Kolab::Url &u, contact.urls()) { if (u.type() == Kolab::Url::Blog) { addressee.insertCustom("KADDRESSBOOK", "BlogFeed", fromStdString(u.url())); } } } if (!contact.affiliations().empty()) { //Storing only a const reference leads to segfaults. No idea why. const Kolab::Affiliation aff = contact.affiliations().at(0); //TODO support multiple if (!aff.organisation().empty()) { addressee.setOrganization(fromStdString(aff.organisation())); } if (!aff.organisationalUnits().empty()) { addressee.setDepartment(fromStdString(aff.organisationalUnits().at(0))); //TODO support multiple } if (!aff.roles().empty()) { addressee.setRole(fromStdString(aff.roles().at(0))); //TODO support multiple } if (!aff.logo().empty()) { addressee.setLogo(toPicture(aff.logo(), aff.logoMimetype())); } foreach(const Kolab::Related &related, aff.relateds()) { if (related.type() != Kolab::Related::Text) { Error() << "invalid relation type"; continue; } if (related.relationTypes() & Kolab::Related::Assistant) { addressee.insertCustom(QLatin1String("KADDRESSBOOK"), QLatin1String("X-AssistantsName"), fromStdString(related.text())); } if (related.relationTypes() & Kolab::Related::Manager) { addressee.insertCustom(QLatin1String("KADDRESSBOOK"), QLatin1String("X-ManagersName"), fromStdString(related.text())); } } foreach(const Kolab::Address &address, aff.addresses()) { addressee.insertCustom(QLatin1String("KADDRESSBOOK"), QLatin1String("X-Office"), fromStdString(address.label())); //TODO support proper addresses } } const std::string &prof = getCustom("X-Profession", contact); if (!prof.empty()) { addressee.insertCustom(QLatin1String("KADDRESSBOOK"), QLatin1String("X-Profession"), fromStdString(prof)); } const std::string &adrBook = getCustom("X-AddressBook", contact); if (!adrBook.empty()) { addressee.insertCustom(QLatin1String("KADDRESSBOOK"), QLatin1String("X-AddressBook"), fromStdString(prof)); } if (!contact.photo().empty()) { addressee.setPhoto(toPicture(contact.photo(), contact.photoMimetype())); } if (!contact.telephones().empty()) { int index = 0; foreach(const Kolab::Telephone &tel, contact.telephones()) { bool pref = false; if (index == contact.telephonesPreferredIndex()) { pref = true; } KContacts::PhoneNumber number(fromStdString(tel.number()), toPhoneType(tel.types(), pref)); index++; addressee.insertPhoneNumber(number); } } if (!contact.addresses().empty()) { int index = 0; foreach(const Kolab::Address &a, contact.addresses()) { bool pref = false; if (index == contact.addressPreferredIndex()) { pref = true; } KContacts::Address adr(toAddressType(a.types(), pref)); adr.setLabel(fromStdString(a.label())); adr.setStreet(fromStdString(a.street())); adr.setLocality(fromStdString(a.locality())); adr.setRegion(fromStdString(a.region())); adr.setPostalCode(fromStdString(a.code())); adr.setCountry(fromStdString(a.country())); index++; addressee.insertAddress(adr); } } if (contact.anniversary().isValid()) { addressee.insertCustom(QLatin1String("KADDRESSBOOK"), QLatin1String("X-Anniversary"), toDate(contact.anniversary()).toString(KDateTime::ISODate)); } if (!contact.imAddresses().empty()) { addressee.insertCustom(QLatin1String("KADDRESSBOOK"), QLatin1String("X-IMAddress"),fromStdString(contact.imAddresses()[0])); //TODO support multiple } if (!contact.relateds().empty()) { foreach(const Kolab::Related &rel, contact.relateds()) { if (rel.type() != Kolab::Related::Text) { Error() << "relation type not supported"; continue; } if (rel.relationTypes() & Kolab::Related::Spouse) { addressee.insertCustom(QLatin1String("KADDRESSBOOK"), QLatin1String("X-SpousesName"),fromStdString(rel.text())); //TODO support multiple } else { Warning() << "relation not supported"; continue; } } } return addressee; } Kolab::Contact fromKABC(const KContacts::Addressee &addressee) { int prefNum = -1; int prefCounter = -1; Kolab::Contact c; c.setUid(toStdString(addressee.uid())); c.setCategories(fromStringList(addressee.categories())); c.setName(toStdString(addressee.formattedName())); Kolab::NameComponents nc; nc.setSurnames(std::vector() << toStdString(addressee.familyName())); nc.setGiven(std::vector() << toStdString(addressee.givenName())); nc.setAdditional(std::vector() << toStdString(addressee.additionalName())); nc.setPrefixes(std::vector() << toStdString(addressee.prefix())); nc.setSuffixes(std::vector() << toStdString(addressee.suffix())); c.setNameComponents(nc); c.setNote(toStdString(addressee.note())); c.setFreeBusyUrl(toStdString(addressee.custom("KOLAB", QString("FreebusyUrl")))); if (!addressee.title().isEmpty()) { c.setTitles(std::vector() << toStdString(addressee.title())); } Kolab::Affiliation businessAff; businessAff.setOrganisation(toStdString(addressee.organization())); if (!addressee.department().isEmpty()) { Debug() << addressee.department() << addressee.department().toLatin1() << addressee.department().toUtf8(); businessAff.setOrganisationalUnits(std::vector() << toStdString(addressee.department())); } if (!addressee.logo().isEmpty()) { std::string logoMimetype; const std::string &logo = fromPicture(addressee.logo(), logoMimetype); businessAff.setLogo(logo, logoMimetype); } if (!addressee.role().isEmpty()) { businessAff.setRoles(std::vector() << toStdString(addressee.role())); } const QString &office = addressee.custom(QLatin1String("KADDRESSBOOK"), QLatin1String("X-Office")); if (!office.isEmpty()) { Kolab::Address a; a.setTypes(Kolab::Address::Work); a.setLabel(toStdString(addressee.custom(QLatin1String("KADDRESSBOOK"), QLatin1String("X-Office")))); businessAff.setAddresses(std::vector() << a); } std::vector relateds; const QString &manager = addressee.custom(QLatin1String("KADDRESSBOOK"), QLatin1String("X-ManagersName")); if (!manager.isEmpty()) { relateds.push_back(Kolab::Related(Kolab::Related::Text, toStdString(manager), Kolab::Related::Manager)); } const QString &assistant = addressee.custom(QLatin1String("KADDRESSBOOK"), QLatin1String("X-AssistantsName")); if (!assistant.isEmpty()) { relateds.push_back(Kolab::Related(Kolab::Related::Text, toStdString(assistant), Kolab::Related::Assistant)); } if (!relateds.empty()) { businessAff.setRelateds(relateds); } if (!(businessAff == Kolab::Affiliation())) { c.setAffiliations(std::vector() << businessAff); } std::vector urls; if (!addressee.url().url().isEmpty()) { urls.push_back(Kolab::Url(toStdString(addressee.url().url().url()))); } const QString &blogUrl = addressee.custom(QLatin1String("KADDRESSBOOK"), QLatin1String("BlogFeed")); if (!blogUrl.isEmpty()) { urls.push_back(Kolab::Url(toStdString(blogUrl), Kolab::Url::Blog)); } c.setUrls(urls); std::vector addresses; prefNum = -1; prefCounter = -1; foreach(const KContacts::Address &a, addressee.addresses()) { Kolab::Address adr; bool pref = false; adr.setTypes(fromAddressType(a.type(), pref)); prefCounter++; if (pref) { prefNum = prefCounter; } adr.setLabel(toStdString(a.label())); adr.setStreet(toStdString(a.street())); adr.setLocality(toStdString(a.locality())); adr.setRegion(toStdString(a.region())); adr.setCode(toStdString(a.postalCode())); adr.setCountry(toStdString(a.country())); addresses.push_back(adr); } c.setAddresses(addresses, prefNum); if (!addressee.nickName().isEmpty()) { c.setNickNames(std::vector() << toStdString(addressee.nickName())); } const QString &spouse = addressee.custom(QLatin1String("KADDRESSBOOK"), QLatin1String("X-SpousesName")); if (!spouse.isEmpty()) { c.setRelateds(std::vector() << Kolab::Related(Kolab::Related::Text, toStdString(spouse), Kolab::Related::Spouse)); } c.setBDay(fromDate(KDateTime(addressee.birthday(), KDateTime::ClockTime))); c.setAnniversary(fromDate(KDateTime(QDate::fromString( addressee.custom(QLatin1String("KADDRESSBOOK"), QLatin1String("X-Anniversary")), Qt::ISODate ), KDateTime::Spec(KDateTime::ClockTime)))); if (!addressee.photo().isEmpty()) { std::string mimetype; const std::string &photo = fromPicture(addressee.photo(), mimetype); c.setPhoto(photo, mimetype); } //TODO // c.setGender(); // c.setLanguages(); std::vector phones; prefNum = -1; prefCounter = -1; foreach (const KContacts::PhoneNumber &n, addressee.phoneNumbers()) { Kolab::Telephone p; p.setNumber(toStdString(n.number())); bool pref = false; p.setTypes(fromPhoneType(n.type(), pref)); prefCounter++; if (pref) { prefNum = prefCounter; } phones.push_back(p); } c.setTelephones(phones, prefNum); const QString &imAddress = addressee.custom(QLatin1String("KADDRESSBOOK"), QLatin1String("X-IMAddress")); if (!imAddress.isEmpty()) { c.setIMaddresses(std::vector() << toStdString(imAddress), 0); } int prefEmail = -1; int count = 0; std::vector emails; foreach(const QString &e, addressee.emails()) { if ((prefEmail == -1) && (e == addressee.preferredEmail())) { prefEmail = count; } count++; emails.push_back(Kolab::Email(toStdString(e), emailTypesFromStringlist(addressee.custom(QLatin1String("KOLAB"), QString::fromLatin1("EmailTypes%1").arg(e))))); } c.setEmailAddresses(emails, prefEmail); if (addressee.geo().isValid()) { c.setGPSpos(std::vector() << Kolab::Geo(addressee.geo().latitude(), addressee.geo().longitude())); } Kolab::Crypto crypto; const QStringList protocolPrefs = addressee.custom( "KADDRESSBOOK", "CRYPTOPROTOPREF" ).split( ',', QString::SkipEmptyParts ); const uint cryptoFormats = stringListToCryptoMessageFormats( protocolPrefs ); int formats = 0; if (cryptoFormats & InlineOpenPGPFormat) { formats |= Kolab::Crypto::PGPinline; } if (cryptoFormats & OpenPGPMIMEFormat) { formats |= Kolab::Crypto::PGPmime; } if (cryptoFormats & SMIMEFormat) { formats |= Kolab::Crypto::SMIME; } if (cryptoFormats & SMIMEOpaqueFormat) { formats |= Kolab::Crypto::SMIMEopaque; } crypto.setAllowed(formats); Kolab::Crypto::CryptoPref signPref = Kolab::Crypto::Ask; switch (stringToSigningPreference(addressee.custom( "KADDRESSBOOK", "CRYPTOSIGNPREF" ) )) { case NeverSign: signPref = Kolab::Crypto::Never; break; case AlwaysSign: signPref = Kolab::Crypto::Always; break; case AlwaysSignIfPossible: signPref = Kolab::Crypto::IfPossible; break; case AlwaysAskForSigning: case AskSigningWheneverPossible: signPref = Kolab::Crypto::Ask; break; default: signPref = Kolab::Crypto::Ask; } crypto.setSignPref(signPref); Kolab::Crypto::CryptoPref encryptPref = Kolab::Crypto::Ask; switch (stringToSigningPreference(addressee.custom( "KADDRESSBOOK", "CRYPTOENCRYPTPREF" ) )) { case NeverEncrypt: encryptPref = Kolab::Crypto::Never; break; case AlwaysEncrypt: encryptPref = Kolab::Crypto::Always; break; case AlwaysEncryptIfPossible: encryptPref = Kolab::Crypto::IfPossible; break; case AlwaysAskForEncryption: case AskWheneverPossible: encryptPref = Kolab::Crypto::Ask; break; default: encryptPref = Kolab::Crypto::Ask; } crypto.setEncryptPref(encryptPref); c.setCrypto(crypto); //FIXME the keys are most certainly worng, look at cryptopageplugin.cpp std::vector keys; const std::string &pgpkey = toStdString(addressee.custom( "KADDRESSBOOK", "OPENPGPFP" )); if (!pgpkey.empty()) { keys.push_back(Kolab::Key(pgpkey, Kolab::Key::PGP)); } const std::string &smimekey = toStdString(addressee.custom( "KADDRESSBOOK", "SMIMEFP" )); if (!smimekey.empty()) { keys.push_back(Kolab::Key(smimekey, Kolab::Key::PKCS7_MIME)); } c.setKeys(keys); if (!addressee.sound().isEmpty()) { Warning() << "sound is not supported"; } const std::string &profession = toStdString(addressee.custom( "KADDRESSBOOK", "X-Profession" )); if (!profession.empty()) { setCustom(profession, "X-Profession", c); } const std::string &adrBook = toStdString(addressee.custom( "KADDRESSBOOK", "X-AddressBook" )); if (!adrBook.empty()) { setCustom(adrBook, "X-AddressBook", c); } //TODO preserve all custom properties (also such which are unknown to us) return c; } DistList fromKABC(const KContacts::ContactGroup &cg) { DistList dl; dl.setName(toStdString(cg.name())); dl.setUid(toStdString(cg.id())); std::vector members; for (unsigned int i = 0; i < cg.dataCount(); i++) { const KContacts::ContactGroup::Data &data = cg.data(i); members.push_back(Kolab::ContactReference(Kolab::ContactReference::EmailReference, toStdString(data.email()), toStdString(data.name()))); } for (unsigned int i = 0; i < cg.contactReferenceCount(); i++) { const KContacts::ContactGroup::ContactReference &ref = cg.contactReference(i); members.push_back(Kolab::ContactReference(Kolab::ContactReference::UidReference, toStdString(ref.uid()))); } if (cg.contactGroupReferenceCount() > 0) { qWarning() << "Tried to save contact group references, which should have been resolved already"; } dl.setMembers(members); return dl; } KContacts::ContactGroup toKABC(const DistList &dl) { KContacts::ContactGroup cg(fromStdString(dl.name())); cg.setId(fromStdString(dl.uid())); foreach(const Kolab::ContactReference &m, dl.members()) { switch (m.type()) { case Kolab::ContactReference::EmailReference: cg.append(KContacts::ContactGroup::Data(fromStdString(m.name()), fromStdString(m.email()))); break; case Kolab::ContactReference::UidReference: cg.append(KContacts::ContactGroup::ContactReference(fromStdString(m.uid()))); break; default: Error() << "invalid contact reference"; } } return cg; } } //Namespace } //Namespace libkolab-1.0.2/conversion/kabcconversion.h000066400000000000000000000025651262531616600206550ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef KOLABKABCCONVERSION_H #define KOLABKABCCONVERSION_H #include "kolab_export.h" #include #include #include namespace Kolab { /** * Conversion of Kolab-Containers to/from KABC Containers. * */ namespace Conversion { KOLAB_EXPORT KContacts::Addressee toKABC(const Kolab::Contact &); KOLAB_EXPORT Kolab::Contact fromKABC(const KContacts::Addressee &); KOLAB_EXPORT KContacts::ContactGroup toKABC(const Kolab::DistList &); KOLAB_EXPORT Kolab::DistList fromKABC(const KContacts::ContactGroup &); }; }; #endif libkolab-1.0.2/conversion/kcalconversion.cpp000066400000000000000000000730211262531616600212150ustar00rootroot00000000000000/* * Copyright (C) 2011 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include "kcalconversion.h" #include #include #include #include #include #include #include #include "kolabformat/errorhandler.h" #include "commonconversion.h" namespace Kolab { namespace Conversion { //The uid of a contact which refers to the uuid of a contact in the addressbook #define CUSTOM_KOLAB_CONTACT_UUID "X_KOLAB_CONTACT_UUID" #define CUSTOM_KOLAB_CONTACT_CUTYPE "X_KOLAB_CONTACT_CUTYPE" #define CUSTOM_KOLAB_URL "X-KOLAB-URL" KCalCore::Duration toDuration(const Kolab::Duration &d) { int value = 0; if (d.hours() || d.minutes() || d.seconds()) { value = ((((d.weeks() * 7 + d.days()) * 24 + d.hours()) * 60 + d.minutes()) * 60 + d.seconds()); if (d.isNegative()) { value = -value; } return KCalCore::Duration(value); } value = d.weeks() * 7 + d.days(); if (d.isNegative()) { value = -value; } return KCalCore::Duration(value, KCalCore::Duration::Days); } Kolab::Duration fromDuration(const KCalCore::Duration &d) { int value = d.value(); bool isNegative = false; if (value < 0) { isNegative = true; value = -value; } //We don't know how the seconds/days were distributed before, so no point in distributing them (probably) if (d.isDaily()) { int days = value; return Kolab::Duration(days, 0, 0, 0, isNegative); } int seconds = value; // int minutes = seconds / 60; // seconds = seconds % 60; // int hours = minutes / 60; // minutes = minutes % 60; return Kolab::Duration(0, 0, 0, seconds, isNegative); } KCalCore::Incidence::Secrecy toSecrecy(Kolab::Classification c) { switch(c) { case Kolab::ClassPublic: return KCalCore::Incidence::SecrecyPublic; case Kolab::ClassPrivate: return KCalCore::Incidence::SecrecyPrivate; case Kolab::ClassConfidential: return KCalCore::Incidence::SecrecyConfidential; default: Error() << "unhandled"; Q_ASSERT(0); } return KCalCore::Incidence::SecrecyPublic; } Kolab::Classification fromSecrecy(KCalCore::Incidence::Secrecy c) { switch(c) { case KCalCore::Incidence::SecrecyPublic: return Kolab::ClassPublic; case KCalCore::Incidence::SecrecyPrivate: return Kolab::ClassPrivate; case KCalCore::Incidence::SecrecyConfidential: return Kolab::ClassConfidential; default: Error() << "unhandled"; Q_ASSERT(0); } return Kolab::ClassPublic; } int toPriority(int priority) { //Same mapping return priority; } int fromPriority(int priority) { //Same mapping return priority; } KCalCore::Incidence::Status toStatus(Kolab::Status s) { switch (s) { case StatusUndefined: return KCalCore::Incidence::StatusNone; case StatusNeedsAction: return KCalCore::Incidence::StatusNeedsAction; case StatusCompleted: return KCalCore::Incidence::StatusCompleted; case StatusInProcess: return KCalCore::Incidence::StatusInProcess; case StatusCancelled: return KCalCore::Incidence::StatusCanceled; case StatusTentative: return KCalCore::Incidence::StatusTentative; case StatusConfirmed: return KCalCore::Incidence::StatusConfirmed; case StatusDraft: return KCalCore::Incidence::StatusDraft; case StatusFinal: return KCalCore::Incidence::StatusFinal; default: Error() << "unhandled"; Q_ASSERT(0); } return KCalCore::Incidence::StatusNone; } Kolab::Status fromStatus(KCalCore::Incidence::Status s) { switch (s) { case KCalCore::Incidence::StatusNone: return StatusUndefined; case KCalCore::Incidence::StatusNeedsAction: return StatusNeedsAction; case KCalCore::Incidence::StatusCompleted: return StatusCompleted; case KCalCore::Incidence::StatusInProcess: return StatusInProcess; case KCalCore::Incidence::StatusCanceled: return StatusCancelled; case KCalCore::Incidence::StatusTentative: return StatusTentative; case KCalCore::Incidence::StatusConfirmed: return StatusConfirmed; case KCalCore::Incidence::StatusDraft: return StatusDraft; case KCalCore::Incidence::StatusFinal: return StatusFinal; default: Error() << "unhandled"; Q_ASSERT(0); } return StatusUndefined; } KCalCore::Attendee::PartStat toPartStat(Kolab::PartStatus p) { switch (p) { case PartNeedsAction: return KCalCore::Attendee::NeedsAction; case PartAccepted: return KCalCore::Attendee::Accepted; case PartDeclined: return KCalCore::Attendee::Declined; case PartTentative: return KCalCore::Attendee::Tentative; case PartDelegated: return KCalCore::Attendee::Delegated; default: Error() << "unhandled"; Q_ASSERT(0); } return KCalCore::Attendee::NeedsAction; } Kolab::PartStatus fromPartStat(KCalCore::Attendee::PartStat p) { switch (p) { case KCalCore::Attendee::NeedsAction: return PartNeedsAction; case KCalCore::Attendee::Accepted: return PartAccepted; case KCalCore::Attendee::Declined: return PartDeclined; case KCalCore::Attendee::Tentative: return PartTentative; case KCalCore::Attendee::Delegated: return PartDelegated; default: Error() << "unhandled"; Q_ASSERT(0); } return PartNeedsAction; } KCalCore::Attendee::Role toRole(Kolab::Role r) { switch (r) { case Required: return KCalCore::Attendee::ReqParticipant; case Chair: return KCalCore::Attendee::Chair; case Optional: return KCalCore::Attendee::OptParticipant; case NonParticipant: return KCalCore::Attendee::NonParticipant; default: Error() << "unhandled"; Q_ASSERT(0); } return KCalCore::Attendee::ReqParticipant; } Kolab::Role fromRole(KCalCore::Attendee::Role r) { switch (r) { case KCalCore::Attendee::ReqParticipant: return Required; case KCalCore::Attendee::Chair: return Chair; case KCalCore::Attendee::OptParticipant: return Optional; case KCalCore::Attendee::NonParticipant: return NonParticipant; default: Error() << "unhandled"; Q_ASSERT(0); } return Required; } template QString getCustomProperty(const QString &id, const T &e) { std::vector &props = e.customProperties(); foreach (const CustomProperty &p, props) { if (fromStdString(p.identifier) == id) { return fromStdString(p.value); } } } template void setIncidence(KCalCore::Incidence &i, const T &e) { if (!e.uid().empty()) { i.setUid(fromStdString(e.uid())); } i.setCreated(toDate(e.created())); i.setLastModified(toDate(e.lastModified())); i.setRevision(e.sequence()); i.setSecrecy(toSecrecy(e.classification())); i.setCategories(toStringList(e.categories())); if (e.start().isValid()) { i.setDtStart(toDate(e.start())); } i.setSummary(fromStdString(e.summary())); //TODO detect richtext i.setDescription(fromStdString(e.description())); //TODO detect richtext i.setStatus(toStatus(e.status())); foreach (const Kolab::Attendee a, e.attendees()) { /* * KCalCore always sets a UID if empty, but that's just a pointer, and not the uid of a real contact. * Since that means the semantics of the two are different, we have to store the kolab uid as a custom property. */ KCalCore::Attendee::Ptr attendee = KCalCore::Attendee::Ptr(new KCalCore::Attendee(fromStdString(a.contact().name()), fromStdString(a.contact().email()), a.rsvp(), toPartStat(a.partStat()), toRole(a.role()) )); if (!a.contact().uid().empty()) { //TODO Identify contact from addressbook based on uid attendee->customProperties().setNonKDECustomProperty(CUSTOM_KOLAB_CONTACT_UUID, fromStdString(a.contact().uid())); } if (!a.delegatedTo().empty()) { if (a.delegatedTo().size() > 1) { WARNING("multiple delegatees are not supported"); } attendee->setDelegate(toMailto(a.delegatedTo().front().email(), a.delegatedTo().front().name()).toString()); } if (!a.delegatedFrom().empty()) { if (a.delegatedFrom().size() > 1) { WARNING("multiple delegators are not supported"); } attendee->setDelegator(toMailto(a.delegatedFrom().front().email(), a.delegatedFrom().front().name()).toString()); } if (a.cutype() != CutypeIndividual) { attendee->customProperties().setNonKDECustomProperty(CUSTOM_KOLAB_CONTACT_CUTYPE, QString::number(a.cutype())); } i.addAttendee(attendee); } foreach (const Kolab::Attachment a, e.attachments()) { KCalCore::Attachment::Ptr ptr; if (!a.uri().empty()) { ptr = KCalCore::Attachment::Ptr(new KCalCore::Attachment(fromStdString(a.uri()), fromStdString(a.mimetype()))); } else { ptr = KCalCore::Attachment::Ptr(new KCalCore::Attachment(QByteArray::fromRawData(a.data().c_str(), a.data().size()).toBase64(), fromStdString(a.mimetype()))); } if (!a.label().empty()) { ptr->setLabel(fromStdString(a.label())); } i.addAttachment(ptr); } QMap props; foreach (const Kolab::CustomProperty &prop, e.customProperties()) { QString key; if (prop.identifier.compare(0, 5, "X-KDE")) { key.append(QString::fromLatin1("X-KOLAB-")); } key.append(fromStdString(prop.identifier)); props.insert(key.toLatin1(), fromStdString(prop.value)); // i.setCustomProperty("KOLAB", fromStdString(prop.identifier).toLatin1(), fromStdString(prop.value)); } i.setCustomProperties(props); } template void getIncidence(T &i, const I &e) { i.setUid(toStdString(e.uid())); i.setCreated(fromDate(e.created())); i.setLastModified(fromDate(e.lastModified())); i.setSequence(e.revision()); i.setClassification(fromSecrecy(e.secrecy())); i.setCategories(fromStringList(e.categories())); i.setStart(fromDate(e.dtStart())); i.setSummary(toStdString(e.summary())); i.setDescription(toStdString(e.description())); i.setStatus(fromStatus(e.status())); std::vector attendees; foreach (const KCalCore::Attendee::Ptr ptr, e.attendees()) { const QString &uid = ptr->customProperties().nonKDECustomProperty(CUSTOM_KOLAB_CONTACT_UUID); Kolab::Attendee a(Kolab::ContactReference(toStdString(ptr->email()), toStdString(ptr->name()), toStdString(uid))); a.setRSVP(ptr->RSVP()); a.setPartStat(fromPartStat(ptr->status())); a.setRole(fromRole(ptr->role())); if (!ptr->delegate().isEmpty()) { std::string name; const std::string &email = fromMailto(QUrl(ptr->delegate()), name); a.setDelegatedTo(std::vector() << Kolab::ContactReference(email, name)); } if (!ptr->delegator().isEmpty()) { std::string name; const std::string &email = fromMailto(QUrl(ptr->delegator()), name); a.setDelegatedFrom(std::vector() << Kolab::ContactReference(email, name)); } const QString &cutype = ptr->customProperties().nonKDECustomProperty(CUSTOM_KOLAB_CONTACT_CUTYPE); if (!cutype.isEmpty()) { a.setCutype(static_cast(cutype.toInt())); } attendees.push_back(a); } i.setAttendees(attendees); std::vector attachments; foreach (const KCalCore::Attachment::Ptr &ptr, e.attachments()) { Kolab::Attachment a; if (ptr->isUri()) { a.setUri(toStdString(ptr->uri()), toStdString(ptr->mimeType())); } else { a.setData(std::string(ptr->decodedData().data(), ptr->decodedData().size()), toStdString(ptr->mimeType())); } a.setLabel(toStdString(ptr->label())); attachments.push_back(a); } i.setAttachments(attachments); std::vector customProperties; const QMap &props = e.customProperties(); for (QMap::const_iterator it = props.begin(); it != props.end(); it++) { QString key(it.key()); if (key == QLatin1String(CUSTOM_KOLAB_URL)) { continue; } customProperties.push_back(Kolab::CustomProperty(toStdString(key.remove("X-KOLAB-")), toStdString(it.value()))); } i.setCustomProperties(customProperties); } int toWeekDay(Kolab::Weekday wday) { switch (wday) { case Kolab::Monday: return 1; case Kolab::Tuesday: return 2; case Kolab::Wednesday: return 3; case Kolab::Thursday: return 4; case Kolab::Friday: return 5; case Kolab::Saturday: return 6; case Kolab::Sunday: return 7; default: Error() << "unhandled"; Q_ASSERT(0); } return 1; } Kolab::Weekday fromWeekDay(int wday) { switch (wday) { case 1: return Kolab::Monday; case 2: return Kolab::Tuesday; case 3: return Kolab::Wednesday; case 4: return Kolab::Thursday; case 5: return Kolab::Friday; case 6: return Kolab::Saturday; case 7: return Kolab::Sunday; default: Error() << "unhandled"; Q_ASSERT(0); } return Kolab::Monday; } KCalCore::RecurrenceRule::PeriodType toRecurrenceType(Kolab::RecurrenceRule::Frequency freq) { switch(freq) { case Kolab::RecurrenceRule::FreqNone: Warning() << "no recurrence?"; break; case Kolab::RecurrenceRule::Yearly: return KCalCore::RecurrenceRule::rYearly; case Kolab::RecurrenceRule::Monthly: return KCalCore::RecurrenceRule::rMonthly; case Kolab::RecurrenceRule::Weekly: return KCalCore::RecurrenceRule::rWeekly; case Kolab::RecurrenceRule::Daily: return KCalCore::RecurrenceRule::rDaily; case Kolab::RecurrenceRule::Hourly: return KCalCore::RecurrenceRule::rHourly; case Kolab::RecurrenceRule::Minutely: return KCalCore::RecurrenceRule::rMinutely; case Kolab::RecurrenceRule::Secondly: return KCalCore::RecurrenceRule::rSecondly; default: Error() << "unhandled"; Q_ASSERT(0); } return KCalCore::RecurrenceRule::rNone; } Kolab::RecurrenceRule::Frequency fromRecurrenceType(KCalCore::RecurrenceRule::PeriodType freq) { switch(freq) { case KCalCore::RecurrenceRule::rNone: Warning() << "no recurrence?"; break; case KCalCore::RecurrenceRule::rYearly: return Kolab::RecurrenceRule::Yearly; case KCalCore::RecurrenceRule::rMonthly: return Kolab::RecurrenceRule::Monthly; case KCalCore::RecurrenceRule::rWeekly: return Kolab::RecurrenceRule::Weekly; case KCalCore::RecurrenceRule::rDaily: return Kolab::RecurrenceRule::Daily; case KCalCore::RecurrenceRule::rHourly: return Kolab::RecurrenceRule::Hourly; case KCalCore::RecurrenceRule::rMinutely: return Kolab::RecurrenceRule::Minutely; case KCalCore::RecurrenceRule::rSecondly: return Kolab::RecurrenceRule::Secondly; default: Error() << "unhandled"; Q_ASSERT(0); } return Kolab::RecurrenceRule::FreqNone; } KCalCore::RecurrenceRule::WDayPos toWeekDayPos(const Kolab::DayPos &dp) { return KCalCore::RecurrenceRule::WDayPos(dp.occurence(), toWeekDay(dp.weekday())); } Kolab::DayPos fromWeekDayPos(const KCalCore::RecurrenceRule::WDayPos &dp) { return Kolab::DayPos(dp.pos(), fromWeekDay(dp.day())); } template void setRecurrence(KCalCore::Incidence &e, const T &event) { const Kolab::RecurrenceRule &rrule = event.recurrenceRule(); if (rrule.isValid()) { KCalCore::Recurrence *rec = e.recurrence(); KCalCore::RecurrenceRule *defaultRR = rec->defaultRRule(true); Q_ASSERT(defaultRR); defaultRR->setWeekStart(toWeekDay(rrule.weekStart())); defaultRR->setRecurrenceType(toRecurrenceType(rrule.frequency())); defaultRR->setFrequency(rrule.interval()); if (rrule.end().isValid()) { rec->setEndDateTime(toDate(rrule.end())); //TODO date/datetime setEndDate(). With date-only the start date has to be taken into account. } else { rec->setDuration(rrule.count()); } if (!rrule.bysecond().empty()) { defaultRR->setBySeconds(QVector::fromStdVector(rrule.bysecond()).toList()); } if (!rrule.byminute().empty()) { defaultRR->setByMinutes(QVector::fromStdVector(rrule.byminute()).toList()); } if (!rrule.byhour().empty()) { defaultRR->setByHours(QVector::fromStdVector(rrule.byhour()).toList()); } if (!rrule.byday().empty()) { QList daypos; foreach(const Kolab::DayPos &dp, rrule.byday()) { daypos.append(toWeekDayPos(dp)); } defaultRR->setByDays(daypos); } if (!rrule.bymonthday().empty()) { defaultRR->setByMonthDays(QVector::fromStdVector(rrule.bymonthday()).toList()); } if (!rrule.byyearday().empty()) { defaultRR->setByYearDays(QVector::fromStdVector(rrule.byyearday()).toList()); } if (!rrule.byweekno().empty()) { defaultRR->setByWeekNumbers(QVector::fromStdVector(rrule.byweekno()).toList()); } if (!rrule.bymonth().empty()) { defaultRR->setByMonths(QVector::fromStdVector(rrule.bymonth()).toList()); } } foreach (const Kolab::cDateTime &dt, event.recurrenceDates()) { const KDateTime &date = toDate(dt); if (date.isDateOnly()) { e.recurrence()->addRDate(date.date()); } else { e.recurrence()->addRDateTime(date); } } foreach (const Kolab::cDateTime &dt, event.exceptionDates()) { const KDateTime &date = toDate(dt); if (date.isDateOnly()) { e.recurrence()->addExDate(date.date()); } else { e.recurrence()->addExDateTime(date); } } } template void getRecurrence(T &i, const I &e) { if (!e.recurs()) { return; } KCalCore::Recurrence *rec = e.recurrence(); KCalCore::RecurrenceRule *defaultRR = rec->defaultRRule(false); if (!defaultRR) { Warning() << "no recurrence"; return; } Q_ASSERT(defaultRR); Kolab::RecurrenceRule rrule; rrule.setWeekStart(fromWeekDay(defaultRR->weekStart())); rrule.setFrequency(fromRecurrenceType(defaultRR->recurrenceType())); rrule.setInterval(defaultRR->frequency()); if (defaultRR->duration() != 0) { //Inidcates if end date is set or not if (defaultRR->duration() > 0) { rrule.setCount(defaultRR->duration()); } } else { rrule.setEnd(fromDate(defaultRR->endDt())); } rrule.setBysecond(defaultRR->bySeconds().toVector().toStdVector()); rrule.setByminute(defaultRR->byMinutes().toVector().toStdVector()); rrule.setByhour(defaultRR->byHours().toVector().toStdVector()); std::vector daypos; foreach (const KCalCore::RecurrenceRule::WDayPos &dp, defaultRR->byDays()) { daypos.push_back(fromWeekDayPos(dp)); } rrule.setByday(daypos); rrule.setBymonthday(defaultRR->byMonthDays().toVector().toStdVector()); rrule.setByyearday(defaultRR->byYearDays().toVector().toStdVector()); rrule.setByweekno(defaultRR->byWeekNumbers().toVector().toStdVector()); rrule.setBymonth(defaultRR->byMonths().toVector().toStdVector()); i.setRecurrenceRule(rrule); std::vector rdates; foreach (const KDateTime &dt, rec->rDateTimes()) { rdates.push_back(fromDate(dt)); } foreach (const QDate &dt, rec->rDates()) { rdates.push_back(fromDate(KDateTime(dt))); } i.setRecurrenceDates(rdates); std::vector exdates; foreach (const KDateTime &dt, rec->exDateTimes()) { exdates.push_back(fromDate(dt)); } foreach (const QDate &dt, rec->exDates()) { exdates.push_back(fromDate(KDateTime(dt))); } i.setExceptionDates(exdates); if (!rec->exRules().empty()) { Warning() << "exrules are not supported"; } } template void setTodoEvent(KCalCore::Incidence &i, const T &e) { i.setPriority(toPriority(e.priority())); if (!e.location().empty()) { i.setLocation(fromStdString(e.location())); //TODO detect richtext } if (e.organizer().isValid()) { i.setOrganizer(KCalCore::Person::Ptr(new KCalCore::Person(fromStdString(e.organizer().name()), fromStdString(e.organizer().email())))); //TODO handle uid too } if (!e.url().empty()) { i.setNonKDECustomProperty(CUSTOM_KOLAB_URL, fromStdString(e.url())); } if (e.recurrenceID().isValid()) { i.setRecurrenceId(toDate(e.recurrenceID())); //TODO THISANDFUTURE } setRecurrence(i, e); foreach (const Kolab::Alarm a, e.alarms()) { KCalCore::Alarm::Ptr alarm = KCalCore::Alarm::Ptr(new KCalCore::Alarm(&i)); switch (a.type()) { case Kolab::Alarm::EMailAlarm: { KCalCore::Person::List receipents; foreach (Kolab::ContactReference c ,a.attendees()) { KCalCore::Person::Ptr person = KCalCore::Person::Ptr(new KCalCore::Person(fromStdString(c.name()), fromStdString(c.email()))); receipents.append(person); } alarm->setEmailAlarm(fromStdString(a.summary()), fromStdString(a.description()), receipents); } break; case Kolab::Alarm::DisplayAlarm: alarm->setDisplayAlarm(fromStdString(a.text())); break; case Kolab::Alarm::AudioAlarm: alarm->setAudioAlarm(fromStdString(a.audioFile().uri())); break; default: Error() << "invalid alarm"; } if (a.start().isValid()) { alarm->setTime(toDate(a.start())); } else if (a.relativeStart().isValid()) { if (a.relativeTo() == Kolab::End) { alarm->setEndOffset(toDuration(a.relativeStart())); } else { alarm->setStartOffset(toDuration(a.relativeStart())); } } alarm->setSnoozeTime(toDuration(a.duration())); alarm->setRepeatCount(a.numrepeat()); alarm->setEnabled(true); i.addAlarm(alarm); } } template void getTodoEvent(T &i, const I &e) { i.setPriority(fromPriority(e.priority())); i.setLocation(toStdString(e.location())); if (e.organizer() && !e.organizer()->email().isEmpty()) { i.setOrganizer(Kolab::ContactReference(Kolab::ContactReference::EmailReference, toStdString(e.organizer()->email()), toStdString(e.organizer()->name()))); //TODO handle uid too } i.setUrl(toStdString(e.nonKDECustomProperty(CUSTOM_KOLAB_URL))); i.setRecurrenceID(fromDate(e.recurrenceId()), false); //TODO THISANDFUTURE getRecurrence(i, e); std::vector alarms; foreach (const KCalCore::Alarm::Ptr &a, e.alarms()) { Kolab::Alarm alarm; //TODO KCalCore disables alarms using KCalCore::Alarm::enabled() (X-KDE-KCALCORE-ENABLED) We should either delete the alarm, or store the attribute . //Ideally we would store the alarm somewhere and temporarily delete it, so we can restore it when parsing. For now we just remove disabled alarms. if (!a->enabled()) { Warning() << "skipping disabled alarm"; continue; } switch (a->type()) { case KCalCore::Alarm::Display: alarm = Kolab::Alarm(toStdString(a->text())); break; case KCalCore::Alarm::Email: { std::vector receipents; foreach(const KCalCore::Person::Ptr &p, a->mailAddresses()) { receipents.push_back(Kolab::ContactReference(toStdString(p->email()), toStdString(p->name()))); } alarm = Kolab::Alarm(toStdString(a->mailSubject()), toStdString(a->mailText()), receipents); } break; case KCalCore::Alarm::Audio: { Kolab::Attachment audioFile; audioFile.setUri(toStdString(a->audioFile()), std::string()); alarm = Kolab::Alarm(audioFile); } break; default: Error() << "unhandled alarm"; } if (a->hasTime()) { alarm.setStart(fromDate(a->time())); } else if (a->hasStartOffset()) { alarm.setRelativeStart(fromDuration(a->startOffset()), Start); } else if (a->hasEndOffset()) { alarm.setRelativeStart(fromDuration(a->endOffset()), End); } else { Error() << "alarm trigger is missing"; continue; } alarm.setDuration(fromDuration(a->snoozeTime()), a->repeatCount()); alarms.push_back(alarm); } i.setAlarms(alarms); } KCalCore::Event::Ptr toKCalCore(const Kolab::Event &event) { KCalCore::Event::Ptr e(new KCalCore::Event); setIncidence(*e, event); setTodoEvent(*e, event); if (event.end().isValid()) { e->setDtEnd(toDate(event.end())); } if (event.duration().isValid()) { e->setDuration(toDuration(event.duration())); } if (event.transparency()) { e->setTransparency(KCalCore::Event::Transparent); } else { e->setTransparency(KCalCore::Event::Opaque); } return e; } Event fromKCalCore(const KCalCore::Event &event) { Event e; getIncidence(e, event); getTodoEvent(e, event); if (event.hasEndDate()) { e.setEnd(fromDate(event.dtEnd())); } else if (event.hasDuration()) { e.setDuration(fromDuration(event.duration())); } if (event.transparency() == KCalCore::Event::Transparent) { e.setTransparency(true); } else { e.setTransparency(false); } return e; } KCalCore::Todo::Ptr toKCalCore ( const Todo &todo ) { KCalCore::Todo::Ptr e(new KCalCore::Todo); setIncidence(*e, todo); setTodoEvent(*e, todo); if (todo.due().isValid()) { e->setDtDue(toDate(todo.due())); } if (!todo.relatedTo().empty()) { e->setRelatedTo(Conversion::fromStdString(todo.relatedTo().front()), KCalCore::Incidence::RelTypeParent); if (todo.relatedTo().size() > 1) { Error() << "only one relation support but got multiple"; } } e->setPercentComplete(todo.percentComplete()); return e; } Todo fromKCalCore ( const KCalCore::Todo &todo ) { Todo t; getIncidence(t, todo); getTodoEvent(t, todo); t.setDue(fromDate(todo.dtDue(true))); t.setPercentComplete(todo.percentComplete()); const QString relatedTo = todo.relatedTo(KCalCore::Incidence::RelTypeParent); if (!relatedTo.isEmpty()) { std::vector relateds; relateds.push_back(Conversion::toStdString(relatedTo)); t.setRelatedTo(relateds); } return t; } KCalCore::Journal::Ptr toKCalCore ( const Journal &journal ) { KCalCore::Journal::Ptr e(new KCalCore::Journal); setIncidence(*e, journal); //TODO contacts return e; } Journal fromKCalCore ( const KCalCore::Journal &journal ) { Journal j; getIncidence(j, journal); //TODO contacts return j; } } } libkolab-1.0.2/conversion/kcalconversion.h000066400000000000000000000033021262531616600206550ustar00rootroot00000000000000/* * Copyright (C) 2011 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef KOLABKCALCONVERSION_H #define KOLABKCALCONVERSION_H #include "kolab_export.h" #include #include #include #include #include #include namespace Kolab { /** * Conversion of Kolab-Containers to/from KCalCore Containers. * */ namespace Conversion { KOLAB_EXPORT KCalCore::Event::Ptr toKCalCore(const Kolab::Event &); KOLAB_EXPORT Kolab::Event fromKCalCore(const KCalCore::Event &); KOLAB_EXPORT KCalCore::Todo::Ptr toKCalCore(const Kolab::Todo &); KOLAB_EXPORT Kolab::Todo fromKCalCore(const KCalCore::Todo &); KOLAB_EXPORT KCalCore::Journal::Ptr toKCalCore(const Kolab::Journal &); KOLAB_EXPORT Kolab::Journal fromKCalCore(const KCalCore::Journal &); KOLAB_EXPORT KDateTime toDate(const Kolab::cDateTime &dt); KOLAB_EXPORT cDateTime fromDate(const KDateTime &dt); }; }; #endif libkolab-1.0.2/conversion/kolabconversion.cpp000066400000000000000000000104121262531616600213660ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include "kolabconversion.h" #include "commonconversion.h" #include namespace Kolab { namespace Conversion { Note fromNote(const KMime::Message::Ptr &m) { Akonadi::NoteUtils::NoteMessageWrapper note(m); Note n; n.setSummary(toStdString(note.title())); n.setDescription(toStdString(note.text())); KDateTime created = KDateTime(note.creationDate()); created.setTimeSpec(KDateTime::UTC); n.setCreated(fromDate(created)); n.setUid(toStdString(note.uid())); KDateTime lastModified = KDateTime(note.lastModifiedDate()); lastModified.setTimeSpec(KDateTime::UTC); n.setLastModified(fromDate(lastModified)); switch (note.classification()) { case Akonadi::NoteUtils::NoteMessageWrapper::Confidential: n.setClassification(Kolab::ClassConfidential); break; case Akonadi::NoteUtils::NoteMessageWrapper::Private: n.setClassification(Kolab::ClassPrivate); break; default: n.setClassification(Kolab::ClassPublic); } std::vector customs; QMap &customsMap = note.custom(); for (QMap ::const_iterator it = customsMap.constBegin(); it != customsMap.constEnd(); it ++) { customs.push_back(Kolab::CustomProperty(toStdString(it.key()), toStdString(it.value()))); } n.setCustomProperties(customs); std::vector attachments; foreach(const Akonadi::NoteUtils::Attachment &a, note.attachments()) { Kolab::Attachment attachment; if (a.url().isValid()) { attachment.setUri(toStdString(a.url().toString()), toStdString(a.mimetype())); } else { attachment.setData(toStdString(QString(a.data())), toStdString(a.mimetype())); } attachment.setLabel(toStdString(a.label())); attachments.push_back(attachment); } n.setAttachments(attachments); return n; } KMime::Message::Ptr toNote(const Note &n) { Akonadi::NoteUtils::NoteMessageWrapper note; note.setTitle(fromStdString(n.summary())); note.setText(fromStdString(n.description())); note.setFrom("kolab@kde4"); note.setCreationDate(toDate(n.created()).dateTime()); note.setUid(fromStdString(n.uid())); note.setLastModifiedDate(toDate(n.lastModified()).dateTime()); switch (n.classification()) { case Kolab::ClassPrivate: note.setClassification(Akonadi::NoteUtils::NoteMessageWrapper::Private); break; case Kolab::ClassConfidential: note.setClassification(Akonadi::NoteUtils::NoteMessageWrapper::Confidential); break; default: note.setClassification(Akonadi::NoteUtils::NoteMessageWrapper::Public); } foreach (const Kolab::Attachment &a, n.attachments()) { if (!a.uri().empty()) { Akonadi::NoteUtils::Attachment attachment(QUrl(fromStdString(a.uri())), fromStdString(a.mimetype())); attachment.setLabel(fromStdString(a.label())); note.attachments().append(attachment); } else { Akonadi::NoteUtils::Attachment attachment(fromStdString(a.data()).toLatin1(), fromStdString(a.mimetype())); attachment.setLabel(fromStdString(a.label())); note.attachments().append(attachment); } } foreach (const Kolab::CustomProperty &a, n.customProperties()) { note.custom().insert(fromStdString(a.identifier), fromStdString(a.value)); } return note.message(); } } } libkolab-1.0.2/conversion/kolabconversion.h000066400000000000000000000022471262531616600210420ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef KOLABCONVERSION_H #define KOLABCONVERSION_H #include "kolab_export.h" #include #include namespace Kolab { /** * Conversion of Kolab-Containers to/from KDE Containers. * */ namespace Conversion { KOLAB_EXPORT KMime::Message::Ptr toNote(const Kolab::Note &); KOLAB_EXPORT Kolab::Note fromNote(const KMime::Message::Ptr &); }; }; #endif libkolab-1.0.2/conversion/timezoneconverter.cpp000066400000000000000000000407671262531616600217720ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include "timezoneconverter.h" #include #include #include #include "kolabformat/errorhandler.h" #include QString TimezoneConverter::normalizeTimezone(const QString& tz) { if (QTimeZone::isTimeZoneIdAvailable(tz.toLatin1())) { return tz; } auto normalizedId = QTimeZone::windowsIdToDefaultIanaId(tz.toLatin1()); if (!normalizedId.isEmpty()) { return normalizedId; } //We're dealing with an invalid or unknown timezone, try to parse it QString guessedTimezone = fromCityName(tz); if (guessedTimezone.isEmpty()) { guessedTimezone = fromHardcodedList(tz); } if (guessedTimezone.isEmpty()) { guessedTimezone = fromGMTOffsetTimezone(tz); } Debug() << "Guessed timezone and found: " << guessedTimezone; return guessedTimezone; } QString TimezoneConverter::fromGMTOffsetTimezone(const QString& tz) { Q_UNUSED(tz); return QString(); } QString TimezoneConverter::fromCityName(const QString& tz) { const auto zones = QTimeZone::availableTimeZoneIds(); QHash countryMap; for (auto zone : zones) { const QString cityName = zone.split('/').last(); Q_ASSERT(!countryMap.contains(cityName)); countryMap.insert(cityName, zone); } QRegExp locationFinder("\\b([a-zA-Z])+\\b", Qt::CaseSensitive, QRegExp::RegExp2); int pos = 0; while (pos >= 0) { pos = locationFinder.indexIn(tz, pos); if (pos >= 0) { ++pos; } const QString location = locationFinder.capturedTexts().first(); qDebug() << "location " << location; if (countryMap.contains(location)) { qDebug() << "found match " << countryMap.value(location); return countryMap.value(location); } } return QString(); } //Based on // * http://msdn.microsoft.com/en-us/library/ms912391(v=winembedded.11).aspx // * http://technet.microsoft.com/en-us/library/cc749073(v=ws.10).aspx // * http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml // * http://stackoverflow.com/questions/4967903/linux-windows-timezone-mapping static const struct WindowsTimezone { // const int gmtOffset; const char *timezoneSpecifier; //This one should be stable and always in english const char *name; //The display name (which is in some cases still useful to try guessing) const char *olson[28]; //Corresponding olson timezones we can map to } windowsTimezones[] = { {"Afghanistan Standard Time", "Kabul", {"Asia/Kabul", "Asia/Kabul"}}, {"Alaskan Standard Time", "Alaska", {"America/Anchorage", "America/Anchorage America/Juneau America/Nome America/Sitka America/Yakutat"}}, {"Arab Standard Time", "Kuwait, Riyadh", {"Asia/Riyadh", "Asia/Bahrain", "Asia/Kuwait", "Asia/Qatar", "Asia/Riyadh", "Asia/Aden"}}, {"Arabian Standard Time", "Abu Dhabi, Muscat", {"Asia/Dubai", "Asia/Dubai", "Asia/Muscat", "Etc/GMT-4"}}, {"Arabic Standard Time", "Baghdad", {"Asia/Baghdad", "Asia/Baghdad"}}, {"Atlantic Standard Time", "Atlantic Time (Canada)", {"America/Halifax", "Atlantic/Bermuda", "America/Halifax America/Glace_Bay America/Goose_Bay America/Moncton", "America/Thule"}}, {"AUS Central Standard Time", "Darwin", {"Australia/Darwin", "Australia/Darwin"}}, {"AUS Eastern Standard Time", "Canberra, Melbourne, Sydney", {"Australia/Sydney", "Australia/Sydney Australia/Melbourne"}}, {"Azerbaijan Standard Time", "Baku", {"Asia/Baku", "Asia/Baku"}}, {"Azores Standard Time", "Azores", {"Atlantic/Azores", "America/Scoresbysund", "Atlantic/Azores"}}, {"Canada Central Standard Time", "Saskatchewan", {"America/Regina", "America/Regina America/Swift_Current"}}, {"Cape Verde Standard Time", "Cape Verde Islands", {"Atlantic/Cape_Verde", "Atlantic/Cape_Verde", "Etc/GMT+1"}}, {"Caucasus Standard Time", "Yerevan", {"Asia/Yerevan", "Asia/Yerevan"}}, {"Cen. Australia Standard Time", "Adelaide", {"Australia/Adelaide", "Australia/Adelaide Australia/Broken_Hill"}}, {"Central America Standard Time", "Central America", {"America/Guatemala", "America/Belize", "America/Costa_Rica", "Pacific/Galapagos", "America/Guatemala", "America/Tegucigalpa", "America/Managua", "America/El_Salvador", "Etc/GMT+6"}}, {"Central Asia Standard Time", "Astana, Dhaka", {"Asia/Almaty", "Antarctica/Vostok", "Indian/Chagos", "Asia/Bishkek", "Asia/Almaty Asia/Qyzylorda", "Etc/GMT-6"}}, {"Central Brazilian Standard Time", "Manaus", {"America/Cuiaba", "America/Cuiaba America/Campo_Grande"}}, {"Central Europe Standard Time", "Belgrade, Bratislava, Budapest, Ljubljana, Prague", {"Europe/Budapest", "Europe/Tirane", "Europe/Prague", "Europe/Budapest", "Europe/Podgorica", "Europe/Belgrade", "Europe/Ljubljana", "Europe/Bratislava"}}, {"Central European Standard Time", "Sarajevo, Skopje, Warsaw, Zagreb", {"Europe/Warsaw", "Europe/Sarajevo", "Europe/Zagreb", "Europe/Skopje", "Europe/Warsaw"}}, {"Central Pacific Standard Time", "Magadan, Solomon Islands, New Caledonia", {"Pacific/Guadalcanal", "Antarctica/Macquarie", "Pacific/Ponape Pacific/Kosrae", "Pacific/Noumea", "Pacific/Guadalcanal", "Pacific/Efate", "Etc/GMT-11"}}, {"Central Standard Time", "Central Time (US and Canada)", {"America/Chicago", "America/Winnipeg America/Rainy_River America/Rankin_Inlet America/Resolute", "America/Matamoros", "America/Chicago America/Indiana/Knox America/Indiana/Tell_City America/Menominee America/North_Dakota/Beulah America/North_Dakota/Center America/North_Dakota/New_Salem", "CST6CDT"}}, {"Central Standard Time (Mexico)", "Guadalajara, Mexico City, Monterrey", {"America/Mexico_City", "America/Mexico_City America/Bahia_Banderas America/Cancun America/Merida America/Monterrey"}}, {"China Standard Time", "Beijing, Chongqing, Hong Kong SAR, Urumqi", {"Asia/Shanghai", "Asia/Shanghai Asia/Chongqing Asia/Harbin Asia/Kashgar Asia/Urumqi", "Asia/Hong_Kong", "Asia/Macau"}}, {"Dateline Standard Time", "International Date Line West", {"Etc/GMT+12", "Etc/GMT+12"}}, {"E. Africa Standard Time", "Nairobi", {"Africa/Nairobi", "Antarctica/Syowa", "Africa/Djibouti", "Africa/Asmera", "Africa/Addis_Ababa", "Africa/Nairobi", "Indian/Comoro", "Indian/Antananarivo", "Africa/Khartoum", "Africa/Mogadishu", "Africa/Juba", "Africa/Dar_es_Salaam", "Africa/Kampala", "Indian/Mayotte", "Etc/GMT-3"}}, {"E. Australia Standard Time", "Brisbane", {"Australia/Brisbane", "Australia/Brisbane Australia/Lindeman"}}, {"E. Europe Standard Time", "Minsk", {"Asia/Nicosia", "Asia/Nicosia"}}, {"E. South America Standard Time", "Brasilia", {"America/Sao_Paulo", "America/Sao_Paulo"}}, {"Eastern Standard Time", "Eastern Time (US and Canada)", {"America/New_York", "America/Nassau", "America/Toronto America/Iqaluit America/Montreal America/Nipigon America/Pangnirtung America/Thunder_Bay", "America/Grand_Turk", "America/New_York America/Detroit America/Indiana/Petersburg America/Indiana/Vincennes America/Indiana/Winamac America/Kentucky/Monticello America/Louisville", "EST5EDT"}}, {"Egypt Standard Time", "Cairo", {"Africa/Cairo", "Africa/Cairo", "Asia/Gaza Asia/Hebron"}}, {"Ekaterinburg Standard Time", "Ekaterinburg", {"Asia/Yekaterinburg", "Asia/Yekaterinburg"}}, {"Fiji Standard Time", "Fiji Islands, Kamchatka, Marshall Islands", {"Pacific/Fiji", "Pacific/Fiji"}}, {"FLE Standard Time", "Helsinki, Kiev, Riga, Sofia, Tallinn, Vilnius", {"Europe/Kiev", "Europe/Mariehamn", "Europe/Sofia", "Europe/Tallinn", "Europe/Helsinki", "Europe/Vilnius", "Europe/Riga", "Europe/Kiev Europe/Simferopol Europe/Uzhgorod Europe/Zaporozhye"}}, {"Georgian Standard Time", "Tblisi", {"Asia/Tbilisi", "Asia/Tbilisi"}}, {"GMT Standard Time", "Greenwich Mean Time : Dublin, Edinburgh, Lisbon, London", {"Europe/London", "Atlantic/Canary", "Atlantic/Faeroe", "Europe/London", "Europe/Guernsey", "Europe/Dublin", "Europe/Isle_of_Man", "Europe/Jersey", "Europe/Lisbon Atlantic/Madeira"}}, {"Greenland Standard Time", "Greenland", {"America/Godthab", "America/Godthab"}}, {"Greenwich Standard Time", "Casablanca, Monrovia", {"Atlantic/Reykjavik", "Africa/Ouagadougou", "Africa/Abidjan", "Africa/El_Aaiun", "Africa/Accra", "Africa/Banjul", "Africa/Conakry", "Africa/Bissau", "Atlantic/Reykjavik", "Africa/Monrovia", "Africa/Bamako", "Africa/Nouakchott", "Atlantic/St_Helena", "Africa/Freetown", "Africa/Dakar", "Africa/Sao_Tome", "Africa/Lome"}}, {"GTB Standard Time", "Athens, Bucharest, Istanbul", {"Europe/Bucharest", "Europe/Athens", "Europe/Chisinau", "Europe/Bucharest"}}, {"Hawaiian Standard Time", "Hawaii", {"Pacific/Honolulu", "Pacific/Rarotonga", "Pacific/Tahiti", "Pacific/Johnston", "Pacific/Honolulu", "Etc/GMT+10"}}, {"India Standard Time", "Chennai, Kolkata, Mumbai, New Delhi", {"Asia/Calcutta", "Asia/Calcutta"}}, {"Iran Standard Time", "Tehran", {"Asia/Tehran", "Asia/Tehran"}}, {"Israel Standard Time", "Jerusalem", {"Asia/Jerusalem", "Asia/Jerusalem"}}, {"Korea Standard Time", "Seoul", {"Asia/Seoul", "Asia/Pyongyang", "Asia/Seoul"}}, // {"Mid-Atlantic Standard Time", "Mid-Atlantic", {"}}, {"Mountain Standard Time", "Mountain Time (US and Canada)", {"America/Denver", "America/Edmonton America/Cambridge_Bay America/Inuvik America/Yellowknife", "America/Ojinaga", "America/Denver America/Boise America/Shiprock", "MST7MDT"}}, {"Mountain Standard Time (Mexico)", "Chihuahua, La Paz, Mazatlan", {"America/Chihuahua", "America/Chihuahua America/Mazatlan"}}, {"Myanmar Standard Time", "Yangon (Rangoon)", {"Asia/Rangoon", "Indian/Cocos", "Asia/Rangoon"}}, {"N. Central Asia Standard Time", "Almaty, Novosibirsk", {"Asia/Novosibirsk", "Asia/Novosibirsk Asia/Novokuznetsk Asia/Omsk"}}, {"Namibia Standard Time", "Windhoek", {"Africa/Windhoek", "Africa/Windhoek"}}, {"Nepal Standard Time", "Kathmandu", {"Asia/Katmandu", "Asia/Katmandu"}}, {"New Zealand Standard Time", "Auckland, Wellington", {"Pacific/Auckland", "Antarctica/South_Pole Antarctica/McMurdo", "Pacific/Auckland"}}, {"Newfoundland Standard Time", "Newfoundland and Labrador", {"America/St_Johns", "America/St_Johns"}}, {"North Asia East Standard Time", "Irkutsk, Ulaanbaatar", {"Asia/Irkutsk", "Asia/Irkutsk"}}, {"North Asia Standard Time", "Krasnoyarsk", {"Asia/Krasnoyarsk", "Asia/Krasnoyarsk"}}, {"Pacific SA Standard Time", "Santiago", {"America/Santiago", "Antarctica/Palmer", "America/Santiago"}}, {"Pacific Standard Time", "Pacific Time (US and Canada); Tijuana", {"America/Los_Angeles", "America/Vancouver America/Dawson America/Whitehorse", "America/Tijuana", "America/Los_Angeles", "PST8PDT"}}, {"Romance Standard Time", "Brussels, Copenhagen, Madrid, Paris", {"Europe/Paris", "Europe/Brussels", "Europe/Copenhagen", "Europe/Madrid Africa/Ceuta", "Europe/Paris"}}, {"Russian Standard Time", "Moscow, St. Petersburg, Volgograd", {"Europe/Moscow", "Europe/Moscow Europe/Samara Europe/Volgograd"}}, {"SA Eastern Standard Time", "Buenos Aires, Georgetown", {"America/Cayenne", "Antarctica/Rothera", "America/Fortaleza America/Araguaina America/Belem America/Maceio America/Recife America/Santarem", "Atlantic/Stanley", "America/Cayenne", "America/Paramaribo", "Etc/GMT+3"}}, {"SA Pacific Standard Time", "Bogota, Lima, Quito", {"America/Bogota", "America/Coral_Harbour", "America/Bogota", "America/Guayaquil", "America/Port-au-Prince", "America/Jamaica", "America/Cayman", "America/Panama", "America/Lima", "Etc/GMT+5"}}, {"SA Western Standard Time", "Caracas, La Paz", {"America/La_Paz", "America/Antigua", "America/Anguilla", "America/Aruba", "America/Barbados", "America/St_Barthelemy", "America/La_Paz", "America/Kralendijk", "America/Manaus America/Boa_Vista America/Eirunepe America/Porto_Velho America/Rio_Branco", "America/Blanc-Sablon", "America/Curacao", "America/Dominica", "America/Santo_Domingo", "America/Grenada", "America/Guadeloupe", "America/Guyana", "America/St_Kitts", "America/St_Lucia", "America/Marigot", "America/Martinique", "America/Montserrat", "America/Puerto_Rico", "America/Lower_Princes", "America/Port_of_Spain", "America/St_Vincent", "America/Tortola", "America/St_Thomas", "Etc/GMT+4"}}, {"Samoa Standard Time", "Midway Island, Samoa", {"Pacific/Apia", "Pacific/Apia"}}, {"SE Asia Standard Time", "Bangkok, Hanoi, Jakarta", {"Asia/Bangkok", "Antarctica/Davis", "Indian/Christmas", "Asia/Jakarta Asia/Pontianak", "Asia/Phnom_Penh", "Asia/Vientiane", "Asia/Hovd", "Asia/Bangkok", "Asia/Saigon", "Etc/GMT-7"}}, {"Singapore Standard Time", "Kuala Lumpur, Singapore", {"Asia/Singapore", "Asia/Brunei", "Asia/Makassar", "Asia/Kuala_Lumpur Asia/Kuching", "Asia/Manila", "Asia/Singapore", "Etc/GMT-8"}}, {"South Africa Standard Time", "Harare, Pretoria", {"Africa/Johannesburg", "Africa/Bujumbura", "Africa/Gaborone", "Africa/Lubumbashi", "Africa/Maseru", "Africa/Blantyre", "Africa/Maputo", "Africa/Kigali", "Africa/Mbabane", "Africa/Johannesburg", "Africa/Lusaka", "Africa/Harare", "Etc/GMT-2"}}, {"Sri Lanka Standard Time", "Sri Jayawardenepura", {"Asia/Colombo", "Asia/Colombo"}}, {"Taipei Standard Time", "Taipei", {"Asia/Taipei", "Asia/Taipei"}}, {"Tasmania Standard Time", "Hobart", {"Australia/Hobart", "Australia/Hobart Australia/Currie"}}, {"Tokyo Standard Time", "Osaka, Sapporo, Tokyo", {"Asia/Tokyo", "Asia/Jayapura", "Asia/Tokyo", "Pacific/Palau", "Asia/Dili", "Etc/GMT-9"}}, {"Tonga Standard Time", "Nuku'alofa", {"Pacific/Tongatapu", "Pacific/Enderbury", "Pacific/Fakaofo", "Pacific/Tongatapu", "Etc/GMT-13"}}, {"US Eastern Standard Time", "Indiana (East)", {"America/Indianapolis", "America/Indianapolis America/Indiana/Marengo America/Indiana/Vevay"}}, {"US Mountain Standard Time", "Arizona", {"America/Phoenix", "America/Dawson_Creek America/Creston", "America/Hermosillo", "America/Phoenix", "Etc/GMT+7"}}, {"Vladivostok Standard Time", "Vladivostok", {"Asia/Vladivostok", "Asia/Vladivostok Asia/Sakhalin"}}, {"W. Australia Standard Time", "Perth", {"Australia/Perth", "Antarctica/Casey", "Australia/Perth"}}, {"W. Central Africa Standard Time", "West Central Africa", {"Africa/Lagos", "Africa/Luanda", "Africa/Porto-Novo", "Africa/Kinshasa", "Africa/Bangui", "Africa/Brazzaville", "Africa/Douala", "Africa/Algiers", "Africa/Libreville", "Africa/Malabo", "Africa/Niamey", "Africa/Lagos", "Africa/Ndjamena", "Africa/Tunis", "Etc/GMT-1"}}, {"W. Europe Standard Time", "Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna", {"Europe/Berlin", "Europe/Andorra", "Europe/Vienna", "Europe/Zurich", "Europe/Berlin", "Europe/Gibraltar", "Europe/Rome", "Europe/Vaduz", "Europe/Luxembourg", "Africa/Tripoli", "Europe/Monaco", "Europe/Malta", "Europe/Amsterdam", "Europe/Oslo", "Europe/Stockholm", "Arctic/Longyearbyen", "Europe/San_Marino", "Europe/Vatican"}}, {"West Asia Standard Time", "Islamabad, Karachi, Tashkent", {"Asia/Tashkent", "Antarctica/Mawson", "Asia/Oral Asia/Aqtau Asia/Aqtobe", "Indian/Maldives", "Indian/Kerguelen", "Asia/Dushanbe", "Asia/Ashgabat", "Asia/Tashkent Asia/Samarkand", "Etc/GMT-5"}}, {"West Pacific Standard Time", "Guam, Port Moresby", {"Pacific/Port_Moresby", "Antarctica/DumontDUrville", "Pacific/Truk", "Pacific/Guam", "Pacific/Saipan", "Pacific/Port_Moresby", "Etc/GMT-10"}}, {"Yakutsk Standard Time", "Yakuts", {"Asia/Yakutsk", "Asia/Yakutsk"}} }; static const int numWindowsTimezones = sizeof windowsTimezones / sizeof *windowsTimezones; QString TimezoneConverter::fromHardcodedList(const QString& tz) { for (int i = 0; i * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef TIMEZONECONVERTER_H #define TIMEZONECONVERTER_H #include class TimezoneConverter { public: static QString normalizeTimezone(const QString &tz); private: static QString fromCityName(const QString &tz); static QString fromHardcodedList(const QString &tz); static QString fromGMTOffsetTimezone(const QString &tz); }; #endif // TIMEZONECONVERTER_H libkolab-1.0.2/dummy.i000066400000000000000000000001421262531616600146030ustar00rootroot00000000000000/* This is a dummy plugin that does nothing. See https://issues.kolab.org/show_bug.cgi?id=2050 */ libkolab-1.0.2/freebusy/000077500000000000000000000000001262531616600151255ustar00rootroot00000000000000libkolab-1.0.2/freebusy/CMakeLists.txt000066400000000000000000000001221262531616600176600ustar00rootroot00000000000000set (FREEBUSY_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/freebusy.cpp PARENT_SCOPE) libkolab-1.0.2/freebusy/freebusy.cpp000066400000000000000000000271461262531616600174670ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include "freebusy.h" #include "conversion/kcalconversion.h" #include "conversion/commonconversion.h" #include "libkolab-version.h" #include #include #include #include #include // namespace KCalCore { // struct KCalFreebusy // { // // void init( const Event::List &eventList, const KDateTime &start, const KDateTime &end ) // { // mDtStart = start.toUtc(); // mDtEnd = end.toUtc(); // // // Loops through every event in the calendar // Event::List::ConstIterator it; // for ( it = eventList.constBegin(); it != eventList.constEnd(); ++it ) { // Event::Ptr event = *it; // // // If this event is transparent it shouldn't be in the freebusy list. // if ( event->transparency() == Event::Transparent ) { // continue; // } // // if ( event->hasRecurrenceId() ) { // continue; //TODO apply special period exception (duration could be different) // } // // const KDateTime eventStart = event->dtStart().toUtc(); // const KDateTime eventEnd = event->dtEnd().toUtc(); // // if ( event->recurs() ) { // const KCalCore::Duration duration( eventStart, eventEnd ); // const KCalCore::DateTimeList list = event->recurrence()->timesInInterval(start, end); // foreach (const KDateTime &dt, list) { // const KDateTime utc = dt.toUtc(); // addLocalPeriod(utc, duration.end(utc) ); // } // } else { // addLocalPeriod( eventStart, eventEnd ); // } // } // // // q->sortList(); // } // // bool addLocalPeriod( // const KDateTime &eventStart, // const KDateTime &eventEnd ) // { // KDateTime tmpStart; // KDateTime tmpEnd; // // //Check to see if the start *or* end of the event is // //between the start and end of the freebusy dates. // if ( !( ( ( mDtStart.secsTo( eventStart ) >= 0 ) && // ( eventStart.secsTo( mDtEnd ) >= 0 ) ) || // ( ( mDtStart.secsTo( eventEnd ) >= 0 ) && // ( eventEnd.secsTo( mDtEnd ) >= 0 ) ) ) ) { // qDebug() << "out of scope"; // return false; // } // // // qDebug() << eventStart.date().toString() << eventStart.time().toString() << mDtStart.toString(); // if ( eventStart < mDtStart ) { //eventStart is before start // // qDebug() << "use start"; // tmpStart = mDtStart; // } else { // tmpStart = eventStart; // } // // qDebug() << eventEnd.date().toString() << eventEnd.time().toString() << mDtEnd.toString(); // if ( eventEnd > mDtEnd ) { //event end is after dtEnd // // qDebug() << "use end"; // tmpEnd = mDtEnd; // } else { // tmpEnd = eventEnd; // } // // // qDebug() << "########## " << tmpStart.isValid(); // Q_ASSERT(tmpStart.isValid()); // Q_ASSERT(tmpEnd.isValid()); // // qDebug() << tmpStart.date().toString() << tmpStart.time().toString() << tmpStart.toString(); // // FreeBusyPeriod p( tmpStart, tmpEnd ); // mBusyPeriods.append( p ); // // return true; // } // // KDateTime mDtStart; // KDateTime mDtEnd; // end datetime // FreeBusyPeriod::List mBusyPeriods; // list of periods // // }; // // } // Namespace namespace Kolab { namespace FreebusyUtils { static QString createUuid() { const QString uuid = QUuid::createUuid().toString(); return uuid.mid(1, uuid.size()-2); } Kolab::Period addLocalPeriod( const KDateTime &eventStart, const KDateTime &eventEnd, const KDateTime &mDtStart, const KDateTime &mDtEnd) { KDateTime tmpStart; KDateTime tmpEnd; //Check to see if the start *or* end of the event is //between the start and end of the freebusy dates. if ( !( ( ( mDtStart <= eventStart) && ( eventStart <= mDtEnd ) ) || ( ( mDtStart <= eventEnd ) && ( eventEnd <= mDtEnd ) ) ) ) { qDebug() << "event is not within the fb range, skipping"; return Kolab::Period(); } if ( eventStart < mDtStart ) { //eventStart is before start tmpStart = mDtStart; } else { tmpStart = eventStart; } // qDebug() << eventEnd.date().toString() << eventEnd.time().toString() << mDtEnd.toString(); if ( eventEnd > mDtEnd ) { //event end is after dtEnd tmpEnd = mDtEnd; } else { tmpEnd = eventEnd; } Q_ASSERT(tmpStart.isValid()); Q_ASSERT(tmpEnd.isValid()); if (tmpStart.isDateOnly()) { tmpStart.setTime(QTime(0,0,0,0)); } if (tmpEnd.isDateOnly()) { tmpEnd.setTime(QTime(23,59,59,999)); //The window is inclusive } return Kolab::Period(Kolab::Conversion::fromDate(tmpStart), Kolab::Conversion::fromDate(tmpEnd)); } Freebusy generateFreeBusy(const std::vector< Event >& events, const cDateTime& startDate, const cDateTime& endDate) { QList list; foreach (const Kolab::Event &e, events) { list.append(Kolab::Conversion::toKCalCore(e)); } KCalCore::Person::Ptr person(new KCalCore::Person("dummyname", "dummyemail")); return generateFreeBusy(list, Kolab::Conversion::toDate(startDate), Kolab::Conversion::toDate(endDate), person); } Freebusy generateFreeBusy(const QList& events, const KDateTime& startDate, const KDateTime& endDate, const KCalCore::Person::Ptr &organizer) { /* * TODO the conversion of date-only values to date-time is only necessary because xCal doesn't allow date only. iCalendar doesn't seem to make this restriction so it looks like a bug. */ KDateTime start = startDate.toUtc(); if (start.isDateOnly()) { start.setTime(QTime(0,0,0,0)); } KDateTime end = endDate.toUtc(); if (end.isDateOnly()) { end.addDays(1); end.setTime(QTime(0,0,0,0)); //The window is inclusive } //TODO try to merge that with KCalCore::Freebusy std::vector freebusyPeriods; Q_FOREACH (KCalCore::Event::Ptr event, events) { // If this event is transparent it shouldn't be in the freebusy list. if ( event->transparency() == KCalCore::Event::Transparent ) { continue; } if ( event->hasRecurrenceId() ) { continue; //TODO apply special period exception (duration could be different) } const KDateTime eventStart = event->dtStart().toUtc(); const KDateTime eventEnd = event->dtEnd().toUtc(); std::vector periods; if ( event->recurs() ) { const KCalCore::Duration duration( eventStart, eventEnd ); const KCalCore::DateTimeList list = event->recurrence()->timesInInterval(start, end); Q_FOREACH (const KDateTime &dt, list) { const KDateTime utc = dt.toUtc(); const Kolab::Period &period = addLocalPeriod(utc, duration.end(utc), start, end); if (period.isValid()) { periods.push_back(period); } } } else { const Kolab::Period &period = addLocalPeriod(eventStart, eventEnd, start, end); if (period.isValid()) { periods.push_back(period); } } if (!periods.empty()) { Kolab::FreebusyPeriod period; period.setPeriods(periods); //TODO get busy type from event (out-of-office, tentative) period.setType(Kolab::FreebusyPeriod::Busy); period.setEvent(Kolab::Conversion::toStdString(event->uid()), Kolab::Conversion::toStdString(event->summary()), Kolab::Conversion::toStdString(event->location())); freebusyPeriods.push_back(period); } } Kolab::Freebusy freebusy; freebusy.setStart(Kolab::Conversion::fromDate(start)); freebusy.setEnd(Kolab::Conversion::fromDate(end)); freebusy.setPeriods(freebusyPeriods); freebusy.setUid(createUuid().toStdString()); freebusy.setTimestamp(Kolab::Conversion::fromDate(KDateTime::currentUtcDateTime())); if (organizer) { freebusy.setOrganizer(ContactReference(Kolab::ContactReference::EmailReference, Kolab::Conversion::toStdString(organizer->email()), Kolab::Conversion::toStdString(organizer->name()))); } return freebusy; } Freebusy aggregateFreeBusy(const std::vector< Freebusy >& fbList, const std::string &organizerEmail, const std::string &organizerName, bool simple) { std::vector periods; KDateTime start; KDateTime end; Q_FOREACH (const Freebusy &fb, fbList) { const KDateTime &tmpStart = Kolab::Conversion::toDate(fb.start()); if (!start.isValid() || tmpStart < start) { start = tmpStart; } const KDateTime &tmpEnd = Kolab::Conversion::toDate(fb.end()); if (!end.isValid() || tmpEnd > end) { end = tmpEnd; } Q_FOREACH (const Kolab::FreebusyPeriod &period, fb.periods()) { Kolab::FreebusyPeriod simplifiedPeriod; simplifiedPeriod.setPeriods(period.periods()); simplifiedPeriod.setType(period.type()); if (!simple) { //Don't copy and reset to avoid unintentional information leaking into simple lists simplifiedPeriod.setEvent(period.eventSummary(), period.eventUid(), period.eventLocation()); } periods.push_back(simplifiedPeriod); } } Freebusy aggregateFB; aggregateFB.setStart(Kolab::Conversion::fromDate(start)); aggregateFB.setEnd(Kolab::Conversion::fromDate(end)); aggregateFB.setPeriods(periods); aggregateFB.setUid(createUuid().toStdString()); aggregateFB.setTimestamp(Kolab::Conversion::fromDate(KDateTime::currentUtcDateTime())); aggregateFB.setOrganizer(ContactReference(Kolab::ContactReference::EmailReference, organizerEmail, organizerName)); return aggregateFB; } std::string toIFB(const Kolab::Freebusy &freebusy) { KCalCore::FreeBusy::Ptr fb(new KCalCore::FreeBusy(Kolab::Conversion::toDate(freebusy.start()), Kolab::Conversion::toDate(freebusy.end()))); KCalCore::FreeBusyPeriod::List list; Q_FOREACH (const Kolab::FreebusyPeriod &fbPeriod, freebusy.periods()) { Q_FOREACH (const Kolab::Period &p, fbPeriod.periods()) { KCalCore::FreeBusyPeriod period(Kolab::Conversion::toDate(p.start), Kolab::Conversion::toDate(p.end)); // period.setSummary("summary"); Doesn't even work. X-SUMMARY is read though (just not written out) //TODO list.append(period); } } fb->addPeriods(list); fb->setUid(QString::fromStdString(freebusy.uid())); fb->setOrganizer(KCalCore::Person::Ptr(new KCalCore::Person(Conversion::fromStdString(freebusy.organizer().name()), Conversion::fromStdString(freebusy.organizer().email())))); fb->setLastModified(Kolab::Conversion::toDate(freebusy.timestamp())); KCalCore::ICalFormat format; format.setApplication("libkolab", LIBKOLAB_LIB_VERSION_STRING); QString data = format.createScheduleMessage( fb, KCalCore::iTIPPublish ); return Conversion::toStdString(data); } } } libkolab-1.0.2/freebusy/freebusy.h000066400000000000000000000027701262531616600171300ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef FREEBUSY_H #define FREEBUSY_H #include "kolab_export.h" #include #include #include namespace Kolab { namespace FreebusyUtils { KOLAB_EXPORT Freebusy generateFreeBusy(const QList& events, const KDateTime& startDate, const KDateTime& endDate, const KCalCore::Person::Ptr &organizer); KOLAB_EXPORT std::string toIFB(const Kolab::Freebusy &); Kolab::Freebusy generateFreeBusy(const std::vector &events, const Kolab::cDateTime &startDate, const Kolab::cDateTime &endDate); KOLAB_EXPORT Kolab::Freebusy aggregateFreeBusy(const std::vector &fbs, const std::string &organizerEmail, const std::string &organizerName, bool simple = true); } } #endif // FREEBUSY_H libkolab-1.0.2/icalendar/000077500000000000000000000000001262531616600152235ustar00rootroot00000000000000libkolab-1.0.2/icalendar/CMakeLists.txt000066400000000000000000000005241262531616600177640ustar00rootroot00000000000000 set (ICALENDAR_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/icalendar.cpp ${CMAKE_CURRENT_SOURCE_DIR}/imip.cpp PARENT_SCOPE) if(PYTHON_BINDINGS) message("building python bindings") add_subdirectory(python) endif(PYTHON_BINDINGS) if(PHP_BINDINGS) message("building php bindings") add_subdirectory(php) endif(PHP_BINDINGS) libkolab-1.0.2/icalendar/icalendar.cpp000066400000000000000000000141671262531616600176620ustar00rootroot00000000000000/* Copyright (C) 2012 Christian Mollekopf 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 Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "icalendar.h" #include "imip.h" #include "libkolab-version.h" #include #include #include #include #include #include #include // #include #include #include namespace Kolab { std::string toICal(const std::vector &events) { KCalCore::Calendar::Ptr calendar(new KCalCore::MemoryCalendar(Kolab::Conversion::getTimeSpec(true, std::string()))); foreach (const Event &event, events) { KCalCore::Event::Ptr kcalEvent = Conversion::toKCalCore(event); kcalEvent->setCreated(KDateTime::currentUtcDateTime()); //sets dtstamp calendar->addEvent(kcalEvent); } KCalCore::ICalFormat format; format.setApplication("libkolab", LIBKOLAB_LIB_VERSION_STRING); // qDebug() << format.createScheduleMessage(calendar->events().first(), KCalCore::iTIPRequest); return Conversion::toStdString(format.toString(calendar)); } std::vector< Event > fromICalEvents(const std::string &input) { KCalCore::Calendar::Ptr calendar(new KCalCore::MemoryCalendar(Kolab::Conversion::getTimeSpec(true, std::string()))); KCalCore::ICalFormat format; format.setApplication("libkolab", LIBKOLAB_LIB_VERSION_STRING); format.fromString(calendar, Conversion::fromStdString(input)); std::vector events; foreach (const KCalCore::Event::Ptr &event, calendar->events()) { events.push_back(Conversion::fromKCalCore(*event)); } return events; } ITipHandler::ITipHandler() : mMethod(iTIPNoMethod) { } ITipHandler::ITipMethod mapFromKCalCore(KCalCore::iTIPMethod method) { Q_ASSERT((int)KCalCore::iTIPPublish == (int)ITipHandler::iTIPPublish); Q_ASSERT((int)KCalCore::iTIPNoMethod == (int)ITipHandler::iTIPNoMethod); return static_cast(method); } KCalCore::iTIPMethod mapToKCalCore(ITipHandler::ITipMethod method) { Q_ASSERT((int)KCalCore::iTIPPublish == (int)ITipHandler::iTIPPublish); Q_ASSERT((int)KCalCore::iTIPNoMethod == (int)ITipHandler::iTIPNoMethod); return static_cast(method); } std::string ITipHandler::toITip(const Event &event, ITipHandler::ITipMethod method) const { KCalCore::ICalFormat format; format.setApplication("libkolab", LIBKOLAB_LIB_VERSION_STRING); KCalCore::iTIPMethod m = mapToKCalCore(method); if (m == KCalCore::iTIPNoMethod) { return std::string(); } // qDebug() << event.start(). /* TODO * DTSTAMP is created * CREATED is current timestamp * LASTMODIFIED is lastModified * * Double check if that is correct. * * I think DTSTAMP should be the current timestamp, and CREATED should be the creation date. */ KCalCore::Event::Ptr e = Conversion::toKCalCore(event); return Conversion::toStdString(format.createScheduleMessage(e, m)); } std::vector< Event > ITipHandler::fromITip(const std::string &string) { KCalCore::Calendar::Ptr calendar(new KCalCore::MemoryCalendar(KDateTime::Spec(KDateTime::UTC))); KCalCore::ICalFormat format; KCalCore::ScheduleMessage::Ptr msg= format.parseScheduleMessage(calendar, Conversion::fromStdString(string)); KCalCore::Event::Ptr event = msg->event().dynamicCast(); std::vector< Event > events; events.push_back(Conversion::fromKCalCore(*event)); mMethod = mapFromKCalCore(msg->method()); return events; } ITipHandler::ITipMethod ITipHandler::method() const { return mMethod; } std::string ITipHandler::toIMip(const Event &event , ITipHandler::ITipMethod m, std::string from, bool bccMe) const { KCalCore::Event::Ptr e = Conversion::toKCalCore(event); // e->recurrence()->addRDateTime(e->dtStart()); //FIXME The createScheduleMessage converts everything to utc without a recurrence. KCalCore::ICalFormat format; format.setApplication("libkolab", LIBKOLAB_LIB_VERSION_STRING); KCalCore::iTIPMethod method = mapToKCalCore(m); const QString &messageText = format.createScheduleMessage( e, method ); //This code is mostly from MailScheduler::performTransaction if ( method == KCalCore::iTIPRequest || method == KCalCore::iTIPCancel || method == KCalCore::iTIPAdd || method == KCalCore::iTIPDeclineCounter ) { return Conversion::toStdString(QString(mailAttendees(e, bccMe, messageText))); } else { QString subject; if ( e && method == KCalCore::iTIPCounter ) { subject = QString( "Counter proposal: %1" ).arg(e->summary()); } return Conversion::toStdString(QString(mailOrganizer( e, Conversion::fromStdString(from), bccMe, messageText, subject))); } return std::string(); } std::vector< Event > ITipHandler::fromIMip(const std::string &input) { KMime::Message::Ptr msg = KMime::Message::Ptr(new KMime::Message); msg->setContent( Conversion::fromStdString(input).toUtf8() ); msg->parse(); msg->content(KMime::ContentIndex()); KMime::Content *c = Kolab::Mime::findContentByType(msg, "text/calendar"); if (!c) { qWarning() << "could not find text/calendar part"; return std::vector< Event >(); } return fromITip(Conversion::toStdString(QString(c->decodedContent()))); } } libkolab-1.0.2/icalendar/icalendar.h000066400000000000000000000053661262531616600173300ustar00rootroot00000000000000/* Copyright (C) 2012 Christian Mollekopf 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 Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef ICALENDAR_H #define ICALENDAR_H #ifndef SWIG #include "kolab_export.h" #else /* No export/import SWIG interface files */ #define KOLAB_EXPORT #endif #include namespace Kolab { /** * Takes a list of events and writes them to an iCal object. * */ KOLAB_EXPORT std::string toICal(const std::vector &); /** * Takes an iCal object and returns the contained events. */ KOLAB_EXPORT std::vector fromICalEvents(const std::string &); class KOLAB_EXPORT ITipHandler { public: ITipHandler(); enum ITipMethod { iTIPPublish, /**< Event, to-do, journal or freebusy posting */ iTIPRequest, /**< Event, to-do or freebusy scheduling request */ iTIPReply, /**< Event, to-do or freebusy reply to request */ iTIPAdd, /**< Event, to-do or journal additional property request */ iTIPCancel, /**< Event, to-do or journal cancellation notice */ iTIPRefresh, /**< Event or to-do description update request */ iTIPCounter, /**< Event or to-do submit counter proposal */ iTIPDeclineCounter,/**< Event or to-do decline a counter proposal */ iTIPNoMethod /**< No method */ }; std::string toIMip(const Kolab::Event &, ITipMethod, std::string from, bool bbcMe = false) const; std::vector fromIMip(const std::string &); /** * Create iTip message from single event */ std::string toITip(const Kolab::Event &, ITipMethod) const; /** * Parse iTip message with a single event */ std::vector fromITip(const std::string &); ITipMethod method() const; private: ITipMethod mMethod; }; } #endif // ICALENDAR_H libkolab-1.0.2/icalendar/icalendar.i000066400000000000000000000004661262531616600173250ustar00rootroot00000000000000%{ /* This macro ensures that return vectors remain a vector also in python and are not converted to tuples */ #define SWIG_PYTHON_EXTRA_NATIVE_CONTAINERS #include "icalendar.h" %} %include "std_string.i" %import(module="kolabformat") %import "../shared.i" %include "icalendar.h"libkolab-1.0.2/icalendar/imip.cpp000066400000000000000000000227401262531616600166720ustar00rootroot00000000000000/* Copyright (C) 2012 Christian Mollekopf 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 Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "imip.h" #include #include #include #include #include #include #include /* * The code in here is copy paste work from kdepim/calendarsupport. * * We need to refactor the code there and move the relevant parts to kdepimlibs to make it reusable. * * */ //From MailClient::send KMime::Message::Ptr createMessage( const QString &from, const QString &_to, const QString &cc, const QString &subject, const QString &body, bool hidden, bool bccMe, const QString &attachment/*, const QString &mailTransport */) { Q_UNUSED( hidden ); const bool outlookConformInvitation = false; QString userAgent = "libkolab"; // We must have a recipients list for most MUAs. Thus, if the 'to' list // is empty simply use the 'from' address as the recipient. QString to = _to; if ( to.isEmpty() ) { to = from; } qDebug() << "\nFrom:" << from << "\nTo:" << to << "\nCC:" << cc << "\nSubject:" << subject << "\nBody: \n" << body << "\nAttachment:\n" << attachment /*<< "\nmailTransport: " << mailTransport*/; // Now build the message we like to send. The message KMime::Message::Ptr instance // will be the root message that has 2 additional message. The body itself and // the attached cal.ics calendar file. KMime::Message::Ptr message = KMime::Message::Ptr( new KMime::Message ); message->contentTransferEncoding()->clear(); // 7Bit, decoded. // Set the headers message->userAgent()->fromUnicodeString(userAgent, "utf-8" ); message->from()->fromUnicodeString( from, "utf-8" ); message->to()->fromUnicodeString( to, "utf-8" ); message->cc()->fromUnicodeString( cc, "utf-8" ); if( bccMe ) { message->bcc()->fromUnicodeString( from, "utf-8" ); //from==me, right? } message->date()->setDateTime( KDateTime::currentLocalDateTime().dateTime() ); message->subject()->fromUnicodeString( subject, "utf-8" ); if ( outlookConformInvitation ) { message->contentType()->setMimeType( "text/calendar" ); message->contentType()->setCharset( "utf-8" ); message->contentType()->setName( QLatin1String( "cal.ics" ), "utf-8" ); message->contentType()->setParameter( QLatin1String( "method" ), QLatin1String( "request" ) ); if ( !attachment.isEmpty() ) { KMime::Headers::ContentDisposition *disposition = new KMime::Headers::ContentDisposition(); disposition->setDisposition( KMime::Headers::CDinline ); message->setHeader( disposition ); message->contentTransferEncoding()->setEncoding( KMime::Headers::CEquPr ); message->setBody( KMime::CRLFtoLF( attachment.toUtf8() ) ); } } else { // We need to set following 4 lines by hand else KMime::Content::addContent // will create a new Content instance for us to attach the main message // what we don't need cause we already have the main message instance where // 2 additional messages are attached. KMime::Headers::ContentType *ct = message->contentType(); ct->setMimeType( "multipart/mixed" ); ct->setBoundary( KMime::multiPartBoundary() ); ct->setCategory( KMime::Headers::CCcontainer ); // Set the first multipart, the body message. KMime::Content *bodyMessage = new KMime::Content; KMime::Headers::ContentDisposition *bodyDisposition = new KMime::Headers::ContentDisposition(); bodyDisposition->setDisposition( KMime::Headers::CDinline ); bodyMessage->contentType()->setMimeType( "text/plain" ); bodyMessage->contentType()->setCharset( "utf-8" ); bodyMessage->contentTransferEncoding()->setEncoding( KMime::Headers::CEquPr ); bodyMessage->setBody( KMime::CRLFtoLF( body.toUtf8() ) ); message->addContent( bodyMessage ); // Set the sedcond multipart, the attachment. if ( !attachment.isEmpty() ) { KMime::Content *attachMessage = new KMime::Content; KMime::Headers::ContentDisposition *attachDisposition = new KMime::Headers::ContentDisposition(); attachDisposition->setDisposition( KMime::Headers::CDattachment ); attachMessage->contentType()->setMimeType( "text/calendar" ); attachMessage->contentType()->setCharset( "utf-8" ); attachMessage->contentType()->setName( QLatin1String( "cal.ics" ), "utf-8" ); attachMessage->contentType()->setParameter( QLatin1String( "method" ), QLatin1String( "request" ) ); attachMessage->setHeader( attachDisposition ); attachMessage->contentTransferEncoding()->setEncoding( KMime::Headers::CEquPr ); attachMessage->setBody( KMime::CRLFtoLF( attachment.toUtf8() ) ); message->addContent( attachMessage ); } } // Job done, attach the both multiparts and assemble the message. message->assemble(); return message; } //From MailClient::mailAttendees QByteArray mailAttendees( const KCalCore::IncidenceBase::Ptr &incidence, // const KPIMIdentities::Identity &identity, bool bccMe, const QString &attachment /*const QString &mailTransport */) { KCalCore::Attendee::List attendees = incidence->attendees(); if ( attendees.isEmpty() ) { qWarning() << "There are no attendees to e-mail"; return QByteArray(); } const QString from = incidence->organizer()->fullName(); const QString organizerEmail = incidence->organizer()->email(); QStringList toList; QStringList ccList; const int numberOfAttendees( attendees.count() ); for ( int i=0; iemail(); if ( email.isEmpty() ) { continue; } // In case we (as one of our identities) are the organizer we are sending // this mail. We could also have added ourselves as an attendee, in which // case we don't want to send ourselves a notification mail. if ( organizerEmail == email ) { continue; } // Build a nice address for this attendee including the CN. QString tname, temail; const QString username = KEmailAddress::quoteNameIfNecessary( a->name() ); // ignore the return value from extractEmailAddressAndName() because // it will always be false since tusername does not contain "@domain". KEmailAddress::extractEmailAddressAndName( username, temail/*byref*/, tname/*byref*/ ); tname += QLatin1String( " <" ) + email + QLatin1Char( '>' ); // Optional Participants and Non-Participants are copied on the email if ( a->role() == KCalCore::Attendee::OptParticipant || a->role() == KCalCore::Attendee::NonParticipant ) { ccList << tname; } else { toList << tname; } } if( toList.isEmpty() && ccList.isEmpty() ) { // Not really to be called a groupware meeting, eh qWarning() << "There are really no attendees to e-mail"; return QByteArray(); } QString to; if ( !toList.isEmpty() ) { to = toList.join( QLatin1String( ", " ) ); } QString cc; if ( !ccList.isEmpty() ) { cc = ccList.join( QLatin1String( ", " ) ); } QString subject; if ( incidence->type() != KCalCore::Incidence::TypeFreeBusy ) { KCalCore::Incidence::Ptr inc = incidence.staticCast(); subject = inc->summary(); } else { subject = QString( "Free Busy Object" ); } const QString body = KCalUtils::IncidenceFormatter::mailBodyStr( incidence, KTimeZone(QTimeZone::systemTimeZoneId()) ); return createMessage(/* identity, */from, to, cc, subject, body, false, bccMe, attachment/*, mailTransport */)->encodedContent(); } QByteArray mailOrganizer( const KCalCore::IncidenceBase::Ptr &incidence, // const KPIMIdentities::Identity &identity, const QString &from, bool bccMe, const QString &attachment, const QString &sub/*, const QString &mailTransport*/ ) { const QString to = incidence->organizer()->fullName(); QString subject = sub; if ( incidence->type() != KCalCore::Incidence::TypeFreeBusy ) { KCalCore::Incidence::Ptr inc = incidence.staticCast(); if ( subject.isEmpty() ) { subject = inc->summary(); } } else { subject = QString( "Free Busy Message" ); } QString body = KCalUtils::IncidenceFormatter::mailBodyStr( incidence, KTimeZone(QTimeZone::systemTimeZoneId()) ); return createMessage( /*identity, */from, to, QString(), subject, body, false, bccMe, attachment/*, mailTransport */)->encodedContent(); } libkolab-1.0.2/icalendar/imip.h000066400000000000000000000025701262531616600163360ustar00rootroot00000000000000/* Copyright (C) 2012 Christian Mollekopf 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 Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IMIP_H #define IMIP_H #include #include QByteArray mailAttendees( const KCalCore::IncidenceBase::Ptr &incidence, bool bccMe, const QString &attachment ); QByteArray mailOrganizer( const KCalCore::IncidenceBase::Ptr &incidence, const QString &from, bool bccMe, const QString &attachment, const QString &sub ); #endif // IMIP_H libkolab-1.0.2/icalendar/php/000077500000000000000000000000001262531616600160125ustar00rootroot00000000000000libkolab-1.0.2/icalendar/php/CMakeLists.txt000066400000000000000000000001651262531616600205540ustar00rootroot00000000000000#Generate PHP wrapper include_directories(../) include(SWIGUtils) generatePHPBindings(kolabicalendar ../icalendar.i) libkolab-1.0.2/icalendar/python/000077500000000000000000000000001262531616600165445ustar00rootroot00000000000000libkolab-1.0.2/icalendar/python/CMakeLists.txt000066400000000000000000000001351262531616600213030ustar00rootroot00000000000000include_directories(../) include(SWIGUtils) generatePythonBindings(icalendar ../icalendar.i) libkolab-1.0.2/kolab_export.h000066400000000000000000000031001262531616600161350ustar00rootroot00000000000000/* * This file is part of libkolab. * Copyright (c) 2012 Christian Mollekopf * * 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 KOLAB_EXPORT_H #define KOLAB_EXPORT_H // #include #ifndef KOLAB_EXPORT # if defined(KOLAB_STATIC_LIBS) /* No export/import for static libraries */ # define KOLAB_EXPORT # elif defined(MAKE_KOLAB_LIB) /* We are building this library */ # define KOLAB_EXPORT __attribute__ ((visibility("default"))) # else /* We are using this library */ # define KOLAB_EXPORT __attribute__ ((visibility("default"))) # endif #endif # ifndef KOLAB_EXPORT_DEPRECATED # define KOLAB_EXPORT_DEPRECATED KDE_DEPRECATED __attribute__ ((visibility("default"))) # endif /** * @namespace Kolab * * @brief * Contains all the KOLAB library global classes, objects, and functions. */ #endif libkolab-1.0.2/kolabformat/000077500000000000000000000000001262531616600156025ustar00rootroot00000000000000libkolab-1.0.2/kolabformat/errorhandler.cpp000066400000000000000000000075531262531616600210070ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include "errorhandler.h" #include #include #include #include #include #include QDebug operator<<(QDebug dbg, const std::string &s) { dbg.nospace() << QString::fromStdString(s); return dbg.space(); } namespace Kolab { DebugStream::DebugStream() : QIODevice() { open(WriteOnly); } DebugStream::~DebugStream(){} qint64 DebugStream::writeData(const char *data, qint64 len) { const QByteArray buf = QByteArray::fromRawData(data, len); // qt_message_output(QtDebugMsg, buf.trimmed().constData()); ErrorHandler::instance().addError(m_severity, buf, m_location); return len; } QMutex mutex; void logMessage(const QString &message, const QString &file, int line, ErrorHandler::Severity s) { ErrorHandler::instance().addError(s, message, file+" "+QString::number(line)); } ErrorHandler::ErrorHandler() : m_worstError(Debug), m_debugStream(new DebugStream) { }; QDebug ErrorHandler::debugStream(ErrorHandler::Severity severity, int line, const char* file) { QMutexLocker locker(&mutex); ErrorHandler::instance().m_debugStream->m_location = QString(QString(file) + "(" + QString::number(line)+")"); ErrorHandler::instance().m_debugStream->m_severity = severity; return QDebug(ErrorHandler::instance().m_debugStream.data()); } void ErrorHandler::addError(ErrorHandler::Severity s, const QString& message, const QString &location) { QMutexLocker locker(&mutex); QString filename = location; if (!filename.split(QLatin1Char('/')).isEmpty()) { filename = filename.split(QLatin1Char('/')).last(); } const QString output = QTime::currentTime().toString(QLatin1String("(hh:mm:ss) ")) + filename + QLatin1String(":\t") + message; std::cout << output.toStdString() << std::endl; if (s == Debug) { return; } if (s > m_worstError) { m_worstError = s; m_worstErrorMessage = message; } m_errorQueue.append(Err(s, message, location)); } ErrorHandler::Severity ErrorHandler::error() const { QMutexLocker locker(&mutex); return m_worstError; } QString ErrorHandler::errorMessage() const { QMutexLocker locker(&mutex); return m_worstErrorMessage; } const QList< ErrorHandler::Err >& ErrorHandler::getErrors() const { QMutexLocker locker(&mutex); return m_errorQueue; } void ErrorHandler::clear() { QMutexLocker locker(&mutex); m_errorQueue.clear(); m_worstError = Debug; } void ErrorHandler::handleLibkolabxmlErrors() { switch (Kolab::error()) { case Kolab::Warning: instance().addError(ErrorHandler::Warning, QString::fromStdString(Kolab::errorMessage()), "libkolabxml"); break; case Kolab::Error: instance().addError(ErrorHandler::Error, QString::fromStdString(Kolab::errorMessage()), "libkolabxml"); break; case Kolab::Critical: instance().addError(ErrorHandler::Critical, QString::fromStdString(Kolab::errorMessage()), "libkolabxml"); break; default: //Do nothing, there is no message available in this case break; } } } libkolab-1.0.2/kolabformat/errorhandler.h000066400000000000000000000112431262531616600204430ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef ERRORHANDLER_H #define ERRORHANDLER_H #include "kolab_export.h" #include #include #include namespace Kolab { class DebugStream; /** * Kolab Error Handler * * Errors are reported during an operation, but the operation might still succeed. * The error handler therefore contains all errors which occured during a single operation, * and must be cleared at the start of a new operation. * * A user of the kolabobject classes should check ErrorHandler::error() after every operation. * * all non-const functions are not for the user of this class and only exist for internal usage. * * TODO: Hide everything which is not meant for the user from the interface. * FIXME: Use Threadlocal storage to make this threadsafe. */ class KOLAB_EXPORT ErrorHandler { public: enum Severity { Debug, Warning, //Warning, error could be corrected, object can be used without dataloss. This warning is also used if dataloss is acceptable because a feature is explicitly not supported. Error, //Potentially corrupt object, writing the object back could result in dataloss. (Object could still be used to display the data readonly). Critical //Critical error, produced object cannot be used and should be thrown away (writing back will result in dataloss). }; struct Err { Err(Severity s, const QString &m, const QString &l): severity(s), message(m), location(l){}; Severity severity; QString message; QString location; }; static ErrorHandler &instance() { static ErrorHandler inst; return inst; } void addError(Severity s, const QString &message, const QString &location); const QList &getErrors() const; Severity error() const; QString errorMessage() const; void clear(); /** * Check for errors during the libkolabxml reading/writing process and copy them into this error handler. */ static void handleLibkolabxmlErrors(); static void clearErrors() { ErrorHandler::instance().clear(); } static bool errorOccured() { if (ErrorHandler::instance().error() >= Error) { return true; } return false; } /** * Returns a debug stream to which logs errors */ static QDebug debugStream(Severity, int line, const char* file); private: ErrorHandler(); ErrorHandler(const ErrorHandler &); ErrorHandler & operator= (const ErrorHandler &); Severity m_worstError; QString m_worstErrorMessage; QList m_errorQueue; QScopedPointer m_debugStream; }; void logMessage(const QString &,const QString &, int, ErrorHandler::Severity s); #define LOG(message) logMessage(message,__FILE__, __LINE__, ErrorHandler::Debug); #define WARNING(message) logMessage(message,__FILE__, __LINE__, ErrorHandler::Warning); #define ERROR(message) logMessage(message,__FILE__, __LINE__, ErrorHandler::Error); #define CRITICAL(message) logMessage(message,__FILE__, __LINE__, ErrorHandler::Critical); class DebugStream: public QIODevice { public: QString m_location; ErrorHandler::Severity m_severity; DebugStream(); virtual ~DebugStream(); bool isSequential() const { return true; } qint64 readData(char *, qint64) { return 0; /* eof */ } qint64 readLineData(char *, qint64) { return 0; /* eof */ } qint64 writeData(const char *data, qint64 len); private: Q_DISABLE_COPY(DebugStream) }; #define Debug() Kolab::ErrorHandler::debugStream(Kolab::ErrorHandler::Debug, __LINE__, __FILE__) #define Warning() Kolab::ErrorHandler::debugStream(Kolab::ErrorHandler::Warning, __LINE__, __FILE__) #define Error() Kolab::ErrorHandler::debugStream(Kolab::ErrorHandler::Error, __LINE__, __FILE__) #define Critical() Kolab::ErrorHandler::debugStream(Kolab::ErrorHandler::Critical, __LINE__, __FILE__) } QDebug operator<<(QDebug dbg, const std::string &s); #endif // ERRORHANDLER_H libkolab-1.0.2/kolabformat/formathelpers.cpp000066400000000000000000000060321262531616600211620ustar00rootroot00000000000000#include "formathelpers.h" #include #include "kolabdefinitions.h" namespace Kolab { static const struct { const char *name; const char *label; } folderTypeData[] = { { KOLAB_FOLDER_TYPE_MAIL, "" }, { KOLAB_FOLDER_TYPE_CONTACT, I18N_NOOP( "Contacts" ) }, { KOLAB_FOLDER_TYPE_EVENT, I18N_NOOP( "Calendar" ) }, { KOLAB_FOLDER_TYPE_TASK, I18N_NOOP( "Tasks" ) }, { KOLAB_FOLDER_TYPE_JOURNAL, I18N_NOOP( "Journal" ) }, { KOLAB_FOLDER_TYPE_NOTE, I18N_NOOP( "Notes" ) }, { KOLAB_FOLDER_TYPE_CONFIGURATION, I18N_NOOP( "Configuration" ) }, { KOLAB_FOLDER_TYPE_FREEBUSY, I18N_NOOP( "Freebusy" ) }, { KOLAB_FOLDER_TYPE_FILE, I18N_NOOP( "Files" ) } }; static const int numFolderTypeData = sizeof folderTypeData / sizeof *folderTypeData; std::string folderAnnotation(FolderType type, bool isDefault) { Q_ASSERT( type >= 0 && type < LastType ); std::string result = folderTypeData[ type ].name; if ( isDefault ) { result += KOLAB_FOLDER_TYPE_DEFAULT_SUFFIX; } return result; } FolderType folderTypeFromString(const std::string& folderTypeName) { if ( folderTypeName == KOLAB_FOLDER_TYPE_CONTACT || folderTypeName == KOLAB_FOLDER_TYPE_CONTACT KOLAB_FOLDER_TYPE_DEFAULT_SUFFIX ) { return ContactType; } if ( folderTypeName == KOLAB_FOLDER_TYPE_EVENT || folderTypeName == KOLAB_FOLDER_TYPE_EVENT KOLAB_FOLDER_TYPE_DEFAULT_SUFFIX ) { return EventType; } if ( folderTypeName == KOLAB_FOLDER_TYPE_TASK || folderTypeName == KOLAB_FOLDER_TYPE_TASK KOLAB_FOLDER_TYPE_DEFAULT_SUFFIX ) { return TaskType; } if ( folderTypeName == KOLAB_FOLDER_TYPE_JOURNAL || folderTypeName == KOLAB_FOLDER_TYPE_JOURNAL KOLAB_FOLDER_TYPE_DEFAULT_SUFFIX ) { return JournalType; } if ( folderTypeName == KOLAB_FOLDER_TYPE_NOTE || folderTypeName == KOLAB_FOLDER_TYPE_NOTE KOLAB_FOLDER_TYPE_DEFAULT_SUFFIX ) { return NoteType; } if ( folderTypeName == KOLAB_FOLDER_TYPE_CONFIGURATION || folderTypeName == KOLAB_FOLDER_TYPE_CONFIGURATION KOLAB_FOLDER_TYPE_DEFAULT_SUFFIX ) { return ConfigurationType; } if ( folderTypeName == KOLAB_FOLDER_TYPE_FREEBUSY || folderTypeName == KOLAB_FOLDER_TYPE_FREEBUSY KOLAB_FOLDER_TYPE_DEFAULT_SUFFIX ) { return FreebusyType; } if ( folderTypeName == KOLAB_FOLDER_TYPE_FILE || folderTypeName == KOLAB_FOLDER_TYPE_FILE KOLAB_FOLDER_TYPE_DEFAULT_SUFFIX ) { return FileType; } return MailType; } FolderType guessFolderTypeFromName(const std::string& name) { for ( int i = 0; i < numFolderTypeData; ++i ) { if ( name == i18n( folderTypeData[ i ].label ).toStdString() || name == folderTypeData[ i ].label ) { return static_cast( i ); } } return MailType; } std::string nameForFolderType(FolderType type) { Q_ASSERT( type >= 0 && type < LastType ); return i18n( folderTypeData[ type ].label ).toStdString(); } } libkolab-1.0.2/kolabformat/formathelpers.h000066400000000000000000000015371262531616600206340ustar00rootroot00000000000000 #ifndef FORMATHELPERS_H #define FORMATHELPERS_H #include #include namespace Kolab { enum FolderType { MailType = 0, ContactType, EventType, TaskType, JournalType, NoteType, ConfigurationType, FreebusyType, FileType, LastType }; /** * Returns the FolderType from a KOLAB_FOLDER_TYPE_* folder type string */ KOLAB_EXPORT FolderType folderTypeFromString( const std::string &folderTypeName ); /** * Returns the annotation string for a folder */ KOLAB_EXPORT std::string folderAnnotation( FolderType type, bool isDefault = false ); /** * Guesses the folder type from a user visible string */ KOLAB_EXPORT FolderType guessFolderTypeFromName( const std::string &name ); /** * Returns a folder name for a type */ KOLAB_EXPORT std::string nameForFolderType( FolderType type ); } #endif libkolab-1.0.2/kolabformat/kolabdefinitions.h000066400000000000000000000061321262531616600213010ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef KOLABDEFINITIONS_H #define KOLABDEFINITIONS_H namespace Kolab { #define KOLAB_FOLDER_TYPE_MAIL "mail" #define KOLAB_FOLDER_TYPE_CONTACT "contact" #define KOLAB_FOLDER_TYPE_EVENT "event" #define KOLAB_FOLDER_TYPE_TASK "task" #define KOLAB_FOLDER_TYPE_JOURNAL "journal" #define KOLAB_FOLDER_TYPE_NOTE "note" #define KOLAB_FOLDER_TYPE_CONFIGURATION "configuration" #define KOLAB_FOLDER_TYPE_FREEBUSY "freebusy" #define KOLAB_FOLDER_TYPE_FILE "file" #define KOLAB_FOLDER_TYPE_DEFAULT_SUFFIX ".default" #define KOLAB_FOLDER_TYPE_DRAFT_SUFFIX ".drafts" #define KOLAB_FOLDER_TYPE_SENT_SUFFIX ".sentitems" #define KOLAB_FOLDER_TYPE_OUTBOX_SUFFIX ".outbox" #define KOLAB_FOLDER_TYPE_TRASH_SUFFIX ".wastebasket" #define KOLAB_FOLDER_TYPE_JUNK_SUFFIX ".junkemail" #define KOLAB_FOLDER_TYPE_INBOX_SUFFIX ".inbox" #define KOLAB_FOLDER_TYPE_ANNOTATION "/vendor/kolab/folder-type" #define X_KOLAB_TYPE_HEADER "X-Kolab-Type" #define X_KOLAB_MIME_VERSION_HEADER "X-Kolab-Mime-Version" #define X_KOLAB_MIME_VERSION_HEADER_COMPAT "X-Kolab-Version" #define KOLAB_VERSION_V2 "2.0" #define KOLAB_VERSION_V3 "3.0" #define KOLAB_OBJECT_FILENAME "kolab.xml" #define MIME_TYPE_XCAL "application/calendar+xml" #define MIME_TYPE_XCARD "application/vcard+xml" #define MIME_TYPE_KOLAB "application/vnd.kolab+xml" #define KOLAB_TYPE_EVENT "application/x-vnd.kolab.event" #define KOLAB_TYPE_TASK "application/x-vnd.kolab.task" #define KOLAB_TYPE_JOURNAL "application/x-vnd.kolab.journal" #define KOLAB_TYPE_CONTACT "application/x-vnd.kolab.contact" #define KOLAB_TYPE_DISTLIST_V2 "application/x-vnd.kolab.contact.distlist" #define KOLAB_TYPE_DISTLIST "application/x-vnd.kolab.distribution-list" #define KOLAB_TYPE_NOTE "application/x-vnd.kolab.note" #define KOLAB_TYPE_CONFIGURATION "application/x-vnd.kolab.configuration" #define KOLAB_TYPE_DICT "application/x-vnd.kolab.configuration.dictionary" #define KOLAB_TYPE_FREEBUSY "application/x-vnd.kolab.freebusy" #define KOLAB_TYPE_FILE "application/x-vnd.kolab.file" #define KOLAB_TYPE_RELATION "application/x-vnd.kolab.configuration.relation" enum Version { KolabV2, KolabV3 }; enum ObjectType { InvalidObject, EventObject, TodoObject, JournalObject, ContactObject, DistlistObject, NoteObject, DictionaryConfigurationObject, FreebusyObject, RelationConfigurationObject }; } #endif libkolab-1.0.2/kolabformat/kolabobject.cpp000066400000000000000000000470621262531616600205760ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include "kolabobject.h" #include "v2helpers.h" #include "kolabdefinitions.h" #include "errorhandler.h" #include "libkolab-version.h" #include "kolabbase.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Kolab { static inline QString eventKolabType() { return QString::fromLatin1(KOLAB_TYPE_EVENT); }; static inline QString todoKolabType() { return QString::fromLatin1(KOLAB_TYPE_TASK); }; static inline QString journalKolabType() { return QString::fromLatin1(KOLAB_TYPE_JOURNAL); }; static inline QString contactKolabType() { return QString::fromLatin1(KOLAB_TYPE_CONTACT); }; static inline QString distlistKolabType() { return QString::fromLatin1(KOLAB_TYPE_DISTLIST); } static inline QString distlistKolabTypeCompat() { return QString::fromLatin1(KOLAB_TYPE_DISTLIST_V2); } static inline QString noteKolabType() { return QString::fromLatin1(KOLAB_TYPE_NOTE); } static inline QString configurationKolabType() { return QString::fromLatin1(KOLAB_TYPE_CONFIGURATION); } static inline QString dictKolabType() { return QString::fromLatin1(KOLAB_TYPE_DICT); } static inline QString freebusyKolabType() { return QString::fromLatin1(KOLAB_TYPE_FREEBUSY); } static inline QString relationKolabType() { return QString::fromLatin1(KOLAB_TYPE_RELATION); } static inline QString xCalMimeType() { return QString::fromLatin1(MIME_TYPE_XCAL); }; static inline QString xCardMimeType() { return QString::fromLatin1(MIME_TYPE_XCARD); }; static inline QString kolabMimeType() { return QString::fromLatin1(MIME_TYPE_KOLAB); }; KCalCore::Event::Ptr readV2EventXML(const QByteArray& xmlData, QStringList& attachments) { return fromXML(xmlData, attachments); } QString ownUrlDecode(QByteArray encodedParam) { encodedParam.replace('+', ' '); return QUrl::fromPercentEncoding(encodedParam); } RelationMember parseMemberUrl(const QString &string) { if (string.startsWith("urn:uuid:")) { RelationMember member; member.gid = string.mid(9); return member; } QUrl url(QUrl::fromEncoded(string.toLatin1())); QList path; Q_FOREACH(const QByteArray &fragment, url.encodedPath().split('/')) { path.append(ownUrlDecode(fragment).toUtf8()); } // qDebug() << path; bool isShared = false; int start = path.indexOf("user"); if (start < 0) { start = path.indexOf("shared"); isShared = true; } if (start < 0) { Warning() << "Couldn't find \"user\" or \"shared\" in path: " << path; return RelationMember(); } path = path.mid(start + 1); if (path.size() < 2) { Warning() << "Incomplete path: " << path; return RelationMember(); } RelationMember member; if (!isShared) { member.user = path.takeFirst(); } member.uid = path.takeLast().toLong(); member.mailbox = path; member.messageId = ownUrlDecode(url.encodedQueryItemValue("message-id")); member.subject = ownUrlDecode(url.encodedQueryItemValue("subject")); member.date = ownUrlDecode(url.encodedQueryItemValue("date")); // qDebug() << member.uid << member.mailbox; return member; } static QByteArray join(const QList &list, const QByteArray &c) { QByteArray result; Q_FOREACH (const QByteArray &a, list) { result += a + c; } result.chop(c.size()); return result; } KOLAB_EXPORT QString generateMemberUrl(const RelationMember &member) { if (!member.gid.isEmpty()) { return QString("urn:uuid:%1").arg(member.gid); } QUrl url; url.setScheme("imap"); QList path; path << "/"; if (!member.user.isEmpty()) { path << "user"; path << QUrl::toPercentEncoding(member.user.toLatin1()); } else { path << "shared"; } Q_FOREACH(const QByteArray &mb, member.mailbox) { path << QUrl::toPercentEncoding(mb); } path << QByteArray::number(member.uid); url.setEncodedPath("/" + join(path, "/")); QList > queryItems; queryItems.append(qMakePair(QString::fromLatin1("message-id").toLatin1(), QUrl::toPercentEncoding(member.messageId))); queryItems.append(qMakePair(QString::fromLatin1("subject").toLatin1(), QUrl::toPercentEncoding(member.subject))); queryItems.append(qMakePair(QString::fromLatin1("date").toLatin1(), QUrl::toPercentEncoding(member.date))); url.setEncodedQueryItems(queryItems); return QString::fromLatin1(url.toEncoded()); } //@cond PRIVATE class KolabObjectReader::Private { public: Private() : mObjectType( InvalidObject ), mVersion( KolabV3 ), mOverrideObjectType(InvalidObject), mDoOverrideVersion(false) { mAddressee = KContacts::Addressee(); } KCalCore::Incidence::Ptr mIncidence; KContacts::Addressee mAddressee; KContacts::ContactGroup mContactGroup; KMime::Message::Ptr mNote; QStringList mDictionary; QString mDictionaryLanguage; ObjectType mObjectType; Version mVersion; Kolab::Freebusy mFreebusy; ObjectType mOverrideObjectType; Version mOverrideVersion; bool mDoOverrideVersion; Akonadi::Relation mRelation; Akonadi::Tag mTag; QStringList mTagMembers; }; //@endcond KolabObjectReader::KolabObjectReader() : d( new KolabObjectReader::Private ) { } KolabObjectReader::KolabObjectReader(const KMime::Message::Ptr& msg) : d( new KolabObjectReader::Private ) { parseMimeMessage(msg); } KolabObjectReader::~KolabObjectReader() { delete d; } void KolabObjectReader::setObjectType(ObjectType type) { d->mOverrideObjectType = type; } void KolabObjectReader::setVersion(Version version) { d->mOverrideVersion = version; d->mDoOverrideVersion = true; } void printMessageDebugInfo(const KMime::Message::Ptr &msg) { //TODO replace by Debug stream for Mimemessage Debug() << "MessageId: " << msg->messageID()->asUnicodeString(); Debug() << "Subject: " << msg->subject()->asUnicodeString(); // Debug() << msg->encodedContent(); } ObjectType KolabObjectReader::parseMimeMessage(const KMime::Message::Ptr &msg) { ErrorHandler::clearErrors(); d->mObjectType = InvalidObject; if (msg->contents().isEmpty()) { Critical() << "message has no contents (we likely failed to parse it correctly)"; printMessageDebugInfo(msg); return InvalidObject; } const std::string message = msg->encodedContent().toStdString(); Kolab::MIMEObject mimeObject; mimeObject.setObjectType(d->mOverrideObjectType); if (d->mDoOverrideVersion) { mimeObject.setVersion(d->mOverrideVersion); } d->mObjectType = mimeObject.parseMessage(message); d->mVersion = mimeObject.getVersion(); switch (mimeObject.getType()) { case EventObject: { const Kolab::Event & event = mimeObject.getEvent(); d->mIncidence = Kolab::Conversion::toKCalCore(event); } break; case TodoObject: { const Kolab::Todo & event = mimeObject.getTodo(); d->mIncidence = Kolab::Conversion::toKCalCore(event); } break; case JournalObject: { const Kolab::Journal & event = mimeObject.getJournal(); d->mIncidence = Kolab::Conversion::toKCalCore(event); } break; case ContactObject: { const Kolab::Contact &contact = mimeObject.getContact(); d->mAddressee = Kolab::Conversion::toKABC(contact); //TODO extract attachments } break; case DistlistObject: { const Kolab::DistList &distlist = mimeObject.getDistlist(); d->mContactGroup = Kolab::Conversion::toKABC(distlist); } break; case NoteObject: { const Kolab::Note ¬e = mimeObject.getNote(); d->mNote = Kolab::Conversion::toNote(note); } break; case DictionaryConfigurationObject: { const Kolab::Configuration &configuration = mimeObject.getConfiguration(); const Kolab::Dictionary &dictionary = configuration.dictionary(); d->mDictionary.clear(); foreach (const std::string &entry, dictionary.entries()) { d->mDictionary.append(Conversion::fromStdString(entry)); } d->mDictionaryLanguage = Conversion::fromStdString(dictionary.language()); } break; case FreebusyObject: { const Kolab::Freebusy &fb = mimeObject.getFreebusy(); d->mFreebusy = fb; break; } case RelationConfigurationObject: { const Kolab::Configuration &configuration = mimeObject.getConfiguration(); const Kolab::Relation &relation = configuration.relation(); if (relation.type() == "tag") { d->mTag = Akonadi::Tag(); d->mTag.setName(Conversion::fromStdString(relation.name())); d->mTag.setGid(Conversion::fromStdString(configuration.uid()).toLatin1()); d->mTag.setType(Akonadi::Tag::GENERIC); d->mTagMembers.reserve(relation.members().size()); foreach (const std::string &member, relation.members()) { d->mTagMembers << Conversion::fromStdString(member); } } else if (relation.type() == "generic") { if (relation.members().size() == 2) { d->mRelation = Akonadi::Relation(); d->mRelation.setRemoteId(Conversion::fromStdString(configuration.uid()).toLatin1()); d->mRelation.setType(Akonadi::Relation::GENERIC); d->mTagMembers.reserve(relation.members().size()); foreach (const std::string &member, relation.members()) { d->mTagMembers << Conversion::fromStdString(member); } } else { Critical() << "generic relation had wrong number of members:" << relation.members().size(); printMessageDebugInfo(msg); } } else { Critical() << "unknown configuration object type" << relation.type(); printMessageDebugInfo(msg); } } break; default: Critical() << "no kolab object found "; printMessageDebugInfo(msg); break; } return d->mObjectType; } Version KolabObjectReader::getVersion() const { return d->mVersion; } ObjectType KolabObjectReader::getType() const { return d->mObjectType; } KCalCore::Event::Ptr KolabObjectReader::getEvent() const { return d->mIncidence.dynamicCast(); } KCalCore::Todo::Ptr KolabObjectReader::getTodo() const { return d->mIncidence.dynamicCast(); } KCalCore::Journal::Ptr KolabObjectReader::getJournal() const { return d->mIncidence.dynamicCast(); } KCalCore::Incidence::Ptr KolabObjectReader::getIncidence() const { return d->mIncidence; } KContacts::Addressee KolabObjectReader::getContact() const { return d->mAddressee; } KContacts::ContactGroup KolabObjectReader::getDistlist() const { return d->mContactGroup; } KMime::Message::Ptr KolabObjectReader::getNote() const { return d->mNote; } QStringList KolabObjectReader::getDictionary(QString& lang) const { lang = d->mDictionaryLanguage; return d->mDictionary; } Freebusy KolabObjectReader::getFreebusy() const { return d->mFreebusy; } bool KolabObjectReader::isTag() const { return !d->mTag.gid().isEmpty(); } Akonadi::Tag KolabObjectReader::getTag() const { return d->mTag; } QStringList KolabObjectReader::getTagMembers() const { return d->mTagMembers; } bool KolabObjectReader::isRelation() const { return d->mRelation.isValid(); } Akonadi::Relation KolabObjectReader::getRelation() const { return d->mRelation; } static KMime::Message::Ptr createMimeMessage(const std::string &mimeMessage) { KMime::Message::Ptr msg(new KMime::Message); msg->setContent(QByteArray(mimeMessage.c_str())); msg->parse(); return msg; } KMime::Message::Ptr KolabObjectWriter::writeEvent(const KCalCore::Event::Ptr &i, Version v, const QString &productId, const QString &) { ErrorHandler::clearErrors(); if (!i) { Critical() << "passed a null pointer"; return KMime::Message::Ptr(); } const Kolab::Event &event = Kolab::Conversion::fromKCalCore(*i); Kolab::MIMEObject mimeObject; const std::string mimeMessage = mimeObject.writeEvent(event, v, productId.toStdString()); return createMimeMessage(mimeMessage); } KMime::Message::Ptr KolabObjectWriter::writeTodo(const KCalCore::Todo::Ptr &i, Version v, const QString &productId, const QString &) { ErrorHandler::clearErrors(); if (!i) { Critical() << "passed a null pointer"; return KMime::Message::Ptr(); } const Kolab::Todo &todo = Kolab::Conversion::fromKCalCore(*i); Kolab::MIMEObject mimeObject; const std::string mimeMessage = mimeObject.writeTodo(todo, v, productId.toStdString()); return createMimeMessage(mimeMessage); } KMime::Message::Ptr KolabObjectWriter::writeJournal(const KCalCore::Journal::Ptr &i, Version v, const QString &productId, const QString &) { ErrorHandler::clearErrors(); if (!i) { Critical() << "passed a null pointer"; return KMime::Message::Ptr(); } const Kolab::Journal &journal = Kolab::Conversion::fromKCalCore(*i); Kolab::MIMEObject mimeObject; const std::string mimeMessage = mimeObject.writeJournal(journal, v, productId.toStdString()); return createMimeMessage(mimeMessage); } KMime::Message::Ptr KolabObjectWriter::writeIncidence(const KCalCore::Incidence::Ptr &i, Version v, const QString& productId, const QString& tz) { if (!i) { Critical() << "passed a null pointer"; return KMime::Message::Ptr(); } switch (i->type()) { case KCalCore::IncidenceBase::TypeEvent: return writeEvent(i.dynamicCast(),v,productId,tz); case KCalCore::IncidenceBase::TypeTodo: return writeTodo(i.dynamicCast(),v,productId,tz); case KCalCore::IncidenceBase::TypeJournal: return writeJournal(i.dynamicCast(),v,productId,tz); default: Critical() << "unknown incidence type"; } return KMime::Message::Ptr(); } KMime::Message::Ptr KolabObjectWriter::writeContact(const KContacts::Addressee &addressee, Version v, const QString &productId) { ErrorHandler::clearErrors(); const Kolab::Contact &contact = Kolab::Conversion::fromKABC(addressee); Kolab::MIMEObject mimeObject; const std::string mimeMessage = mimeObject.writeContact(contact, v, productId.toStdString()); return createMimeMessage(mimeMessage); } KMime::Message::Ptr KolabObjectWriter::writeDistlist(const KContacts::ContactGroup &kDistList, Version v, const QString &productId) { ErrorHandler::clearErrors(); const Kolab::DistList &distlist = Kolab::Conversion::fromKABC(kDistList); Kolab::MIMEObject mimeObject; const std::string mimeMessage = mimeObject.writeDistlist(distlist, v, productId.toStdString()); return createMimeMessage(mimeMessage); } KMime::Message::Ptr KolabObjectWriter::writeNote(const KMime::Message::Ptr &n, Version v, const QString &productId) { ErrorHandler::clearErrors(); if (!n) { Critical() << "passed a null pointer"; return KMime::Message::Ptr(); } const Kolab::Note ¬e = Kolab::Conversion::fromNote(n); Kolab::MIMEObject mimeObject; const std::string mimeMessage = mimeObject.writeNote(note, v, productId.toStdString()); return createMimeMessage(mimeMessage); } KMime::Message::Ptr KolabObjectWriter::writeDictionary(const QStringList &entries, const QString& lang, Version v, const QString& productId) { ErrorHandler::clearErrors(); Kolab::Dictionary dictionary(Conversion::toStdString(lang)); std::vector ent; foreach (const QString &e, entries) { ent.push_back(Conversion::toStdString(e)); } dictionary.setEntries(ent); Kolab::Configuration configuration(dictionary); //TODO preserve creation/lastModified date Kolab::MIMEObject mimeObject; const std::string mimeMessage = mimeObject.writeConfiguration(configuration, v, productId.toStdString()); return createMimeMessage(mimeMessage); } KMime::Message::Ptr KolabObjectWriter::writeFreebusy(const Freebusy &freebusy, Version v, const QString& productId) { ErrorHandler::clearErrors(); Kolab::MIMEObject mimeObject; const std::string mimeMessage = mimeObject.writeFreebusy(freebusy, v, productId.toStdString()); return createMimeMessage(mimeMessage); } KMime::Message::Ptr writeRelationHelper(const Kolab::Relation &relation, const QByteArray &uid, const QString &productId) { ErrorHandler::clearErrors(); Kolab::MIMEObject mimeObject; Kolab::Configuration configuration(relation); //TODO preserve creation/lastModified date configuration.setUid(uid.constData()); const std::string mimeMessage = mimeObject.writeConfiguration(configuration, Kolab::KolabV3, Conversion::toStdString(productId)); return createMimeMessage(mimeMessage); } KMime::Message::Ptr KolabObjectWriter::writeTag(const Akonadi::Tag &tag, const QStringList &members, Version v, const QString &productId) { ErrorHandler::clearErrors(); if (v != KolabV3) { Critical() << "only v3 implementation available"; } Kolab::Relation relation(Conversion::toStdString(tag.name()), "tag"); std::vector m; m.reserve(members.count()); foreach (const QString &member, members) { m.push_back(Conversion::toStdString(member)); } relation.setMembers(m); return writeRelationHelper(relation, tag.gid(), productId); } KMime::Message::Ptr KolabObjectWriter::writeRelation(const Akonadi::Relation &relation, const QStringList &items, Version v, const QString &productId) { ErrorHandler::clearErrors(); if (v != KolabV3) { Critical() << "only v3 implementation available"; } if (items.size() != 2) { Critical() << "Wrong number of members for generic relation."; return KMime::Message::Ptr(); } Kolab::Relation kolabRelation(std::string(), "generic"); std::vector m; m.reserve(2); m.push_back(Conversion::toStdString(items.at(0))); m.push_back(Conversion::toStdString(items.at(1))); kolabRelation.setMembers(m); return writeRelationHelper(kolabRelation, relation.remoteId(), productId); } }; //Namespace libkolab-1.0.2/kolabformat/kolabobject.h000066400000000000000000000123501262531616600202330ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef KOLABOBJECT_H #define KOLABOBJECT_H #include #include #include #include #include #include #include #include #include #include #include #include "kolabdefinitions.h" namespace Kolab { class Freebusy; KOLAB_EXPORT KCalCore::Event::Ptr readV2EventXML(const QByteArray &xmlData, QStringList &attachments); struct KOLAB_EXPORT RelationMember { QString messageId; QString subject; QString date; QList mailbox; QString user; qint64 uid; QString gid; }; KOLAB_EXPORT RelationMember parseMemberUrl(const QString &url); KOLAB_EXPORT QString generateMemberUrl(const RelationMember &url); /** * Class to read Kolab Mime files * * It implements the Kolab specifics of Mime message handling. * This class is not reusable and only meant to read a single object. * Parse the mime message and then call the correct getter, based on the type * */ class KOLAB_EXPORT KolabObjectReader { public: KolabObjectReader(); explicit KolabObjectReader(const KMime::Message::Ptr &msg); ~KolabObjectReader(); ObjectType parseMimeMessage(const KMime::Message::Ptr &msg); /** * Set to override the autodetected object type, before parsing the message. */ void setObjectType(ObjectType); /** * Set to override the autodetected version, before parsing the message. */ void setVersion(Version); /** * Returns the Object type of the parsed kolab object. */ ObjectType getType() const; /** * Returns the kolab-format version of the parsed kolab object. */ Version getVersion() const; /** * Getter to get the retrieved object. * Only the correct one will return a valid object. * * Use getType() to determine the correct one to call. */ KCalCore::Event::Ptr getEvent() const; KCalCore::Todo::Ptr getTodo() const; KCalCore::Journal::Ptr getJournal() const; KCalCore::Incidence::Ptr getIncidence() const; KContacts::Addressee getContact() const; KContacts::ContactGroup getDistlist() const; KMime::Message::Ptr getNote() const; QStringList getDictionary(QString &lang) const; Freebusy getFreebusy() const; bool isTag() const; Akonadi::Tag getTag() const; QStringList getTagMembers() const; bool isRelation() const; Akonadi::Relation getRelation() const; private: //@cond PRIVATE KolabObjectReader(const KolabObjectReader &other); KolabObjectReader &operator=(const KolabObjectReader &rhs); class Private; Private *const d; //@endcond }; /** * Class to write Kolab Mime files * */ class KOLAB_EXPORT KolabObjectWriter { public: static KMime::Message::Ptr writeEvent(const KCalCore::Event::Ptr &, Version v = KolabV3, const QString &productId = QString(), const QString &tz = QString()); static KMime::Message::Ptr writeTodo(const KCalCore::Todo::Ptr &, Version v = KolabV3, const QString &productId = QString(),const QString &tz = QString()); static KMime::Message::Ptr writeJournal(const KCalCore::Journal::Ptr &, Version v = KolabV3, const QString &productId = QString(),const QString &tz = QString()); static KMime::Message::Ptr writeIncidence(const KCalCore::Incidence::Ptr &, Version v = KolabV3, const QString &productId = QString(),const QString &tz = QString()); static KMime::Message::Ptr writeContact(const KContacts::Addressee &, Version v = KolabV3, const QString &productId = QString()); static KMime::Message::Ptr writeDistlist(const KContacts::ContactGroup &, Version v = KolabV3, const QString &productId = QString()); static KMime::Message::Ptr writeNote(const KMime::Message::Ptr &, Version v = KolabV3, const QString &productId = QString()); static KMime::Message::Ptr writeDictionary(const QStringList &, const QString &lang, Version v = KolabV3, const QString &productId = QString()); static KMime::Message::Ptr writeFreebusy(const Kolab::Freebusy &, Version v = KolabV3, const QString &productId = QString()); static KMime::Message::Ptr writeTag(const Akonadi::Tag &, const QStringList &items, Version v = KolabV3, const QString &productId = QString()); static KMime::Message::Ptr writeRelation(const Akonadi::Relation &, const QStringList &items, Version v = KolabV3, const QString &productId = QString()); }; } //Namespace #endif // KOLABOBJECT_H libkolab-1.0.2/kolabformat/kolabobject.i000066400000000000000000000010411262531616600202270ustar00rootroot00000000000000%{ /* This macro ensures that return vectors remain a vector also in python and are not converted to tuples */ #define SWIG_PYTHON_EXTRA_NATIVE_CONTAINERS #include "../kolabformat/xmlobject.h" #include "../kolabformat/kolabdefinitions.h" #include "../kolabformat/mimeobject.h" %} %include "std_string.i" %include "std_vector.i" %import(module="kolabformat") %import "../shared.i" %include "../kolabformat/xmlobject.h" %include "../kolabformat/kolabdefinitions.h" %include "../kolabformat/mimeobject.h" libkolab-1.0.2/kolabformat/mimeobject.cpp000066400000000000000000000666111262531616600204360ustar00rootroot00000000000000/* * Copyright (C) 2012 Sofia Balicka * Copyright (C) 2014 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include "mimeobject.h" #include "conversion/kcalconversion.h" #include "conversion/kolabconversion.h" #include "conversion/kabcconversion.h" #include "conversion/commonconversion.h" #include "kolabformat/kolabobject.h" #include "kolabformat/xmlobject.h" #include "kolabformat/errorhandler.h" #include "kolabformat/v2helpers.h" #include "mime/mimeutils.h" #include "libkolab-version.h" #include #include #include #include Q_DECLARE_METATYPE(Kolab::Event); Q_DECLARE_METATYPE(Kolab::Todo); Q_DECLARE_METATYPE(Kolab::Journal); Q_DECLARE_METATYPE(Kolab::Contact); Q_DECLARE_METATYPE(Kolab::DistList); Q_DECLARE_METATYPE(Kolab::Note); Q_DECLARE_METATYPE(Kolab::Freebusy); Q_DECLARE_METATYPE(Kolab::Configuration); static inline std::string eventKolabType() { return std::string(KOLAB_TYPE_EVENT); }; static inline std::string todoKolabType() { return std::string(KOLAB_TYPE_TASK); }; static inline std::string journalKolabType() { return std::string(KOLAB_TYPE_JOURNAL); }; static inline std::string contactKolabType() { return std::string(KOLAB_TYPE_CONTACT); }; static inline std::string distlistKolabType() { return std::string(KOLAB_TYPE_DISTLIST); } static inline std::string distlistKolabTypeCompat() { return std::string(KOLAB_TYPE_DISTLIST_V2); } static inline std::string noteKolabType() { return std::string(KOLAB_TYPE_NOTE); } static inline std::string configurationKolabType() { return std::string(KOLAB_TYPE_CONFIGURATION); } static inline std::string dictKolabType() { return std::string(KOLAB_TYPE_DICT); } static inline std::string freebusyKolabType() { return std::string(KOLAB_TYPE_FREEBUSY); } static inline std::string relationKolabType() { return std::string(KOLAB_TYPE_RELATION); } static inline std::string xCalMimeType() { return std::string(MIME_TYPE_XCAL); }; static inline std::string xCardMimeType() { return std::string(MIME_TYPE_XCARD); }; static inline std::string kolabMimeType() { return std::string(MIME_TYPE_KOLAB); }; static std::string getProductId(const std::string &pId) { if (pId.empty()) { return LIBKOLAB_LIB_VERSION_STRING; } return pId + " " + LIBKOLAB_LIB_VERSION_STRING; } namespace Kolab { static Kolab::ObjectType getObjectType(const std::string &type) { if (type == eventKolabType()) { return EventObject; } else if (type == todoKolabType()) { return TodoObject; } else if (type == journalKolabType()) { return JournalObject; } else if (type == contactKolabType()) { return ContactObject; } else if (type == distlistKolabType() || type == distlistKolabTypeCompat()) { return DistlistObject; } else if (type == noteKolabType()) { return NoteObject; } else if (type == freebusyKolabType()) { return FreebusyObject; } else if (boost::contains(type, dictKolabType())) { //Previous versions appended the language to the type return DictionaryConfigurationObject; } else if (type == relationKolabType()) { return RelationConfigurationObject; } Warning() << "Unknown object type: " << type; return Kolab::InvalidObject; } static QByteArray getTypeString(Kolab::ObjectType type) { switch (type) { case EventObject: return KOLAB_TYPE_EVENT; case TodoObject: return KOLAB_TYPE_TASK; case JournalObject: return KOLAB_TYPE_JOURNAL; case FreebusyObject: return KOLAB_TYPE_FREEBUSY; case ContactObject: return KOLAB_TYPE_CONTACT; case DistlistObject: return KOLAB_TYPE_DISTLIST; case NoteObject: return KOLAB_TYPE_NOTE; case DictionaryConfigurationObject: return KOLAB_TYPE_CONFIGURATION; case RelationConfigurationObject: return KOLAB_TYPE_RELATION; default: Critical() << "unknown type "<< type; } return QByteArray(); } static QByteArray getMimeType(Kolab::ObjectType type) { switch (type) { case EventObject: case TodoObject: case JournalObject: case FreebusyObject: return MIME_TYPE_XCAL; case ContactObject: case DistlistObject: return MIME_TYPE_XCARD; case NoteObject: case DictionaryConfigurationObject: case RelationConfigurationObject: return MIME_TYPE_KOLAB; default: Critical() << "unknown type "<< type; } return QByteArray(); } static Kolab::ObjectType detectType(const KMime::Message::Ptr &msg) { Q_FOREACH(const QByteArray &type, Mime::getContentMimeTypeList(msg)) { Kolab::ObjectType t = getObjectType(type.toStdString()); //works for v2 types if (t != InvalidObject) { return t; } } return InvalidObject; } static void printMessageDebugInfo(const KMime::Message::Ptr &msg) { //TODO replace by Debug stream for Mimemessage Debug() << "MessageId: " << msg->messageID()->asUnicodeString(); Debug() << "Subject: " << msg->subject()->asUnicodeString(); // Debug() << msg->encodedContent(); } //@cond PRIVATE class MIMEObject::Private { public: Private() : mObjectType(InvalidObject), mVersion(KolabV3), mOverrideObjectType(InvalidObject), mDoOverrideVersion(false) { } QVariant readKolabV2(const KMime::Message::Ptr &msg, Kolab::ObjectType objectType); QVariant readKolabV3(const KMime::Message::Ptr &msg, Kolab::ObjectType objectType); QVariant parseMimeMessage(const KMime::Message::Ptr &msg); QVariant parseMimeMessage(const std::string &s); ObjectType mObjectType; Version mVersion; ObjectType mOverrideObjectType; Version mOverrideVersion; bool mDoOverrideVersion; QVariant mObject; }; //@endcond static std::vector getAttachments(const std::vector &attachments, const KMime::Message::Ptr &msg) { std::vector allAttachments; foreach (const Kolab::Attachment &attachment, attachments) { if (!attachment.uri().empty()) { const Kolab::Attachment extracted = Mime::getAttachment(attachment.uri(), msg); if (extracted.isValid()) { allAttachments.push_back(extracted); } } else { allAttachments.push_back(attachment); } } return allAttachments; } static std::vector getAttachments(const QStringList &attachmentNames, const KMime::Message::Ptr &msg) { std::vector allAttachments; foreach (const QString &name, attachmentNames) { const Kolab::Attachment extracted = Mime::getAttachmentByName(name, msg); if (extracted.isValid()) { allAttachments.push_back(extracted); } } return allAttachments; } QVariant MIMEObject::Private::readKolabV2(const KMime::Message::Ptr &msg, Kolab::ObjectType objectType) { if (objectType == DictionaryConfigurationObject) { KMime::Content *xmlContent = Mime::findContentByType(msg, "application/xml"); if (!xmlContent) { Critical() << "no application/xml part found"; printMessageDebugInfo(msg); return InvalidObject; } const QByteArray &xmlData = xmlContent->decodedContent(); QString dictionaryLanguage; const QStringList entries = Kolab::readLegacyDictionaryConfiguration(xmlData, dictionaryLanguage); mObjectType = objectType; Kolab::Dictionary dictionary(Conversion::toStdString(dictionaryLanguage)); std::vector convertedEntries; foreach (const QString &value, entries) { convertedEntries.push_back(Conversion::toStdString(value)); } dictionary.setEntries(convertedEntries); return QVariant::fromValue(Kolab::Configuration(dictionary)); } KMime::Content *xmlContent = Mime::findContentByType(msg, getTypeString(objectType)); if (!xmlContent) { Critical() << "no part with type" << getTypeString(objectType) << " found"; printMessageDebugInfo(msg); return QVariant(); } const QByteArray &xmlData = xmlContent->decodedContent(); Q_ASSERT(!xmlData.isEmpty()); QVariant variant; switch (objectType) { case EventObject: { QStringList attachments; KCalCore::Event::Ptr kEvent = fromXML(xmlData, attachments); Kolab::Event event = Kolab::Conversion::fromKCalCore(*kEvent); event.setAttachments(getAttachments(attachments, msg)); variant = QVariant::fromValue(event); break; } case TodoObject: { QStringList attachments; KCalCore::Todo::Ptr kTodo = fromXML(xmlData, attachments); Kolab::Todo todo = Kolab::Conversion::fromKCalCore(*kTodo); todo.setAttachments(getAttachments(attachments, msg)); variant = QVariant::fromValue(todo); break; } case JournalObject: { QStringList attachments; KCalCore::Journal::Ptr kJournal = fromXML(xmlData, attachments); Kolab::Journal journal = Kolab::Conversion::fromKCalCore(*kJournal); journal.setAttachments(getAttachments(attachments, msg)); variant = QVariant::fromValue(journal); break; } case ContactObject: { KContacts::Addressee kContact= addresseeFromKolab(xmlData, msg); Kolab::Contact contact = Kolab::Conversion::fromKABC(kContact); variant = QVariant::fromValue(contact); break; } case DistlistObject: { KContacts::ContactGroup kContactGroup= contactGroupFromKolab(xmlData); Kolab::DistList distlist = Kolab::Conversion::fromKABC(kContactGroup); variant = QVariant::fromValue(distlist); break; } case NoteObject: { KMime::Message::Ptr kNote = noteFromKolab(xmlData, KDateTime(msg->date()->dateTime())); Kolab::Note note = Kolab::Conversion::fromNote(kNote); variant = QVariant::fromValue(note); break; } default: CRITICAL("no kolab object found "); break; } if (ErrorHandler::errorOccured()) { printMessageDebugInfo(msg); return QVariant(); } mObjectType = objectType; return variant; } QVariant MIMEObject::Private::readKolabV3(const KMime::Message::Ptr &msg, Kolab::ObjectType objectType) { KMime::Content * const xmlContent = Mime::findContentByType(msg, getMimeType(objectType)); if (!xmlContent) { Critical() << "no " << getMimeType(objectType) << " part found"; printMessageDebugInfo(msg); return InvalidObject; } const QByteArray &content = xmlContent->decodedContent(); const std::string xml = std::string(content.data(), content.size()); QVariant variant; switch (objectType) { case EventObject: { Kolab::Event event = Kolab::readEvent(xml, false); event.setAttachments(getAttachments(event.attachments(), msg)); variant = QVariant::fromValue(event); break; } case TodoObject: { Kolab::Todo todo = Kolab::readTodo(xml, false); todo.setAttachments(getAttachments(todo.attachments(), msg)); variant = QVariant::fromValue(todo); break; } case JournalObject: { Kolab::Journal journal = Kolab::readJournal(xml, false); journal.setAttachments(getAttachments(journal.attachments(), msg)); variant = QVariant::fromValue(journal); break; } case ContactObject: variant = QVariant::fromValue(Kolab::readContact(xml, false)); break; case DistlistObject: variant = QVariant::fromValue(Kolab::readDistlist(xml, false)); break; case NoteObject: variant = QVariant::fromValue(Kolab::readNote(xml, false)); break; case FreebusyObject: variant = QVariant::fromValue(Kolab::readFreebusy(xml, false)); break; case DictionaryConfigurationObject: case RelationConfigurationObject: variant = QVariant::fromValue(Kolab::readConfiguration(xml, false)); break; default: Critical() << "no kolab object found "; printMessageDebugInfo(msg); break; } if (ErrorHandler::errorOccured()) { printMessageDebugInfo(msg); return QVariant(); } mObjectType = objectType; return variant; } QVariant MIMEObject::Private::parseMimeMessage(const KMime::Message::Ptr &msg) { ErrorHandler::clearErrors(); mObjectType = InvalidObject; if (msg->contents().isEmpty()) { Critical() << "message has no contents (we likely failed to parse it correctly)"; printMessageDebugInfo(msg); return QVariant(); } Kolab::ObjectType objectType = InvalidObject; if (mOverrideObjectType == InvalidObject) { if (KMime::Headers::Base *xKolabHeader = msg->headerByType(X_KOLAB_TYPE_HEADER)) { objectType = getObjectType(xKolabHeader->asUnicodeString().trimmed().toStdString()); } else { Warning() << "could not find the X-Kolab-Type Header, trying autodetection" ; //This works only for v2 messages atm. objectType = detectType(msg); } } else { objectType = mOverrideObjectType; } if (objectType == InvalidObject) { Critical() << "unable to detect object type"; printMessageDebugInfo(msg); return QVariant(); } if (!mDoOverrideVersion) { KMime::Headers::Base *xKolabVersion = msg->headerByType(X_KOLAB_MIME_VERSION_HEADER); if (!xKolabVersion) { //For backwards compatibility to development versions, can be removed in future versions xKolabVersion = msg->headerByType(X_KOLAB_MIME_VERSION_HEADER_COMPAT); } if (!xKolabVersion || xKolabVersion->asUnicodeString() == KOLAB_VERSION_V2) { mVersion = KolabV2; } else { if (xKolabVersion->asUnicodeString() != KOLAB_VERSION_V3) { //TODO version compatibility check? Warning() << "Kolab Version Header available but not on the same version as the implementation: " << xKolabVersion->asUnicodeString(); } mVersion = KolabV3; } } else { mVersion = mOverrideVersion; } if (mVersion == KolabV2) { return readKolabV2(msg, objectType); } return readKolabV3(msg, objectType); } QVariant MIMEObject::Private::parseMimeMessage(const std::string &s) { KMime::Message::Ptr msg(new KMime::Message); msg->setContent(QByteArray(s.c_str())); msg->parse(); return parseMimeMessage(msg); } MIMEObject::MIMEObject() : d(new MIMEObject::Private) { } void MIMEObject::setObjectType(ObjectType type) { d->mOverrideObjectType = type; } void MIMEObject::setVersion(Version version) { d->mOverrideVersion = version; d->mDoOverrideVersion = true; } static std::string createCid() { return QString::fromLatin1("cid:%1@%2").arg(KRandom::randomString(16)).arg("kolab.resource.akonadi").toStdString(); } std::vector convertToReferences(const std::vector &attachments, std::vector &attachmentCids) { std::vector attachmentsWithReferences; Q_FOREACH (const Kolab::Attachment &a, attachments) { Kolab::Attachment attachment; attachment.setLabel(a.label()); const std::string cid = a.uri().empty() ? createCid() : a.uri(); attachmentCids.push_back(cid); attachment.setUri(cid, a.mimetype()); //Serialize the attachment as attachment with uri, referencing the created mime-part attachmentsWithReferences.push_back(attachment); } return attachmentsWithReferences; } template static T convertAttachmentsToReferences(const T &incidence, std::vector &attachmentCids) { T removedAttachments = incidence; removedAttachments.setAttachments(convertToReferences(incidence.attachments(), attachmentCids)); return removedAttachments; } static void addAttachments(KMime::Message::Ptr msg, const std::vector &attachments, std::vector &attachmentCids) { int index = 0; foreach (const Attachment &attachment, attachments) { const std::string data = attachment.data(); const std::string cid = attachmentCids.empty() ? attachment.uri() : attachmentCids.at(index); msg->addContent(Mime::createAttachmentPart(Mime::fromCid(QByteArray(cid.c_str())).toLatin1(), QByteArray(attachment.mimetype().c_str()), QString::fromStdString(attachment.label()), QByteArray::fromRawData(data.c_str(), data.size()))); index++; } } ObjectType MIMEObject::parseMessage(const std::string &msg) { d->mObject = d->parseMimeMessage(msg); return d->mObjectType; } ObjectType MIMEObject::getType() const { return d->mObjectType; } Version MIMEObject::getVersion() const { return d->mVersion; } Kolab::Event MIMEObject::getEvent() const { return d->mObject.value(); } Kolab::Todo MIMEObject::getTodo() const { return d->mObject.value(); } Kolab::Journal MIMEObject::getJournal() const { return d->mObject.value(); } Kolab::Note MIMEObject::getNote() const { return d->mObject.value(); } Kolab::Contact MIMEObject::getContact() const { return d->mObject.value(); } Kolab::DistList MIMEObject::getDistlist() const { return d->mObject.value(); } Kolab::Freebusy MIMEObject::getFreebusy() const { return d->mObject.value(); } Kolab::Configuration MIMEObject::getConfiguration() const { return d->mObject.value(); } std::string MIMEObject::writeEvent(const Event &event, Version version, const std::string &pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; std::vector attachmentCids; if (version == KolabV3) { const std::string xml = xmlObject.writeEvent(convertAttachmentsToReferences(event, attachmentCids), version, productId); msg = Mime::createMessage(xCalMimeType(), eventKolabType(), xml, true, productId, event.organizer().email(), event.organizer().name(), event.uid()); } else if (version == KolabV2) { const std::string xml = xmlObject.writeEvent(event, version, productId); msg = Mime::createMessage(eventKolabType(), eventKolabType(), xml, false, productId, event.organizer().email(), event.organizer().name(), event.uid()); } addAttachments(msg, event.attachments(), attachmentCids); msg->assemble(); return msg->encodedContent().data(); } Event MIMEObject::readEvent(const std::string &s) { return d->parseMimeMessage(s).value(); } std::string MIMEObject::writeTodo(const Todo &todo, Version version, const std::string &pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; std::vector attachmentCids; if (version == KolabV3) { const std::string xml = xmlObject.writeTodo(convertAttachmentsToReferences(todo, attachmentCids), version, productId); msg = Mime::createMessage(xCalMimeType(), todoKolabType(), xml, true, productId, todo.organizer().email(), todo.organizer().name(), todo.uid()); } else if (version == KolabV2) { const std::string xml = xmlObject.writeTodo(todo, version, productId); msg = Mime::createMessage(todoKolabType(), todoKolabType(), xml, false, productId, todo.organizer().email(), todo.organizer().name(), todo.uid()); } addAttachments(msg, todo.attachments(), attachmentCids); msg->assemble(); return msg->encodedContent().data(); } Todo MIMEObject::readTodo(const std::string &s) { return d->parseMimeMessage(s).value(); } std::string MIMEObject::writeJournal(const Journal &journal, Version version, const std::string &pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; std::vector attachmentCids; if (version == KolabV3) { const std::string xml = xmlObject.writeJournal(convertAttachmentsToReferences(journal, attachmentCids), version, productId); msg = Mime::createMessage(xCalMimeType(), journalKolabType(), xml, true, productId, std::string(), std::string(), journal.uid()); } else if (version == KolabV2) { const std::string xml = xmlObject.writeJournal(journal, version, productId); msg = Mime::createMessage(journalKolabType(), journalKolabType(), xml, false, productId, std::string(), std::string(), journal.uid()); } addAttachments(msg, journal.attachments(), attachmentCids); msg->assemble(); return msg->encodedContent().data(); } Journal MIMEObject::readJournal(const std::string &s){ return d->parseMimeMessage(s).value(); } std::string MIMEObject::writeNote(const Note ¬e, Version version, const std::string &pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; std::vector attachmentCids; if (version == KolabV3) { const std::string xml = xmlObject.writeNote(convertAttachmentsToReferences(note, attachmentCids), version, productId); msg = Mime::createMessage(kolabMimeType(), noteKolabType(), xml, true, productId, std::string(), std::string(), note.uid()); } else if (version == KolabV2) { const std::string xml = xmlObject.writeNote(note, version, productId); msg = Mime::createMessage(noteKolabType(), noteKolabType(), xml, false, productId, std::string(), std::string(), note.uid()); } addAttachments(msg, note.attachments(), attachmentCids); msg->assemble(); return msg->encodedContent().data(); } Note MIMEObject::readNote(const std::string &s){ return d->parseMimeMessage(s).value(); } std::string MIMEObject::writeContact(const Contact &contact, Version version, const std::string &pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; const std::string xml = xmlObject.writeContact(contact, version, productId); Email preferredEmail = !contact.emailAddresses().empty() ? contact.emailAddresses().at(contact.emailAddressPreferredIndex()) : Email(); QPair pair = Conversion::fromMailto(preferredEmail.address()); std::string name = pair.second; std::string email = pair.first; if (name.empty()) { name = contact.name(); } if (version == KolabV3) { msg = Mime::createMessage(xCardMimeType(), contactKolabType(), xml, true, productId, email, name, contact.uid()); } else if (version == KolabV2) { msg = Mime::createMessage(contactKolabType(), contactKolabType(), xml, false, productId, email, name, contact.uid()); } msg->assemble(); return msg->encodedContent().data(); } Contact MIMEObject::readContact(const std::string &s){ return d->parseMimeMessage(s).value(); } std::string MIMEObject::writeDistlist(const DistList &distlist, Version version, const std::string &pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; const std::string xml = xmlObject.writeDistlist(distlist, version, productId); if (version == KolabV3) { msg = Mime::createMessage(xCardMimeType(), distlistKolabType(), xml, true, productId, std::string(), std::string(), distlist.uid()); } else if (version == KolabV2) { msg = Mime::createMessage(distlistKolabType(), distlistKolabType(), xml, false, productId, std::string(), std::string(), distlist.uid()); } msg->assemble(); return msg->encodedContent().data(); } DistList MIMEObject::readDistlist(const std::string &s) { return d->parseMimeMessage(s).value(); } std::string MIMEObject::writeConfiguration(const Configuration &configuration, Version version, const std::string& pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; const std::string xml = xmlObject.writeConfiguration(configuration, version, productId); std::string kolabType; switch (configuration.type()) { case Kolab::Configuration::TypeDictionary: kolabType = dictKolabType(); break; case Kolab::Configuration::TypeRelation: kolabType = relationKolabType(); break; case Kolab::Configuration::TypeSnippet: kolabType = configurationKolabType(); break; case Kolab::Configuration::TypeFileDriver: kolabType = configurationKolabType(); break; case Kolab::Configuration::TypeCategoryColor: kolabType = configurationKolabType(); break; default: break; } if (version == KolabV3) { msg = Mime::createMessage(kolabMimeType(), kolabType, xml, true, productId, std::string(), std::string(), configuration.uid()); } else if (version == KolabV2) { Critical() << "Not available in KolabV2"; } msg->assemble(); return msg->encodedContent().data(); } Configuration MIMEObject::readConfiguration(const std::string &s) { return d->parseMimeMessage(s).value(); } std::string MIMEObject::writeFreebusy(const Freebusy &freebusy, Version version, const std::string& pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; const std::string xml = xmlObject.writeFreebusy(freebusy, version, productId); if (version == KolabV3) { msg = Mime::createMessage(xCalMimeType(), freebusyKolabType(), xml, true, productId, std::string(), std::string(), freebusy.uid()); } else if (version == KolabV2) { Critical() << "Not available in KolabV2"; } msg->assemble(); return msg->encodedContent().data(); } Freebusy MIMEObject::readFreebusy(const std::string &s) { return d->parseMimeMessage(s).value(); } } libkolab-1.0.2/kolabformat/mimeobject.h000066400000000000000000000067631262531616600201050ustar00rootroot00000000000000/* * Copyright (C) 2012 Sofia Balicka * Copyright (C) 2014 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef MIMEOBJECT_H #define MIMEOBJECT_H #ifndef SWIG #include "kolab_export.h" #else /* No export/import SWIG interface files */ #define KOLAB_EXPORT #endif #include #include "kolabdefinitions.h" namespace Kolab { class KOLAB_EXPORT MIMEObject { public: MIMEObject(); ObjectType parseMessage(const std::string &msg); /** * Set to override the autodetected object type, before parsing the message. */ void setObjectType(ObjectType); /** * Set to override the autodetected version, before parsing the message. */ void setVersion(Version); /** * Returns the Object type of the parsed kolab object. */ ObjectType getType() const; /** * Returns the kolab-format version of the parsed kolab object. */ Version getVersion() const; Kolab::Event getEvent() const; Kolab::Todo getTodo() const; Kolab::Journal getJournal() const; Kolab::Note getNote() const; Kolab::Contact getContact() const; Kolab::DistList getDistlist() const; Kolab::Freebusy getFreebusy() const; Kolab::Configuration getConfiguration() const; std::string writeEvent(const Kolab::Event &event, Version version, const std::string &productId = std::string()); Kolab::Event readEvent(const std::string &s); std::string writeTodo(const Kolab::Todo &todo, Version version, const std::string &productId = std::string()); Kolab::Todo readTodo(const std::string &s); std::string writeJournal(const Kolab::Journal &journal, Version version, const std::string &productId = std::string()); Kolab::Journal readJournal(const std::string &s); std::string writeNote(const Kolab::Note ¬e, Version version, const std::string &productId = std::string()); Kolab::Note readNote(const std::string &s); std::string writeContact(const Kolab::Contact &contact, Version version, const std::string &productId = std::string()); Kolab::Contact readContact(const std::string &s); std::string writeDistlist(const Kolab::DistList &distlist, Version version, const std::string &productId = std::string()); Kolab::DistList readDistlist(const std::string &s); std::string writeFreebusy(const Kolab::Freebusy &freebusy, Version version, const std::string &productId = std::string()); Kolab::Freebusy readFreebusy(const std::string &s); std::string writeConfiguration(const Kolab::Configuration &freebusy, Version version, const std::string &productId = std::string()); Kolab::Configuration readConfiguration(const std::string &s); private: //@cond PRIVATE MIMEObject(const MIMEObject &other); MIMEObject &operator=(const MIMEObject &rhs); class Private; Private *const d; //@endcond }; } #endif libkolab-1.0.2/kolabformat/php/000077500000000000000000000000001262531616600163715ustar00rootroot00000000000000libkolab-1.0.2/kolabformat/php/CMakeLists.txt000066400000000000000000000001641262531616600211320ustar00rootroot00000000000000#Generate PHP wrapper include_directories(../) include(SWIGUtils) generatePHPBindings(kolabobject ../kolabobject.i) libkolab-1.0.2/kolabformat/php/test.php000066400000000000000000000050751262531616600200700ustar00rootroot00000000000000setCreated(new cDateTime(2012,3,14, 9,5,30, true)); $e->setStart(new cDateTime(2012,7,31)); $e->setUid("uid"); $e->setPriority(1); $xo = new XMLObject; print $xo->writeEvent($e, kolabobject::KolabV2, "test.php"); print $xo->writeEvent($e, kolabobject::KolabV3, "test.php"); ////// Test Contact $c = new Contact(); $nc = new NameComponents; $sn = new vectors; $sn->push("Contact"); $nc->setSurnames($sn); $gn = new vectors; $gn->push("Sample"); $nc->setGiven($gn); $c->setNameComponents($nc); $c->setName("Sample Contact"); $em = new vectors; $em->push("sample.v2@localhost"); $c->setEmailAddresses($em); $xo = new XMLObject; print $xo->writeContact($c, kolabobject::KolabV2, "test.php"); print "UID = " . $xo->getSerializedUID() . "\n\n"; print $xo->writeContact($c, kolabobject::KolabV3, "test.php"); print "UID = " . $xo->getSerializedUID() . "\n\n"; $dlxml = << ebb1774429a2e03afafb31f233e23b42 2010-11-25T18:02:32Z 2011-07-23T09:06:38Z public Horde::Kolab Another lista Another User other@debian-vm.local a2cfdc52365ef429042413bf7717dc85 Sample A. User Jr. sample@debian-vm.local f538c7e9ad5a63e4452b7db3bc291231 EOL; $xo = new XMLObject; $dl = new DistList($xo->readDistList($dlxml, kolabobject::KolabV2)); echo $dl->uid() . "\n\n"; $ml = $dl->members(); for ($i=0; $i < $ml->size(); $i++) { $m = $ml->get($i); echo "Member [" . $m->type() . "]: " . $m->uid() . "; " . $m->email() . "\n"; } $dl2 = new DistList(); $ml = new vectorcontactref; $m1 = new ContactReference(ContactReference::UidReference, 'some-uid-value'); $ml->push($m1); $m2 = new ContactReference(ContactReference::EmailReference, 'sample@localhost'); $ml->push($m2); $dl2->setMembers($ml); echo $xo->writeDistList($dl2, kolabobject::KolabV2); echo $xo->writeDistList($dl2, kolabobject::KolabV3); ?> libkolab-1.0.2/kolabformat/python/000077500000000000000000000000001262531616600171235ustar00rootroot00000000000000libkolab-1.0.2/kolabformat/python/CMakeLists.txt000066400000000000000000000001421262531616600216600ustar00rootroot00000000000000include_directories(../) include(SWIGUtils) generatePythonBindings(kolabobject ../kolabobject.i) libkolab-1.0.2/kolabformat/v2helpers.cpp000066400000000000000000000247351262531616600202330ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include "v2helpers.h" #include "kolabdefinitions.h" #include "kolabformatV2/kolabbase.h" #include "kolabformatV2/journal.h" #include "kolabformatV2/task.h" #include "kolabformatV2/event.h" #include "kolabformatV2/contact.h" #include "kolabformatV2/distributionlist.h" #include "kolabformatV2/note.h" #include "mime/mimeutils.h" #include "kolabformat/errorhandler.h" #include #include #include #include #include namespace Kolab { void getAttachments(KCalCore::Incidence::Ptr incidence, const QStringList &attachments, const KMime::Message::Ptr &mimeData) { if (!incidence) { Error() << "Invalid incidence"; return; } foreach (const QString &name, attachments) { QByteArray type; KMime::Content *content = Mime::findContentByName(mimeData, name, type); if (!content) { // guard against malformed events with non-existent attachments Warning() << "could not find attachment: "<< name.toUtf8() << type; continue; } const QByteArray c = content->decodedContent().toBase64(); KCalCore::Attachment::Ptr attachment( new KCalCore::Attachment( c, QString::fromLatin1( type ) ) ); attachment->setLabel( name ); incidence->addAttachment(attachment); Debug() << "ATTACHMENT NAME" << name << type; } } static QImage getPicture(const QString &pictureAttachmentName, const KMime::Message::Ptr &data, QByteArray &type) { if (!data) { Critical() << "empty message"; return QImage(); } KMime::Content *imgContent = Mime::findContentByName(data, pictureAttachmentName/*"kolab-picture.png"*/, type); if (!imgContent) { Warning() << "could not find picture: " << pictureAttachmentName; return QImage(); } QByteArray imgData = imgContent->decodedContent(); QBuffer buffer(&imgData); buffer.open(QIODevice::ReadOnly); QImage image; bool success = false; if (type == "image/jpeg") { success = image.load(&buffer, "JPEG"); //FIXME I tried getting the code to interpret the picture as PNG, but the VCard implementation writes it as JPEG anyways... // if (success) { // QByteArray pic; // QBuffer b(&pic); // b.open(QIODevice::ReadWrite); // Q_ASSERT(image.save(&b, "PNG")); // b.close(); // Debug() << pic.toBase64(); // QBuffer b2(&pic); // b2.open(QIODevice::ReadOnly); // success = image.load(&b2, "PNG"); // b2.close(); // Q_ASSERT(success); // } } else { type = "image/png"; success = image.load(&buffer, "PNG"); } buffer.close(); if (!success) { Warning() << "failed to load picture"; } return image; } KContacts::Addressee addresseeFromKolab( const QByteArray &xmlData, const KMime::Message::Ptr &data) { if (!data) { Critical() << "empty message"; return KContacts::Addressee(); } KContacts::Addressee addressee; // Debug() << "xmlData " << xmlData; KolabV2::Contact contact(QString::fromUtf8(xmlData)); QByteArray type; const QString &pictureAttachmentName = contact.pictureAttachmentName(); if (!pictureAttachmentName.isEmpty()) { const QImage &img = getPicture(pictureAttachmentName, data, type); contact.setPicture(img, type); } const QString &logoAttachmentName = contact.logoAttachmentName(); if (!logoAttachmentName.isEmpty()) { contact.setLogo(getPicture(logoAttachmentName, data, type), type); } const QString &soundAttachmentName = contact.soundAttachmentName(); if (!soundAttachmentName.isEmpty()) { QByteArray type; KMime::Content *content = Mime::findContentByName(data, soundAttachmentName/*"sound"*/, type); if (content) { const QByteArray &sData = content->decodedContent(); contact.setSound(sData); } else { Warning() << "could not find sound: " << soundAttachmentName; } } contact.saveTo(&addressee); return addressee; } KContacts::Addressee addresseeFromKolab(const QByteArray &xmlData, QString &pictureAttachmentName, QString &logoAttachmentName, QString &soundAttachmentName) { KContacts::Addressee addressee; KolabV2::Contact contact(QString::fromUtf8(xmlData)); pictureAttachmentName = contact.pictureAttachmentName(); logoAttachmentName = contact.logoAttachmentName(); soundAttachmentName = contact.soundAttachmentName(); contact.saveTo(&addressee); return addressee; } static QByteArray createPicture(const QImage &img, const QString &/*format*/, QString &type) { QByteArray pic; QBuffer buffer(&pic); buffer.open(QIODevice::WriteOnly); type = "image/png"; //FIXME it's not possible to save jpegs lossless, so we always use png. otherwise we would compress the image on every write. // if (format == "image/jpeg") { // type = "image/jpeg"; // img.save(&buffer, "JPEG"); // } else { img.save(&buffer, "PNG"); // } buffer.close(); return pic; } KMime::Message::Ptr contactToKolabFormat(const KolabV2::Contact& contact, const QString &productId) { KMime::Message::Ptr message = Mime::createMessage( QByteArray(KOLAB_TYPE_CONTACT), false, productId.toLatin1() ); if (!message) { Critical() << "empty message"; return KMime::Message::Ptr(); } message->subject()->fromUnicodeString( contact.uid(), "utf-8" ); message->from()->fromUnicodeString( contact.fullEmail(), "utf-8" ); KMime::Content* content = Mime::createMainPart( KOLAB_TYPE_CONTACT, contact.saveXML().toUtf8() ); message->addContent( content ); if ( !contact.picture().isNull() ) { QString type; const QByteArray &pic = createPicture(contact.picture(), contact.pictureFormat(), type); content = Mime::createAttachmentPart(QByteArray(), type.toLatin1(), /*"kolab-picture.png"*/contact.pictureAttachmentName(), pic ); message->addContent(content); } if ( !contact.logo().isNull() ) { QString type; const QByteArray &pic = createPicture(contact.logo(), contact.logoFormat(), type); content = Mime::createAttachmentPart(QByteArray(), type.toLatin1(), /*"kolab-logo.png"*/contact.logoAttachmentName(), pic ); message->addContent(content); } if ( !contact.sound().isEmpty() ) { content = Mime::createAttachmentPart(QByteArray(), "audio/unknown", /*"sound"*/contact.soundAttachmentName(), contact.sound() ); message->addContent(content); } message->assemble(); return message; } KContacts::ContactGroup contactGroupFromKolab(const QByteArray &xmlData) { KContacts::ContactGroup contactGroup; // qDebug() << "xmlData " << xmlData; KolabV2::DistributionList distList(QString::fromUtf8(xmlData)); distList.saveTo(&contactGroup); return contactGroup; } KMime::Message::Ptr distListToKolabFormat(const KolabV2::DistributionList& distList, const QString &productId) { KMime::Message::Ptr message = Mime::createMessage( KOLAB_TYPE_DISTLIST_V2, false, productId.toLatin1() ); if (!message) { Critical() << "empty message"; return KMime::Message::Ptr(); } message->subject()->fromUnicodeString( distList.uid(), "utf-8" ); message->from()->fromUnicodeString( distList.uid(), "utf-8" ); KMime::Content* content = Mime::createMainPart( KOLAB_TYPE_DISTLIST_V2, distList.saveXML().toUtf8() ); message->addContent( content ); message->assemble(); return message; } KMime::Message::Ptr noteFromKolab(const QByteArray &xmlData, const KDateTime &creationDate) { KolabV2::Note j; if ( !j.load( xmlData ) ) { Warning() << "failed to read note"; return KMime::Message::Ptr(); } Akonadi::NoteUtils::NoteMessageWrapper note; note.setTitle(j.summary()); note.setText(j.body().toUtf8()); note.setFrom("kolab@kde4"); note.setCreationDate(creationDate.dateTime()); return note.message(); } KMime::Message::Ptr noteToKolab(const KMime::Message::Ptr& msg, const QString &productId) { if (!msg) { Critical() << "empty message"; return KMime::Message::Ptr(); } Akonadi::NoteUtils::NoteMessageWrapper note(msg); return Mime::createMessage(note.title(), KOLAB_TYPE_NOTE, KOLAB_TYPE_NOTE, noteToKolabXML(msg), false, productId); } QByteArray noteToKolabXML(const KMime::Message::Ptr& msg) { if (!msg) { Critical() << "empty message"; return QByteArray(); } Akonadi::NoteUtils::NoteMessageWrapper note(msg); KolabV2::Note j; j.setSummary( note.title() ); j.setBody( note.text() ); return j.saveXML().toUtf8(); } QStringList readLegacyDictionaryConfiguration(const QByteArray &xmlData, QString &language) { QStringList dictionary; const QDomDocument xmlDoc = KolabV2::KolabBase::loadDocument( QString::fromUtf8(xmlData) ); //TODO extract function from V2 format if ( xmlDoc.isNull() ) { Error() << "Failed to read the xml document"; return QStringList(); } QDomElement top = xmlDoc.documentElement(); if ( top.tagName() != "configuration" ) { qWarning( "XML error: Top tag was %s instead of the expected configuration", top.tagName().toAscii().data() ); return QStringList(); } for ( QDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling() ) { if ( n.isComment() || !n.isElement() ) continue; QDomElement e = n.toElement(); if (e.tagName() == "language") { language = e.text(); } else if (e.tagName() == "e") { dictionary.append(e.text()); } } return dictionary; } } libkolab-1.0.2/kolabformat/v2helpers.h000066400000000000000000000074661262531616600177020ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef V2HELPERS_H #define V2HELPERS_H #include "kolabdefinitions.h" #include "kolabformatV2/kolabbase.h" #include "kolabformatV2/journal.h" #include "kolabformatV2/task.h" #include "kolabformatV2/event.h" #include "kolabformatV2/contact.h" #include "kolabformatV2/distributionlist.h" #include "kolabformatV2/note.h" #include "mime/mimeutils.h" #include "kolabformat/errorhandler.h" #include #include #include #include #include #include #include #include #include namespace Kolab { /* * Parse XML, create KCalCore container and extract attachments */ template static KCalPtr fromXML(const QByteArray &xmlData, QStringList &attachments) { const QDomDocument xmlDoc = KolabV2::KolabBase::loadDocument( QString::fromUtf8(xmlData) ); //TODO extract function from V2 format if ( xmlDoc.isNull() ) { Critical() << "Failed to read the xml document"; return KCalPtr(); } const KCalPtr i = Container::fromXml( xmlDoc, QString() ); //For parsing we don't need the timezone, so we don't set one Q_ASSERT ( i ); QDomNodeList nodes = xmlDoc.elementsByTagName("inline-attachment"); for (int i = 0; i < nodes.size(); i++ ) { attachments.append(nodes.at(i).toElement().text()); } return i; } void getAttachments(KCalCore::Incidence::Ptr incidence, const QStringList &attachments, const KMime::Message::Ptr &mimeData); template static inline IncidencePtr incidenceFromKolabImpl( const KMime::Message::Ptr &data, const QByteArray &mimetype, const QString &timezoneId ) { KMime::Content *xmlContent = Mime::findContentByType( data, mimetype ); if ( !xmlContent ) { Critical() << "couldn't find part"; return IncidencePtr(); } const QByteArray &xmlData = xmlContent->decodedContent(); QStringList attachments; IncidencePtr ptr = fromXML(xmlData, attachments); //TODO do we care about timezone? getAttachments(ptr, attachments, data); return ptr; } KContacts::Addressee addresseeFromKolab( const QByteArray &xmlData, const KMime::Message::Ptr &data); KContacts::Addressee addresseeFromKolab( const QByteArray &xmlData, QString &pictureAttachmentName, QString &logoAttachmentName, QString &soundAttachmentName); KMime::Message::Ptr contactToKolabFormat(const KolabV2::Contact& contact, const QString &productId); KContacts::ContactGroup contactGroupFromKolab(const QByteArray &xmlData); KMime::Message::Ptr distListToKolabFormat(const KolabV2::DistributionList& distList, const QString &productId); KMime::Message::Ptr noteFromKolab(const QByteArray &xmlData, const KDateTime &creationDate); KMime::Message::Ptr noteToKolab(const KMime::Message::Ptr& msg, const QString &productId); QByteArray noteToKolabXML(const KMime::Message::Ptr& msg); QStringList readLegacyDictionaryConfiguration(const QByteArray &xmlData, QString &language); } #endif libkolab-1.0.2/kolabformat/xmlobject.cpp000066400000000000000000000315511262531616600203020ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include "xmlobject.h" #include "v2helpers.h" #include "kolabformatV2/event.h" #include "conversion/kcalconversion.h" #include "conversion/kolabconversion.h" #include "conversion/commonconversion.h" #include "conversion/kabcconversion.h" #include namespace Kolab { static QString createUuid() { const QString uuid = QUuid::createUuid().toString(); return uuid.mid(1, uuid.size()-2); } XMLObject::XMLObject() { } std::string XMLObject::getSerializedUID() const { return mWrittenUID; } std::vector XMLObject::getAttachments() const { return mAttachments; } std::string XMLObject::writeEvent(const Event &event, Version version, const std::string& productId) { mWrittenUID.clear(); if (version == KolabV2) { const KCalCore::Event::Ptr i = Conversion::toKCalCore(event); if (!i) { Critical() << "invalid incidence"; return std::string(); } if (i->uid().isEmpty()) { i->setUid(createUuid()); } mWrittenUID = Conversion::toStdString(i->uid()); //The timezone is used for created and last modified dates const QString &xml = KolabV2::Event::eventToXML(i, QLatin1String("UTC")); return Conversion::toStdString(xml); } const std::string result = Kolab::writeEvent(event, productId); mWrittenUID = Kolab::getSerializedUID(); ErrorHandler::handleLibkolabxmlErrors(); return result; } Event XMLObject::readEvent(const std::string& s, Version version) { if (version == KolabV2) { QStringList attachments; const KCalCore::Event::Ptr event = Kolab::fromXML(QString::fromUtf8(s.c_str()).toUtf8(), attachments); if (!event || Kolab::ErrorHandler::errorOccured()) { Critical() << "failed to read xml"; return Event(); } mAttachments.clear(); foreach (const QString &attachment, attachments) { mAttachments.push_back(Conversion::toStdString(attachment)); } return Conversion::fromKCalCore(*event); } const Kolab::Event event = Kolab::readEvent(s, false); ErrorHandler::handleLibkolabxmlErrors(); return event; } std::string XMLObject::writeTodo(const Todo &event, Version version, const std::string& productId) { mWrittenUID.clear(); if (version == KolabV2) { const KCalCore::Todo::Ptr i = Conversion::toKCalCore(event); if (!i) { Critical() << "invalid incidence"; return std::string(); } if (i->uid().isEmpty()) { i->setUid(createUuid()); } mWrittenUID = Conversion::toStdString(i->uid()); //The timezone is used for created and last modified dates const QString &xml = KolabV2::Task::taskToXML(i, QLatin1String("UTC")); return Conversion::toStdString(xml); } const std::string result = Kolab::writeTodo(event, productId); mWrittenUID = Kolab::getSerializedUID(); ErrorHandler::handleLibkolabxmlErrors(); return result; } Todo XMLObject::readTodo(const std::string& s, Version version) { if (version == KolabV2) { QStringList attachments; const KCalCore::Todo::Ptr event = Kolab::fromXML(QString::fromUtf8(s.c_str()).toUtf8(), attachments); if (!event || Kolab::ErrorHandler::errorOccured()) { Error() << "failed to read xml"; return Todo(); } mAttachments.clear(); foreach (const QString &attachment, attachments) { mAttachments.push_back(Conversion::toStdString(attachment)); } return Conversion::fromKCalCore(*event); } const Kolab::Todo todo = Kolab::readTodo(s, false); ErrorHandler::handleLibkolabxmlErrors(); return todo; } std::string XMLObject::writeJournal(const Journal &event, Version version, const std::string& productId) { mWrittenUID.clear(); if (version == KolabV2) { const KCalCore::Journal::Ptr i = Conversion::toKCalCore(event); if (!i) { Critical() << "invalid journal"; return std::string(); } if (i->uid().isEmpty()) { i->setUid(createUuid()); } mWrittenUID = Conversion::toStdString(i->uid()); //The timezone is used for created and last modified dates const QString &xml = KolabV2::Journal::journalToXML(i, QLatin1String("UTC")); return Conversion::toStdString(xml); } const std::string result = Kolab::writeJournal(event, productId); mWrittenUID = Kolab::getSerializedUID(); return result; } Journal XMLObject::readJournal(const std::string& s, Version version) { if (version == KolabV2) { QStringList attachments; const KCalCore::Journal::Ptr event = Kolab::fromXML(QString::fromUtf8(s.c_str()).toUtf8(), attachments); if (!event || Kolab::ErrorHandler::errorOccured()) { Critical() << "failed to read xml"; return Journal(); } mAttachments.clear(); foreach (const QString &attachment, attachments) { mAttachments.push_back(Conversion::toStdString(attachment)); } return Conversion::fromKCalCore(*event); } const Kolab::Journal journal = Kolab::readJournal(s, false); ErrorHandler::handleLibkolabxmlErrors(); return journal; } std::string XMLObject::writeFreebusy(const Freebusy &event, Version version, const std::string& productId) { mWrittenUID.clear(); if (version != KolabV3) { Critical() << "only v3 implementation available"; return std::string(); } const std::string result = Kolab::writeFreebusy(event, productId); mWrittenUID = Kolab::getSerializedUID(); return result; } Freebusy XMLObject::readFreebusy(const std::string& s, Version version) { if (version != KolabV3) { Critical() << "only v3 implementation available"; return Freebusy(); } return Kolab::readFreebusy(s, false); } std::string XMLObject::logoAttachmentName() const { return mLogoAttachmentName; } std::string XMLObject::pictureAttachmentName() const { return mPictureAttachmentName; } std::string XMLObject::soundAttachmentName() const { return mSoundAttachmentName; } Contact XMLObject::readContact(const std::string& s, Version version) { if (version == KolabV2) { const QByteArray xmlData(s.c_str(), s.size()); QString pictureAttachmentName; QString logoAttachmentName; QString soundAttachmentName; const KContacts::Addressee addressee = addresseeFromKolab(xmlData, pictureAttachmentName, logoAttachmentName, soundAttachmentName); mPictureAttachmentName = Conversion::toStdString(pictureAttachmentName); mLogoAttachmentName = Conversion::toStdString(logoAttachmentName); mSoundAttachmentName = Conversion::toStdString(soundAttachmentName); return Conversion::fromKABC(addressee); } const Kolab::Contact contact = Kolab::readContact(s, false); ErrorHandler::handleLibkolabxmlErrors(); return contact; } std::string XMLObject::writeContact(const Contact &contact, Version version, const std::string& productId) { mWrittenUID.clear(); if (version == KolabV2) { //FIXME attachment names are hardcoded for now KContacts::Addressee addressee = Conversion::toKABC(contact); if (addressee.uid().isEmpty()) { addressee.setUid(createUuid()); } mWrittenUID = Conversion::toStdString(addressee.uid()); const KolabV2::Contact contact(&addressee); return Conversion::toStdString(contact.saveXML()); } const std::string result = Kolab::writeContact(contact, productId); mWrittenUID = Kolab::getSerializedUID(); ErrorHandler::handleLibkolabxmlErrors(); return result; } DistList XMLObject::readDistlist(const std::string& s, Version version) { if (version == KolabV2) { const QByteArray xmlData(s.c_str(), s.size()); const KContacts::ContactGroup contactGroup = contactGroupFromKolab(xmlData); return Conversion::fromKABC(contactGroup); } const Kolab::DistList distlist = Kolab::readDistlist(s, false); ErrorHandler::handleLibkolabxmlErrors(); return distlist; } std::string XMLObject::writeDistlist(const DistList &distlist, Version version, const std::string& productId) { mWrittenUID.clear(); if (version == KolabV2) { KContacts::ContactGroup contactGroup = Conversion::toKABC(distlist); if (contactGroup.id().isEmpty()) { contactGroup.setId(createUuid()); } mWrittenUID = Conversion::toStdString(contactGroup.id()); const KolabV2::DistributionList d(&contactGroup); return Conversion::toStdString(d.saveXML()); } const std::string result = Kolab::writeDistlist(distlist, productId); mWrittenUID = Kolab::getSerializedUID(); ErrorHandler::handleLibkolabxmlErrors(); return result; } Note XMLObject::readNote(const std::string& s, Version version) { if (version == KolabV2) { const KMime::Message::Ptr msg = noteFromKolab(QByteArray(s.c_str(), s.length()), KDateTime()); if (!msg || Kolab::ErrorHandler::errorOccured()) { Critical() << "failed to read xml"; return Note(); } return Conversion::fromNote(msg); } const Kolab::Note note = Kolab::readNote(s, false); ErrorHandler::handleLibkolabxmlErrors(); return note; } std::string XMLObject::writeNote(const Note ¬e, Version version, const std::string& productId) { mWrittenUID.clear(); if (version == KolabV2) { Note noteWithUID = note; if (noteWithUID.uid().empty()) { noteWithUID.setUid(Conversion::toStdString(createUuid())); } mWrittenUID = noteWithUID.uid(); const KMime::Message::Ptr n = Conversion::toNote(noteWithUID); const QByteArray &xml = noteToKolabXML(n); return std::string(xml.constData()); } const std::string result = Kolab::writeNote(note, productId); mWrittenUID = Kolab::getSerializedUID(); ErrorHandler::handleLibkolabxmlErrors(); return result; } Configuration XMLObject::readConfiguration(const std::string& s, Version version) { if (version == KolabV2) { QString lang; const QStringList dict = readLegacyDictionaryConfiguration(QByteArray(s.c_str(), s.length()), lang); if (lang.isEmpty()) { Critical() << "not a dictionary or not a v2 configuration object"; return Kolab::Configuration(); } std::vector entries; foreach (const QString e, dict) { entries.push_back(Conversion::toStdString(e)); } Kolab::Dictionary dictionary(Conversion::toStdString(lang)); dictionary.setEntries(entries); return Configuration(dictionary); } const Kolab::Configuration configuration = Kolab::readConfiguration(s, false); ErrorHandler::handleLibkolabxmlErrors(); return configuration; } std::string XMLObject::writeConfiguration(const Configuration &configuration, Version version, const std::string& productId) { mWrittenUID.clear(); if (version != KolabV3) { Critical() << "only v3 implementation available"; return std::string(); } const std::string result = Kolab::writeConfiguration(configuration, productId); mWrittenUID = Kolab::getSerializedUID(); ErrorHandler::handleLibkolabxmlErrors(); return result; } File XMLObject::readFile(const std::string& s, Version version) { if (version == KolabV2) { Critical() << "only v3 implementation available"; return File(); } const Kolab::File file = Kolab::readFile(s, false); ErrorHandler::handleLibkolabxmlErrors(); return file; } std::string XMLObject::writeFile(const File &file, Version version, const std::string& productId) { mWrittenUID.clear(); if (version != KolabV3) { Critical() << "only v3 implementation available"; return std::string(); } const std::string result = Kolab::writeFile(file, productId); mWrittenUID = Kolab::getSerializedUID(); ErrorHandler::handleLibkolabxmlErrors(); return result; } }; libkolab-1.0.2/kolabformat/xmlobject.h000066400000000000000000000076271262531616600177560ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #ifndef KOLABXMLOBJECT_H #define KOLABXMLOBJECT_H #ifndef SWIG #include "kolab_export.h" #else /* No export/import SWIG interface files */ #define KOLAB_EXPORT #endif #include #include "kolabdefinitions.h" namespace Kolab { class KOLAB_EXPORT XMLObject { public: XMLObject(); std::string getSerializedUID() const; ///List of attachment names to be retrieved from the mime message (only when reading v2, for v3 attachments containing the cid: of the attachment-part are created ) std::vector getAttachments() const; Kolab::Event readEvent(const std::string& s, Kolab::Version version); std::string writeEvent(const Kolab::Event &, Kolab::Version version, const std::string& productId = std::string()); Kolab::Todo readTodo(const std::string& s, Kolab::Version version); std::string writeTodo(const Kolab::Todo &, Kolab::Version version, const std::string& productId = std::string()); Kolab::Journal readJournal(const std::string& s, Kolab::Version version); std::string writeJournal(const Kolab::Journal &, Kolab::Version version, const std::string& productId = std::string()); Kolab::Freebusy readFreebusy(const std::string& s, Kolab::Version version); std::string writeFreebusy(const Kolab::Freebusy &, Kolab::Version version, const std::string& productId = std::string()); std::string pictureAttachmentName() const; std::string logoAttachmentName() const; std::string soundAttachmentName() const; /** * Find the attachments and set them on the read Contact object. * * V2 Notes: * Picture, logo and sound must be retrieved from Mime Message attachments using they're corresponding attachment name. */ Kolab::Contact readContact(const std::string& s, Kolab::Version version); /** * V2 Notes: * * Uses the following attachment names: * ** kolab-picture.png * ** kolab-logo.png * ** sound */ std::string writeContact(const Kolab::Contact &, Kolab::Version version, const std::string& productId = std::string()); Kolab::DistList readDistlist(const std::string& s, Kolab::Version version); std::string writeDistlist(const Kolab::DistList &, Kolab::Version version, const std::string& productId = std::string()); /** * V2 notes: * * set the creation date from the mime date header. */ Kolab::Note readNote(const std::string& s, Kolab::Version version); std::string writeNote(const Kolab::Note &, Kolab::Version version, const std::string& productId = std::string()); Kolab::Configuration readConfiguration(const std::string& s, Kolab::Version version); std::string writeConfiguration(const Kolab::Configuration &, Kolab::Version version, const std::string& productId = std::string()); Kolab::File readFile(const std::string& s, Kolab::Version version); std::string writeFile(const Kolab::File &, Kolab::Version version, const std::string& productId = std::string()); private: std::vector mAttachments; std::string mLogoAttachmentName; std::string mSoundAttachmentName; std::string mPictureAttachmentName; std::string mWrittenUID; }; } #endif // KOLABXMLOBJECT_H libkolab-1.0.2/kolabformatV2/000077500000000000000000000000001262531616600160125ustar00rootroot00000000000000libkolab-1.0.2/kolabformatV2/CMakeLists.txt000066400000000000000000000006501262531616600205530ustar00rootroot00000000000000 set( kolabformatv2_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/kolabbase.cpp ${CMAKE_CURRENT_SOURCE_DIR}/contact.cpp ${CMAKE_CURRENT_SOURCE_DIR}/distributionlist.cpp ${CMAKE_CURRENT_SOURCE_DIR}/event.cpp ${CMAKE_CURRENT_SOURCE_DIR}/task.cpp ${CMAKE_CURRENT_SOURCE_DIR}/journal.cpp ${CMAKE_CURRENT_SOURCE_DIR}/incidence.cpp ${CMAKE_CURRENT_SOURCE_DIR}/note.cpp # kolabformatv2.cpp PARENT_SCOPE) libkolab-1.0.2/kolabformatV2/contact.cpp000066400000000000000000001046461262531616600201640ustar00rootroot00000000000000/* This file is part of libkabc and/or kaddressbook. Copyright (c) 2004 Klarälvdalens Datakonsult AB 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. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "contact.h" #include #include #include #include using namespace KolabV2; static const char* s_pictureAttachmentName = "kolab-picture.png"; static const char* s_logoAttachmentName = "kolab-logo.png"; static const char* s_soundAttachmentName = "sound"; static const char* s_unhandledTagAppName = "KOLABUNHANDLED"; // no hyphens in appnames! // saving (addressee->xml) Contact::Contact( const KContacts::Addressee* addr ) : mHasGeo( false ) { setFields( addr ); } // loading (xml->addressee) Contact::Contact( const QString& xml ) : mHasGeo( false ) { load( xml ); } Contact::~Contact() { } void Contact::setGivenName( const QString& name ) { mGivenName = name; } QString Contact::givenName() const { return mGivenName; } void Contact::setMiddleNames( const QString& names ) { mMiddleNames = names; } QString Contact::middleNames() const { return mMiddleNames; } void Contact::setLastName( const QString& name ) { mLastName = name; } QString Contact::lastName() const { return mLastName; } void Contact::setFullName( const QString& name ) { mFullName = name; } QString Contact::fullName() const { return mFullName; } void Contact::setInitials( const QString& initials ) { mInitials = initials; } QString Contact::initials() const { return mInitials; } void Contact::setPrefix( const QString& prefix ) { mPrefix = prefix; } QString Contact::prefix() const { return mPrefix; } void Contact::setSuffix( const QString& suffix ) { mSuffix = suffix; } QString Contact::suffix() const { return mSuffix; } void Contact::setRole( const QString& role ) { mRole = role; } QString Contact::role() const { return mRole; } void Contact::setFreeBusyUrl( const QString& fbUrl ) { mFreeBusyUrl = fbUrl; } QString Contact::freeBusyUrl() const { return mFreeBusyUrl; } void Contact::setOrganization( const QString& organization ) { mOrganization = organization; } QString Contact::organization() const { return mOrganization; } void Contact::setWebPage( const QString& url ) { mWebPage = url; } QString Contact::webPage() const { return mWebPage; } void Contact::setIMAddress( const QString& imAddress ) { mIMAddress = imAddress; } QString Contact::imAddress() const { return mIMAddress; } void Contact::setDepartment( const QString& department ) { mDepartment = department; } QString Contact::department() const { return mDepartment; } void Contact::setOfficeLocation( const QString& location ) { mOfficeLocation = location; } QString Contact::officeLocation() const { return mOfficeLocation; } void Contact::setProfession( const QString& profession ) { mProfession = profession; } QString Contact::profession() const { return mProfession; } void Contact::setTitle( const QString& title ) { mTitle = title; } QString Contact::title() const { return mTitle; } void Contact::setManagerName( const QString& name ) { mManagerName = name; } QString Contact::managerName() const { return mManagerName; } void Contact::setAssistant( const QString& name ) { mAssistant = name; } QString Contact::assistant() const { return mAssistant; } void Contact::setNickName( const QString& name ) { mNickName = name; } QString Contact::nickName() const { return mNickName; } void Contact::setSpouseName( const QString& name ) { mSpouseName = name; } QString Contact::spouseName() const { return mSpouseName; } void Contact::setBirthday( const QDate& date ) { mBirthday = date; } QDate Contact::birthday() const { return mBirthday; } void Contact::setAnniversary( const QDate& date ) { mAnniversary = date; } QDate Contact::anniversary() const { return mAnniversary; } void Contact::setChildren( const QString& children ) { mChildren = children; } QString Contact::children() const { return mChildren; } void Contact::setGender( const QString& gender ) { mGender = gender; } QString Contact::gender() const { return mGender; } void Contact::setLanguage( const QString& language ) { mLanguage = language; } QString Contact::language() const { return mLanguage; } void Contact::addPhoneNumber( const PhoneNumber& number ) { mPhoneNumbers.append( number ); } QList& Contact::phoneNumbers() { return mPhoneNumbers; } const QList& Contact::phoneNumbers() const { return mPhoneNumbers; } void Contact::addEmail( const Email& email ) { mEmails.append( email ); } QList& Contact::emails() { return mEmails; } QString Contact::fullEmail() const { return mFullEmail; } const QList& Contact::emails() const { return mEmails; } void Contact::addAddress( const Contact::Address& address ) { mAddresses.append( address ); } QList& Contact::addresses() { return mAddresses; } const QList& Contact::addresses() const { return mAddresses; } void Contact::setPreferredAddress( const QString& address ) { mPreferredAddress = address; } QString Contact::preferredAddress() const { return mPreferredAddress; } bool Contact::loadNameAttribute( QDomElement& element ) { for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) { if ( n.isComment() ) continue; if ( n.isElement() ) { QDomElement e = n.toElement(); QString tagName = e.tagName(); if ( tagName == "given-name" ) setGivenName( e.text() ); else if ( tagName == "middle-names" ) setMiddleNames( e.text() ); else if ( tagName == "last-name" ) setLastName( e.text() ); else if ( tagName == "full-name" ) setFullName( e.text() ); else if ( tagName == "initials" ) setInitials( e.text() ); else if ( tagName == "prefix" ) setPrefix( e.text() ); else if ( tagName == "suffix" ) setSuffix( e.text() ); else // TODO: Unhandled tag - save for later storage qDebug() <<"Warning: Unhandled tag" << e.tagName(); } else qDebug() <<"Node is not a comment or an element???"; } return true; } void Contact::saveNameAttribute( QDomElement& element ) const { QDomElement e = element.ownerDocument().createElement( "name" ); element.appendChild( e ); writeString( e, "given-name", givenName() ); writeString( e, "middle-names", middleNames() ); writeString( e, "last-name", lastName() ); writeString( e, "full-name", fullName() ); writeString( e, "initials", initials() ); writeString( e, "prefix", prefix() ); writeString( e, "suffix", suffix() ); } bool Contact::loadPhoneAttribute( QDomElement& element ) { PhoneNumber number; for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) { if ( n.isComment() ) continue; if ( n.isElement() ) { QDomElement e = n.toElement(); QString tagName = e.tagName(); if ( tagName == "type" ) number.type = e.text(); else if ( tagName == "number" ) number.number = e.text(); else // TODO: Unhandled tag - save for later storage qDebug() <<"Warning: Unhandled tag" << e.tagName(); } else qDebug() <<"Node is not a comment or an element???"; } addPhoneNumber( number ); return true; } void Contact::savePhoneAttributes( QDomElement& element ) const { QList::ConstIterator it = mPhoneNumbers.constBegin(); for ( ; it != mPhoneNumbers.constEnd(); ++it ) { QDomElement e = element.ownerDocument().createElement( "phone" ); element.appendChild( e ); const PhoneNumber& p = *it; writeString( e, "type", p.type ); writeString( e, "number", p.number ); } } void Contact::saveEmailAttributes( QDomElement& element ) const { QList::ConstIterator it = mEmails.constBegin(); for ( ; it != mEmails.constEnd(); ++it ) saveEmailAttribute( element, *it ); } void Contact::loadCustomAttributes( QDomElement& element ) { Custom custom; custom.app = element.attribute( "app" ); custom.name = element.attribute( "name" ); custom.value = element.attribute( "value" ); mCustomList.append( custom ); } void Contact::saveCustomAttributes( QDomElement& element ) const { QList::ConstIterator it = mCustomList.constBegin(); for ( ; it != mCustomList.constEnd(); ++it ) { Q_ASSERT( !(*it).name.isEmpty() ); if ( (*it).app == s_unhandledTagAppName ) { writeString( element, (*it).name, (*it).value ); } else { // Let's use attributes so that other tag-preserving-code doesn't need sub-elements QDomElement e = element.ownerDocument().createElement( "x-custom" ); element.appendChild( e ); e.setAttribute( "app", (*it).app ); e.setAttribute( "name", (*it).name ); e.setAttribute( "value", (*it).value ); } } } bool Contact::loadAddressAttribute( QDomElement& element ) { Address address; for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) { if ( n.isComment() ) continue; if ( n.isElement() ) { QDomElement e = n.toElement(); QString tagName = e.tagName(); if ( tagName == "type" ) address.type = e.text(); else if ( tagName == "x-kde-type" ) address.kdeAddressType = e.text().toInt(); else if ( tagName == "street" ) address.street = e.text(); else if ( tagName == "pobox" ) address.pobox = e.text(); else if ( tagName == "locality" ) address.locality = e.text(); else if ( tagName == "region" ) address.region = e.text(); else if ( tagName == "postal-code" ) address.postalCode = e.text(); else if ( tagName == "country" ) address.country = e.text(); else // TODO: Unhandled tag - save for later storage qDebug() <<"Warning: Unhandled tag" << e.tagName(); } else qDebug() <<"Node is not a comment or an element???"; } addAddress( address ); return true; } void Contact::saveAddressAttributes( QDomElement& element ) const { QList
::ConstIterator it = mAddresses.constBegin(); for ( ; it != mAddresses.constEnd(); ++it ) { QDomElement e = element.ownerDocument().createElement( "address" ); element.appendChild( e ); const Address& a = *it; writeString( e, "type", a.type ); writeString( e, "x-kde-type", QString::number( a.kdeAddressType ) ); if ( !a.street.isEmpty() ) writeString( e, "street", a.street ); if ( !a.pobox.isEmpty() ) writeString( e, "pobox", a.pobox ); if ( !a.locality.isEmpty() ) writeString( e, "locality", a.locality ); if ( !a.region.isEmpty() ) writeString( e, "region", a.region ); if ( !a.postalCode.isEmpty() ) writeString( e, "postal-code", a.postalCode ); if ( !a.country.isEmpty() ) writeString( e, "country", a.country ); } } bool Contact::loadAttribute( QDomElement& element ) { const QString tagName = element.tagName(); switch ( tagName[0].toLatin1() ) { case 'a': if ( tagName == "address" ) return loadAddressAttribute( element ); if ( tagName == "assistant" ) { setAssistant( element.text() ); return true; } if ( tagName == "anniversary" ) { if ( !element.text().isEmpty() ) setAnniversary( stringToDate( element.text() ) ); return true; } break; case 'b': if ( tagName == "birthday" ) { if ( !element.text().isEmpty() ) setBirthday( stringToDate( element.text() ) ); return true; } break; case 'c': if ( tagName == "children" ) { setChildren( element.text() ); return true; } break; case 'd': if ( tagName == "department" ) { setDepartment( element.text() ); return true; } break; case 'e': if ( tagName == "email" ) { Email email; if ( loadEmailAttribute( element, email ) ) { addEmail( email ); return true; } else return false; } break; case 'f': if ( tagName == "free-busy-url" ) { setFreeBusyUrl( element.text() ); return true; } break; case 'g': if ( tagName == "gender" ) { setGender( element.text() ); return true; } break; case 'i': if ( tagName == "im-address" ) { setIMAddress( element.text() ); return true; } break; case 'j': if ( tagName == "job-title" ) { // see saveAttributes: is mapped to the Role field setTitle( element.text() ); return true; } break; case 'l': if ( tagName == "language" ) { setLanguage( element.text() ); return true; } if ( tagName == "latitude" ) { setLatitude( element.text().toFloat() ); mHasGeo = true; return true; } if ( tagName == "longitude" ) { setLongitude( element.text().toFloat() ); mHasGeo = true; } break; case 'm': if ( tagName == "manager-name" ) { setManagerName( element.text() ); return true; } case 'n': if ( tagName == "name" ) return loadNameAttribute( element ); if ( tagName == "nick-name" ) { setNickName( element.text() ); return true; } break; case 'o': if ( tagName == "organization" ) { setOrganization( element.text() ); return true; } if ( tagName == "office-location" ) { setOfficeLocation( element.text() ); return true; } break; case 'p': if ( tagName == "profession" ) { setProfession( element.text() ); return true; } if ( tagName == "picture" ) { mPictureAttachmentName = element.text(); return true; } if ( tagName == "phone" ) { return loadPhoneAttribute( element ); return true; } if ( tagName == "preferred-address" ) { setPreferredAddress( element.text() ); return true; } break; case 'r': if ( tagName == "role" ) { setRole( element.text() ); return true; } break; case 's': if ( tagName == "spouse-name" ) { setSpouseName( element.text() ); return true; } break; case 'x': if ( tagName == "x-logo" ) { mLogoAttachmentName = element.text(); return true; } if ( tagName == "x-sound" ) { mSoundAttachmentName = element.text(); return true; } if ( tagName == "x-custom" ) { loadCustomAttributes( element ); return true; } if ( tagName == "x-title" ) { setTitle( element.text() ); return true; } break; case 'w': if ( tagName == "web-page" ) { setWebPage( element.text() ); return true; } break; default: break; } return KolabBase::loadAttribute( element ); } bool Contact::saveAttributes( QDomElement& element ) const { // Save the base class elements KolabBase::saveAttributes( element ); saveNameAttribute( element ); writeString( element, "free-busy-url", freeBusyUrl() ); writeString( element, "organization", organization() ); writeString( element, "web-page", webPage() ); writeString( element, "im-address", imAddress() ); writeString( element, "department", department() ); writeString( element, "office-location", officeLocation() ); writeString( element, "profession", profession() ); writeString( element, "role", role() ); writeString( element, "job-title", title() ); writeString( element, "manager-name", managerName() ); writeString( element, "assistant", assistant() ); writeString( element, "nick-name", nickName() ); writeString( element, "spouse-name", spouseName() ); writeString( element, "birthday", dateToString( birthday() ) ); writeString( element, "anniversary", dateToString( anniversary() ) ); if ( !picture().isNull() ) writeString( element, "picture", mPictureAttachmentName ); if ( !logo().isNull() ) writeString( element, "x-logo", mLogoAttachmentName ); if ( !sound().isNull() ) writeString( element, "x-sound", mSoundAttachmentName ); writeString( element, "children", children() ); writeString( element, "gender", gender() ); writeString( element, "language", language() ); savePhoneAttributes( element ); saveEmailAttributes( element ); saveAddressAttributes( element ); writeString( element, "preferred-address", preferredAddress() ); if ( mHasGeo ) { writeString( element, "latitude", QString::number( latitude(), 'g', DBL_DIG ) ); writeString( element, "longitude", QString::number( longitude(), 'g', DBL_DIG ) ); } saveCustomAttributes( element ); return true; } bool Contact::loadXML( const QDomDocument& document ) { QDomElement top = document.documentElement(); if ( top.tagName() != "contact" ) { qWarning( "XML error: Top tag was %s instead of the expected contact", top.tagName().toAscii().data() ); return false; } for ( QDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling() ) { if ( n.isComment() ) continue; if ( n.isElement() ) { QDomElement e = n.toElement(); if ( !loadAttribute( e ) ) { // Unhandled tag - save for later storage //qDebug() <<"Saving unhandled tag" << e.tagName(); Custom c; c.app = s_unhandledTagAppName; c.name = e.tagName(); c.value = e.text(); mCustomList.append( c ); } } else qDebug() <<"Node is not a comment or an element???"; } return true; } QString Contact::saveXML() const { QDomDocument document = domTree(); QDomElement element = document.createElement("contact" ); element.setAttribute( "version", "1.0" ); saveAttributes( element ); document.appendChild( element ); return document.toString(); } static QString addressTypeToString( int /*KContacts::Address::Type*/ type ) { if ( type & KContacts::Address::Home ) return "home"; if ( type & KContacts::Address::Work ) return "business"; return "other"; } static int addressTypeFromString( const QString& type ) { if ( type == "home" ) return KContacts::Address::Home; if ( type == "business" ) return KContacts::Address::Work; // well, this shows "other" in the editor, which is what we want... return KContacts::Address::Dom | KContacts::Address::Intl | KContacts::Address::Postal | KContacts::Address::Parcel; } static QStringList phoneTypeToString( KContacts::PhoneNumber::Type type ) { // KABC has a bitfield, i.e. the same phone number can be used for work and home // and fax and cellphone etc. etc. // So when saving we need to create as many tags as bits that were set. QStringList types; if ( type & KContacts::PhoneNumber::Fax ) { if ( type & KContacts::PhoneNumber::Home ) types << "homefax"; else // assume work -- if ( type & KContacts::PhoneNumber::Work ) types << "businessfax"; type = type & ~KContacts::PhoneNumber::Home; type = type & ~KContacts::PhoneNumber::Work; } // To support both "home1" and "home2", map Home+Pref to home1 if ( ( type & KContacts::PhoneNumber::Home ) && ( type & KContacts::PhoneNumber::Pref ) ) { types << "home1"; type = type & ~KContacts::PhoneNumber::Home; type = type & ~KContacts::PhoneNumber::Pref; } // To support both "business1" and "business2", map Work+Pref to business1 if ( ( type & KContacts::PhoneNumber::Work ) && ( type & KContacts::PhoneNumber::Pref ) ) { types << "business1"; type = type & ~KContacts::PhoneNumber::Work; type = type & ~KContacts::PhoneNumber::Pref; } if ( type & KContacts::PhoneNumber::Home ) types << "home2"; if ( type & KContacts::PhoneNumber::Msg ) // Msg==messaging types << "company"; if ( type & KContacts::PhoneNumber::Work ) types << "business2"; if ( type & KContacts::PhoneNumber::Pref ) types << "primary"; if ( type & KContacts::PhoneNumber::Voice ) types << "callback"; // ## if ( type & KContacts::PhoneNumber::Cell ) types << "mobile"; if ( type & KContacts::PhoneNumber::Video ) types << "radio"; // ## if ( type & KContacts::PhoneNumber::Bbs ) types << "ttytdd"; if ( type & KContacts::PhoneNumber::Modem ) types << "telex"; // # if ( type & KContacts::PhoneNumber::Car ) types << "car"; if ( type & KContacts::PhoneNumber::Isdn ) types << "isdn"; if ( type & KContacts::PhoneNumber::Pcs ) types << "assistant"; // ## Assistant is e.g. secretary if ( type & KContacts::PhoneNumber::Pager ) types << "pager"; return types; } static KContacts::PhoneNumber::Type phoneTypeFromString( const QString& type ) { if ( type == "homefax" ) return KContacts::PhoneNumber::Home | KContacts::PhoneNumber::Fax; if ( type == "businessfax" ) return KContacts::PhoneNumber::Work | KContacts::PhoneNumber::Fax; if ( type == "business1" ) return KContacts::PhoneNumber::Work | KContacts::PhoneNumber::Pref; if ( type == "business2" ) return KContacts::PhoneNumber::Work; if ( type == "home1" ) return KContacts::PhoneNumber::Home | KContacts::PhoneNumber::Pref; if ( type == "home2" ) return KContacts::PhoneNumber::Home; if ( type == "company" ) return KContacts::PhoneNumber::Msg; if ( type == "primary" ) return KContacts::PhoneNumber::Pref; if ( type == "callback" ) return KContacts::PhoneNumber::Voice; if ( type == "mobile" ) return KContacts::PhoneNumber::Cell; if ( type == "radio" ) return KContacts::PhoneNumber::Video; if ( type == "ttytdd" ) return KContacts::PhoneNumber::Bbs; if ( type == "telex" ) return KContacts::PhoneNumber::Modem; if ( type == "car" ) return KContacts::PhoneNumber::Car; if ( type == "isdn" ) return KContacts::PhoneNumber::Isdn; if ( type == "assistant" ) return KContacts::PhoneNumber::Pcs; if ( type == "pager" ) return KContacts::PhoneNumber::Pager; return KContacts::PhoneNumber::Home; // whatever } static const char* s_knownCustomFields[] = { "X-IMAddress", "X-Office", "X-Profession", "X-ManagersName", "X-AssistantsName", "X-SpousesName", "X-Anniversary", "DistributionList", 0 }; // The saving is addressee -> Contact -> xml, this is the first part void Contact::setFields( const KContacts::Addressee* addressee ) { KolabBase::setFields( addressee ); setGivenName( addressee->givenName() ); setMiddleNames( addressee->additionalName() ); setLastName( addressee->familyName() ); setFullName( addressee->formattedName() ); setPrefix( addressee->prefix() ); setSuffix( addressee->suffix() ); setOrganization( addressee->organization() ); setWebPage( addressee->url().url().url() ); setIMAddress( addressee->custom( "KADDRESSBOOK", "X-IMAddress" ) ); setDepartment( addressee->department()); setOfficeLocation( addressee->custom( "KADDRESSBOOK", "X-Office" ) ); setProfession( addressee->custom( "KADDRESSBOOK", "X-Profession" ) ); setRole( addressee->role() ); setTitle( addressee->title() ); setManagerName( addressee->custom( "KADDRESSBOOK", "X-ManagersName" ) ); setAssistant( addressee->custom( "KADDRESSBOOK", "X-AssistantsName" ) ); setNickName( addressee->nickName() ); setSpouseName( addressee->custom( "KADDRESSBOOK", "X-SpousesName" ) ); if ( !addressee->birthday().isNull() ) setBirthday( addressee->birthday().date() ); const QString& anniversary = addressee->custom( "KADDRESSBOOK", "X-Anniversary" ); if ( !anniversary.isEmpty() ) setAnniversary( stringToDate( anniversary ) ); const QStringList emails = addressee->emails(); // Conversion problem here: // KContacts::Addressee has only one full name and N addresses, but the XML format // has N times (fullname+address). So we just copy the fullname over and ignore it on loading. for ( QStringList::ConstIterator it = emails.constBegin(); it != emails.constEnd(); ++it ) { Email email; email.displayName = fullName(); email.smtpAddress = *it; addEmail( email ); } // save formatted full email for later usage mFullEmail = addressee->fullEmail(); // Now the real-world addresses QString preferredAddress = "home"; const KContacts::Address::List addresses = addressee->addresses(); for ( KContacts::Address::List::ConstIterator it = addresses.constBegin() ; it != addresses.constEnd(); ++it ) { Address address; address.kdeAddressType = (*it).type(); address.type = addressTypeToString( address.kdeAddressType ); address.street = (*it).street(); address.pobox = (*it).postOfficeBox(); address.locality = (*it).locality(); address.region = (*it).region(); address.postalCode = (*it).postalCode(); address.country = (*it).country(); // ## TODO not in the XML format: extended address info. // ## KDE-specific tags? Or hiding those fields? Or adding a warning? addAddress( address ); if ( address.kdeAddressType & KContacts::Address::Pref ) { preferredAddress = address.type; // home, business or other } } setPreferredAddress( preferredAddress ); const KContacts::PhoneNumber::List phones = addressee->phoneNumbers(); for ( KContacts::PhoneNumber::List::ConstIterator it = phones.constBegin(); it != phones.constEnd(); ++it ) { // Create a tag per phone type set in the bitfield QStringList types = phoneTypeToString( (*it).type() ); for( QStringList::ConstIterator typit = types.constBegin(); typit != types.constEnd(); ++typit ) { PhoneNumber phoneNumber; phoneNumber.type = *typit; phoneNumber.number = (*it).number(); addPhoneNumber( phoneNumber ); } } setPicture( loadPictureFromAddressee( addressee->photo() ), addressee->photo().type() ); mPictureAttachmentName = addressee->custom( "KOLAB", "PictureAttachmentName" ); if ( mPictureAttachmentName.isEmpty() ) mPictureAttachmentName = s_pictureAttachmentName; setLogo( loadPictureFromAddressee( addressee->logo() ), addressee->logo().type() ); mLogoAttachmentName = addressee->custom( "KOLAB", "LogoAttachmentName" ); if ( mLogoAttachmentName.isEmpty() ) mLogoAttachmentName = s_logoAttachmentName; setSound( loadSoundFromAddressee( addressee->sound() ) ); mSoundAttachmentName = addressee->custom( "KOLAB", "SoundAttachmentName" ); if ( mSoundAttachmentName.isEmpty() ) mSoundAttachmentName = s_soundAttachmentName; if ( addressee->geo().isValid() ) { setLatitude( addressee->geo().latitude() ); setLongitude( addressee->geo().longitude() ); mHasGeo = true; } // Other KADDRESSBOOK custom fields than those already handled // (includes e.g. crypto settings, and extra im addresses) QStringList knownCustoms; for ( const char** p = s_knownCustomFields; *p; ++p ) knownCustoms << QString::fromLatin1( *p ); QStringList customs = addressee->customs(); for( QStringList::ConstIterator it = customs.constBegin(); it != customs.constEnd(); ++it ) { // KContacts::Addressee doesn't offer a real way to iterate over customs, other than splitting strings ourselves // The format is "app-name:value". int pos = (*it).indexOf( '-' ); if ( pos == -1 ) continue; QString app = (*it).left( pos ); if ( app == "KOLAB" ) continue; QString name = (*it).mid( pos + 1 ); pos = name.indexOf( ':' ); if ( pos == -1 ) continue; QString value = name.mid( pos + 1 ); name = name.left( pos ); if ( !knownCustoms.contains( name ) ) { //qDebug() <<"app=" << app <<" name=" << name <<" value=" << value; Custom c; if ( app != "KADDRESSBOOK" ) // that's the default c.app = app; c.name = name; c.value = value; mCustomList.append( c ); } } const QString url = addressee->custom("KOLAB", "FreebusyUrl"); if ( !url.isEmpty() ) { setFreeBusyUrl( url ); } // Those fields, although defined in Addressee, are not used in KDE // (e.g. not visible in kaddressbook/addresseeeditorwidget.cpp) // So it doesn't matter much if we don't have them in the XML. // mailer, timezone, productId, sortString, agent, rfc2426 name() // Things KAddressBook can't handle, so they are saved as unhandled tags: // initials, children, gender, language } // The loading is: xml -> Contact -> addressee, this is the second part void Contact::saveTo( KContacts::Addressee* addressee ) { // TODO: This needs the same set of TODOs as the setFields method KolabBase::saveTo( addressee ); KContacts::ResourceLocatorUrl url; url.setUrl(QUrl(webPage())); addressee->setGivenName( givenName() ); addressee->setAdditionalName( middleNames() ); addressee->setFamilyName( lastName() ); addressee->setFormattedName( fullName() ); addressee->setPrefix( prefix() ); addressee->setSuffix( suffix() ); addressee->setOrganization( organization() ); addressee->setUrl(url); addressee->insertCustom( "KADDRESSBOOK", "X-IMAddress", imAddress() ); addressee->setDepartment( department() ); addressee->insertCustom( "KADDRESSBOOK", "X-Office", officeLocation() ); addressee->insertCustom( "KADDRESSBOOK", "X-Profession", profession() ); addressee->setRole( role() ); addressee->setTitle( title() ); addressee->insertCustom( "KADDRESSBOOK", "X-ManagersName", managerName() ); addressee->insertCustom( "KADDRESSBOOK", "X-AssistantsName", assistant() ); addressee->setNickName( nickName() ); addressee->insertCustom( "KADDRESSBOOK", "X-SpousesName", spouseName() ); if ( birthday().isValid() ) addressee->setBirthday( QDateTime( birthday() ) ); if ( anniversary().isValid() ) addressee->insertCustom( "KADDRESSBOOK", "X-Anniversary", dateToString( anniversary() ) ); else addressee->removeCustom( "KADDRESSBOOK", "X-Anniversary" ); addressee->insertCustom( "KOLAB", "FreebusyUrl", freeBusyUrl() ); // We need to store both the original attachment name and the picture data into the addressee. // This is important, otherwise we would save the image under another attachment name w/o deleting the original one! if ( !mPicture.isNull() ) { KContacts::Picture picture( mPicture ); addressee->setPhoto( picture ); } // Note that we must save the filename in all cases, so that removing the picture // actually deletes the attachment. addressee->insertCustom( "KOLAB", "PictureAttachmentName", mPictureAttachmentName ); if ( !mLogo.isNull() ) { KContacts::Picture picture( mLogo ); addressee->setLogo( picture ); } addressee->insertCustom( "KOLAB", "LogoAttachmentName", mLogoAttachmentName ); if ( !mSound.isNull() ) addressee->setSound( KContacts::Sound( mSound ) ); addressee->insertCustom( "KOLAB", "SoundAttachmentName", mSoundAttachmentName ); if ( mHasGeo ) addressee->setGeo( KContacts::Geo( mLatitude, mLongitude ) ); QStringList emailAddresses; for ( QList::ConstIterator it = mEmails.constBegin(); it != mEmails.constEnd(); ++it ) { // we can't do anything with (*it).displayName emailAddresses.append( (*it).smtpAddress ); } addressee->setEmails( emailAddresses ); for ( QList
::ConstIterator it = mAddresses.constBegin(); it != mAddresses.constEnd(); ++it ) { KContacts::Address address; int type = (*it).kdeAddressType; if ( type == -1 ) { // no kde-specific type available type = addressTypeFromString( (*it).type ); if ( (*it).type == mPreferredAddress ) type |= KContacts::Address::Pref; } address.setType( static_cast(type) ); address.setStreet( (*it).street ); address.setPostOfficeBox( (*it).pobox ); address.setLocality( (*it).locality ); address.setRegion( (*it).region ); address.setPostalCode( (*it).postalCode ); address.setCountry( (*it).country ); addressee->insertAddress( address ); } for ( QList::ConstIterator it = mPhoneNumbers.constBegin(); it != mPhoneNumbers.constEnd(); ++it ) { KContacts::PhoneNumber number; number.setType( phoneTypeFromString( (*it).type ) ); number.setNumber( (*it).number ); addressee->insertPhoneNumber( number ); } for( QList::ConstIterator it = mCustomList.constBegin(); it != mCustomList.constEnd(); ++it ) { QString app = (*it).app.isEmpty() ? QString::fromLatin1( "KADDRESSBOOK" ) : (*it).app; addressee->insertCustom( app, (*it).name, (*it).value ); } //qDebug() << addressee->customs(); } QImage Contact::loadPictureFromAddressee( const KContacts::Picture& picture ) { QImage img; if ( !picture.isIntern() && !picture.url().isEmpty() ) { QString tmpFile; qWarning() << "external pictures are currently not supported"; //FIXME add kio support to libcalendaring or use libcurl // if ( KIO::NetAccess::download( picture.url(), tmpFile, 0 /*no widget known*/ ) ) { // img.load( tmpFile ); // KIO::NetAccess::removeTempFile( tmpFile ); // } } else img = picture.data(); return img; } QByteArray KolabV2::Contact::loadSoundFromAddressee( const KContacts::Sound& sound ) { QByteArray data; if ( !sound.isIntern() && !sound.url().isEmpty() ) { QString tmpFile; // if ( KIO::NetAccess::download( sound.url(), tmpFile, 0 /*no widget known*/ ) ) { // QFile f( tmpFile ); // if ( f.open( QIODevice::ReadOnly ) ) { // data = f.readAll(); // f.close(); // } // KIO::NetAccess::removeTempFile( tmpFile ); // } } else data = sound.data(); return data; } QString KolabV2::Contact::productID() const { // TODO: When KAB has the version number in a header file, don't hardcode (Bo) // Or we could use Addressee::productID? (David) return "KAddressBook 3.3, Kolab resource"; } libkolab-1.0.2/kolabformatV2/contact.h000066400000000000000000000174261262531616600176300ustar00rootroot00000000000000/* This file is part of libkabc and/or kaddressbook. Copyright (c) 2002 - 2004 Klarälvdalens Datakonsult AB 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. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef KOLABV2CONTACT_H #define KOLABV2CONTACT_H #include "kolabbase.h" #include namespace KContacts { class Addressee; class Picture; class Sound; } namespace KolabV2 { class Contact : public KolabBase { public: struct PhoneNumber { public: QString type; QString number; }; struct Address { public: Address() : kdeAddressType( -1 ) { } int kdeAddressType; // KContacts::Address::Type QString type; // kolab-compliant address type: home, work or other QString street; QString pobox; QString locality; QString region; QString postalCode; QString country; }; explicit Contact( const KContacts::Addressee* address ); Contact( const QString& xml ); ~Contact(); void saveTo( KContacts::Addressee* address ); QString type() const { return "Contact"; } void setGivenName( const QString& name ); QString givenName() const; void setMiddleNames( const QString& names ); QString middleNames() const; void setLastName( const QString& name ); QString lastName() const; void setFullName( const QString& name ); QString fullName() const; void setInitials( const QString& initials ); QString initials() const; void setPrefix( const QString& prefix ); QString prefix() const; void setSuffix( const QString& suffix ); QString suffix() const; void setRole( const QString& role ); QString role() const; void setFreeBusyUrl( const QString& fbUrl ); QString freeBusyUrl() const; void setOrganization( const QString& organization ); QString organization() const; void setWebPage( const QString& url ); QString webPage() const; void setIMAddress( const QString& imAddress ); QString imAddress() const; void setDepartment( const QString& department ); QString department() const; void setOfficeLocation( const QString& location ); QString officeLocation() const; void setProfession( const QString& profession ); QString profession() const; void setTitle( const QString& title ); QString title() const; void setManagerName( const QString& name ); QString managerName() const; void setAssistant( const QString& name ); QString assistant() const; void setNickName( const QString& name ); QString nickName() const; void setSpouseName( const QString& name ); QString spouseName() const; void setBirthday( const QDate& date ); QDate birthday() const; void setAnniversary( const QDate& date ); QDate anniversary() const; void setPicture( const QImage& image, const QString &format) { mPicture = image; mPictureFormat = format; } QString pictureAttachmentName() const { return mPictureAttachmentName; } QString pictureFormat() const { return mPictureFormat; } QImage picture() const { return mPicture; } void setLogo( const QImage& image, const QString &format ) { mLogo = image; mLogoFormat = format; } QString logoAttachmentName() const { return mLogoAttachmentName; } QString logoFormat() const { return mLogoFormat; } QImage logo() const { return mLogo; } void setSound( const QByteArray& sound ) { mSound = sound; } QString soundAttachmentName() const { return mSoundAttachmentName; } QByteArray sound() const { return mSound; } void setChildren( const QString& children ); QString children() const; void setGender( const QString& gender ); QString gender() const; void setLanguage( const QString& language ); QString language() const; void addPhoneNumber( const PhoneNumber& number ); QList& phoneNumbers(); const QList& phoneNumbers() const; void addEmail( const Email& email ); QList& emails(); const QList& emails() const; QString fullEmail() const; void addAddress( const Address& address ); QList
& addresses(); const QList
& addresses() const; // which address is preferred: home or business or other void setPreferredAddress( const QString& address ); QString preferredAddress() const; float latitude() const { return mLatitude; } void setLatitude( float latitude ) { mLatitude = latitude; } float longitude() const { return mLongitude; } void setLongitude( float longitude ) { mLongitude = longitude; } // Load the attributes of this class bool loadAttribute( QDomElement& ); // Save the attributes of this class bool saveAttributes( QDomElement& ) const; // Load this note by reading the XML file bool loadXML( const QDomDocument& xml ); // Serialize this note to an XML string QString saveXML() const; protected: void setFields( const KContacts::Addressee* ); private: bool loadNameAttribute( QDomElement& element ); void saveNameAttribute( QDomElement& element ) const; bool loadPhoneAttribute( QDomElement& element ); void savePhoneAttributes( QDomElement& element ) const; void saveEmailAttributes( QDomElement& element ) const; bool loadAddressAttribute( QDomElement& element ); void saveAddressAttributes( QDomElement& element ) const; void loadCustomAttributes( QDomElement& element ); void saveCustomAttributes( QDomElement& element ) const; QImage loadPictureFromAddressee( const KContacts::Picture& picture ); QByteArray loadSoundFromAddressee( const KContacts::Sound& sound ); QString productID() const; QString mGivenName; QString mMiddleNames; QString mLastName; QString mFullName; QString mInitials; QString mPrefix; QString mSuffix; QString mRole; QString mFreeBusyUrl; QString mOrganization; QString mWebPage; QString mIMAddress; QString mDepartment; QString mOfficeLocation; QString mProfession; QString mTitle; QString mManagerName; QString mAssistant; QString mNickName; QString mSpouseName; QDate mBirthday; QDate mAnniversary; QImage mPicture; QString mPictureFormat; QImage mLogo; QString mLogoFormat; QByteArray mSound; QString mPictureAttachmentName; QString mLogoAttachmentName; QString mSoundAttachmentName; QString mChildren; QString mGender; QString mLanguage; QList mPhoneNumbers; QList mEmails; QString mFullEmail; QList
mAddresses; QString mPreferredAddress; float mLatitude; float mLongitude; bool mHasGeo; struct Custom { QString app; QString name; QString value; }; QList mCustomList; }; } #endif // KOLABCONTACT_H libkolab-1.0.2/kolabformatV2/distributionlist.cpp000066400000000000000000000154721262531616600221420ustar00rootroot00000000000000/* This file is part of Akonadi KolabProxy. Copyright (c) 2009 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. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "distributionlist.h" #include #include #include using namespace KolabV2; static const char* s_unhandledTagAppName = "KOLABUNHANDLED"; // no hyphens in appnames! // saving (contactgroup->xml) DistributionList::DistributionList( const KContacts::ContactGroup* contactGroup ) { setFields( contactGroup ); } // loading (xml->contactgroup) DistributionList::DistributionList( const QString& xml ) { load( xml ); } DistributionList::~DistributionList() { } void DistributionList::setName( const QString& name ) { mName = name; } QString DistributionList::name() const { return mName; } void KolabV2::DistributionList::loadDistrListMember( const QDomElement& element ) { Member member; for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) { if ( n.isComment() ) continue; if ( n.isElement() ) { QDomElement e = n.toElement(); QString tagName = e.tagName(); if ( tagName == "display-name" ) member.displayName = e.text(); else if ( tagName == "smtp-address" ) member.email = e.text(); else if ( tagName == "uid" ) member.uid = e.text(); } } mDistrListMembers.append( member ); } void DistributionList::saveDistrListMembers( QDomElement& element ) const { QList::ConstIterator it = mDistrListMembers.constBegin(); for( ; it != mDistrListMembers.constEnd(); ++it ) { QDomElement e = element.ownerDocument().createElement( "member" ); element.appendChild( e ); const Member& m = *it; if (!m.uid.isEmpty()) { writeString( e, "uid", m.uid ); } else { writeString( e, "display-name", m.displayName ); writeString( e, "smtp-address", m.email ); } } } bool DistributionList::loadAttribute( QDomElement& element ) { const QString tagName = element.tagName(); switch ( tagName[0].toLatin1() ) { case 'd': if ( tagName == "display-name" ) { setName( element.text() ); return true; } break; case 'm': if ( tagName == "member" ) { loadDistrListMember( element ); return true; } break; default: break; } return KolabBase::loadAttribute( element ); } bool DistributionList::saveAttributes( QDomElement& element ) const { // Save the base class elements KolabBase::saveAttributes( element ); writeString( element, "display-name", name() ); saveDistrListMembers( element ); return true; } bool DistributionList::loadXML( const QDomDocument& document ) { QDomElement top = document.documentElement(); if ( top.tagName() != "distribution-list" ) { qWarning( "XML error: Top tag was %s instead of the expected distribution-list", top.tagName().toAscii().data() ); return false; } for ( QDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling() ) { if ( n.isComment() ) continue; if ( n.isElement() ) { QDomElement e = n.toElement(); if ( !loadAttribute( e ) ) { // Unhandled tag - save for later storage //qDebug() <<"Saving unhandled tag" << e.tagName(); Custom c; c.app = s_unhandledTagAppName; c.name = e.tagName(); c.value = e.text(); mCustomList.append( c ); } } else qDebug() <<"Node is not a comment or an element???"; } return true; } QString DistributionList::saveXML() const { QDomDocument document = domTree(); QDomElement element = document.createElement( "distribution-list" ); element.setAttribute( "version", "1.0" ); saveAttributes( element ); document.appendChild( element ); return document.toString(); } QString DistributionList::productID() const { // TODO should we get name/version from desktop file? return QLatin1String( "Akonadi Kolab Proxy" ); } // The saving is contactgroup -> DistributionList -> xml, this is the first part void DistributionList::setFields( const KContacts::ContactGroup* contactGroup ) { KolabBase::setFields( contactGroup ); setName( contactGroup->name() ); // explicit contact data for ( uint index = 0; index < contactGroup->dataCount(); ++index ) { const KContacts::ContactGroup::Data& data = contactGroup->data( index ); Member m; m.displayName = data.name(); m.email = data.email(); mDistrListMembers.append( m ); } for ( uint index = 0; index < contactGroup->contactReferenceCount(); ++index ) { const KContacts::ContactGroup::ContactReference& data = contactGroup->contactReference( index ); Member m; m.uid = data.uid(); mDistrListMembers.append( m ); } if (contactGroup->contactGroupReferenceCount() > 0) { qWarning() << "Tried to save contact group references, which should have been resolved already"; } } // The loading is: xml -> DistributionList -> contactgroup, this is the second part void DistributionList::saveTo( KContacts::ContactGroup* contactGroup ) { KolabBase::saveTo( contactGroup ); contactGroup->setName( name() ); QList::ConstIterator mit = mDistrListMembers.constBegin(); for ( ; mit != mDistrListMembers.constEnd(); ++mit ) { if (!(*mit).uid.isEmpty()) { contactGroup->append(KContacts::ContactGroup::ContactReference( (*mit).uid )); } else { contactGroup->append(KContacts::ContactGroup::Data( (*mit).displayName, (*mit).email )); } } } // kate: space-indent on; indent-width 2; replace-tabs on; libkolab-1.0.2/kolabformatV2/distributionlist.h000066400000000000000000000055601262531616600216040ustar00rootroot00000000000000/* This file is part of Akonadi KolabProxy Copyright (c) 2009 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. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef KOLABV2DISTRIBUTIONLIST_H #define KOLABV2DISTRIBUTIONLIST_H #include "kolabbase.h" namespace KContacts { class ContactGroup; } namespace KolabV2 { class DistributionList : public KolabBase { public: explicit DistributionList( const KContacts::ContactGroup* contactGroup ); DistributionList( const QString& xml ); ~DistributionList(); void saveTo( KContacts::ContactGroup* contactGroup ); QString type() const { return "DistributionList"; } void setName( const QString& name ); QString name() const; // Load the attributes of this class bool loadAttribute( QDomElement& ); // Save the attributes of this class bool saveAttributes( QDomElement& ) const; // Load this note by reading the XML file bool loadXML( const QDomDocument& xml ); // Serialize this note to an XML string QString saveXML() const; QString productID() const; protected: void setFields( const KContacts::ContactGroup* ); private: void loadDistrListMember( const QDomElement& element ); void saveDistrListMembers( QDomElement& element ) const; QString mName; struct Custom { QString app; QString name; QString value; }; QList mCustomList; struct Member { QString displayName; QString email; QString uid; }; QList mDistrListMembers; }; } #endif // KOLABDISTRIBUTIONLIST_H // kate: space-indent on; indent-width 2; replace-tabs on; libkolab-1.0.2/kolabformatV2/event.cpp000066400000000000000000000142421262531616600176420ustar00rootroot00000000000000/* This file is part of the kolab resource - the implementation of the Kolab storage format. See www.kolab.org for documentation on this. Copyright (c) 2004 Bo Thorsen 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. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "event.h" #include #include using namespace KolabV2; KCalCore::Event::Ptr Event::fromXml( const QDomDocument& xmlDoc, const QString& tz) { Event event( tz ); event.loadXML( xmlDoc ); KCalCore::Event::Ptr kcalEvent( new KCalCore::Event() ); event.saveTo( kcalEvent ); return kcalEvent; } QString Event::eventToXML( const KCalCore::Event::Ptr &kcalEvent, const QString& tz ) { Event event( tz, kcalEvent ); return event.saveXML(); } Event::Event( const QString& tz, const KCalCore::Event::Ptr &event ) : Incidence( tz, event ), mShowTimeAs( KCalCore::Event::Opaque ), mHasEndDate( false ) { if ( event ) { setFields( event ); } } Event::~Event() { } void Event::setTransparency( KCalCore::Event::Transparency transparency ) { mShowTimeAs = transparency; } KCalCore::Event::Transparency Event::transparency() const { return mShowTimeAs; } void Event::setEndDate( const KDateTime& date ) { mEndDate = date; mHasEndDate = true; if ( mFloatingStatus == AllDay ) qDebug() <<"ERROR: Time on end date but no time on the event"; mFloatingStatus = HasTime; } void Event::setEndDate( const QDate& date ) { mEndDate = KDateTime( date ); mHasEndDate = true; if ( mFloatingStatus == HasTime ) qDebug() <<"ERROR: No time on end date but time on the event"; mFloatingStatus = AllDay; } void Event::setEndDate( const QString& endDate ) { if ( endDate.length() > 10 ) // This is a date + time setEndDate( stringToDateTime( endDate ) ); else // This is only a date setEndDate( stringToDate( endDate ) ); } KDateTime Event::endDate() const { return mEndDate; } bool Event::loadAttribute( QDomElement& element ) { // This method doesn't handle the color-label tag yet QString tagName = element.tagName(); if ( tagName == "show-time-as" ) { // TODO: Support tentative and outofoffice if ( element.text() == "free" ) setTransparency( KCalCore::Event::Transparent ); else setTransparency( KCalCore::Event::Opaque ); } else if ( tagName == "end-date" ) setEndDate( element.text() ); else return Incidence::loadAttribute( element ); // We handled this return true; } bool Event::saveAttributes( QDomElement& element ) const { // Save the base class elements Incidence::saveAttributes( element ); // TODO: Support tentative and outofoffice if ( transparency() == KCalCore::Event::Transparent ) writeString( element, "show-time-as", "free" ); else writeString( element, "show-time-as", "busy" ); if ( mHasEndDate ) { if ( mFloatingStatus == HasTime ) writeString( element, "end-date", dateTimeToString( endDate() ) ); else writeString( element, "end-date", dateToString( endDate().date() ) ); } return true; } bool Event::loadXML( const QDomDocument& document ) { QDomElement top = document.documentElement(); if ( top.tagName() != "event" ) { qWarning( "XML error: Top tag was %s instead of the expected event", top.tagName().toAscii().data() ); return false; } for ( QDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling() ) { if ( n.isComment() ) continue; if ( n.isElement() ) { QDomElement e = n.toElement(); loadAttribute( e ); } else qDebug() <<"Node is not a comment or an element???"; } return true; } QString Event::saveXML() const { QDomDocument document = domTree(); QDomElement element = document.createElement( "event" ); element.setAttribute( "version", "1.0" ); saveAttributes( element ); document.appendChild( element ); return document.toString(); } void Event::setFields( const KCalCore::Event::Ptr &event ) { Incidence::setFields( event ); // note: if hasEndDate() is false and hasDuration() is true // dtEnd() returns start+duration if ( event->hasEndDate() || event->hasDuration() ) { if ( event->allDay() ) { // This is an all-day event. Don't timezone move this one mFloatingStatus = AllDay; setEndDate( event->dtEnd().date() ); } else { mFloatingStatus = HasTime; setEndDate( localToUTC( event->dtEnd() ) ); } } else { mHasEndDate = false; } setTransparency( event->transparency() ); } void Event::saveTo( const KCalCore::Event::Ptr &event ) { Incidence::saveTo( event ); //PORT KF5 ? method removed event->setHasEndDate( mHasEndDate ); if ( mHasEndDate ) { if ( mFloatingStatus == AllDay ) // This is an all-day event. Don't timezone move this one event->setDtEnd( endDate() ); else event->setDtEnd( utcToLocal( endDate() ) ); } event->setTransparency( transparency() ); } libkolab-1.0.2/kolabformatV2/event.h000066400000000000000000000067411262531616600173140ustar00rootroot00000000000000/* This file is part of the kolab resource - the implementation of the Kolab storage format. See www.kolab.org for documentation on this. Copyright (c) 2004 Bo Thorsen 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. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef KOLABV2_EVENT_H #define KOLABV2_EVENT_H #include "incidence.h" #include class QDomElement; namespace KolabV2 { /** * This class represents an event, and knows how to load/save it * from/to XML, and from/to a KCalCore::Event. * The instances of this class are temporary, only used to convert * one to the other. */ class Event : public Incidence { public: /// Use this to parse an xml string to a event entry /// The caller is responsible for deleting the returned event static KCalCore::Event::Ptr fromXml( const QDomDocument& xmlDoc, const QString& tz); /// Use this to get an xml string describing this event entry static QString eventToXML( const KCalCore::Event::Ptr &, const QString& tz ); /// Create a event object and explicit Event( const QString& tz, const KCalCore::Event::Ptr &event = KCalCore::Event::Ptr() ); virtual ~Event(); void saveTo( const KCalCore::Event::Ptr &event ); virtual QString type() const { return "Event"; } virtual void setTransparency( KCalCore::Event::Transparency transparency ); virtual KCalCore::Event::Transparency transparency() const; virtual void setEndDate( const KDateTime& date ); virtual void setEndDate( const QDate& date ); virtual void setEndDate( const QString& date ); virtual KDateTime endDate() const; // Load the attributes of this class virtual bool loadAttribute( QDomElement& ); // Save the attributes of this class virtual bool saveAttributes( QDomElement& ) const; // Load this event by reading the XML file virtual bool loadXML( const QDomDocument& xml ); // Serialize this event to an XML string virtual QString saveXML() const; protected: // Read all known fields from this ical incidence void setFields( const KCalCore::Event::Ptr & ); KCalCore::Event::Transparency mShowTimeAs; KDateTime mEndDate; bool mHasEndDate; }; } #endif // KOLAB_EVENT_H libkolab-1.0.2/kolabformatV2/incidence.cpp000066400000000000000000001020061262531616600204360ustar00rootroot00000000000000/* This file is part of the kolab resource - the implementation of the Kolab storage format. See www.kolab.org for documentation on this. Copyright (c) 2004 Bo Thorsen 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. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "incidence.h" #include "libkolab-version.h" #include #include #include #include #include using namespace KolabV2; Incidence::Incidence( const QString& tz, const KCalCore::Incidence::Ptr &incidence ) : KolabBase( tz ), mFloatingStatus( Unset ), mHasAlarm( false ), mPriority( 0 ) { Q_UNUSED( incidence ); } Incidence::~Incidence() { } void Incidence::setPriority( int priority ) { mPriority = priority; } int Incidence::priority() const { return mPriority; } void Incidence::setSummary( const QString& summary ) { mSummary = summary; } QString Incidence::summary() const { return mSummary; } void Incidence::setLocation( const QString& location ) { mLocation = location; } QString Incidence::location() const { return mLocation; } void Incidence::setOrganizer( const Email& organizer ) { mOrganizer = organizer; } KolabBase::Email Incidence::organizer() const { return mOrganizer; } void Incidence::setStartDate( const KDateTime& startDate ) { mStartDate = startDate; if ( mFloatingStatus == AllDay ) qDebug() <<"ERROR: Time on start date but no time on the event"; mFloatingStatus = HasTime; } void Incidence::setStartDate( const QDate& startDate ) { mStartDate = KDateTime( startDate ); if ( mFloatingStatus == HasTime ) qDebug() <<"ERROR: No time on start date but time on the event"; mFloatingStatus = AllDay; } void Incidence::setStartDate( const QString& startDate ) { if ( startDate.length() > 10 ) // This is a date + time setStartDate( stringToDateTime( startDate ) ); else // This is only a date setStartDate( stringToDate( startDate ) ); } KDateTime Incidence::startDate() const { return mStartDate; } void Incidence::setAlarm( float alarm ) { mAlarm = alarm; mHasAlarm = true; } float Incidence::alarm() const { return mAlarm; } Incidence::Recurrence Incidence::recurrence() const { return mRecurrence; } void Incidence::addAttendee( const Attendee& attendee ) { mAttendees.append( attendee ); } QList& Incidence::attendees() { return mAttendees; } const QList& Incidence::attendees() const { return mAttendees; } void Incidence::setInternalUID( const QString& iuid ) { mInternalUID = iuid; } QString Incidence::internalUID() const { return mInternalUID; } bool Incidence::loadAttendeeAttribute( QDomElement& element, Attendee& attendee ) { for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) { if ( n.isComment() ) continue; if ( n.isElement() ) { QDomElement e = n.toElement(); QString tagName = e.tagName(); if ( tagName == "display-name" ) attendee.displayName = e.text(); else if ( tagName == "smtp-address" ) attendee.smtpAddress = e.text(); else if ( tagName == "status" ) attendee.status = e.text(); else if ( tagName == "request-response" ) // This sets reqResp to false, if the text is "false". Otherwise it // sets it to true. This means the default setting is true. attendee.requestResponse = ( e.text().toLower() != "false" ); else if ( tagName == "invitation-sent" ) // Like above, only this defaults to false attendee.invitationSent = ( e.text().toLower() != "true" ); else if ( tagName == "role" ) attendee.role = e.text(); else if ( tagName == "delegated-to" ) attendee.delegate = e.text(); else if ( tagName == "delegated-from" ) attendee.delegator = e.text(); else // TODO: Unhandled tag - save for later storage qDebug() <<"Warning: Unhandled tag" << e.tagName(); } else qDebug() <<"Node is not a comment or an element???"; } return true; } void Incidence::saveAttendeeAttribute( QDomElement& element, const Attendee& attendee ) const { QDomElement e = element.ownerDocument().createElement( "attendee" ); element.appendChild( e ); writeString( e, "display-name", attendee.displayName ); writeString( e, "smtp-address", attendee.smtpAddress ); writeString( e, "status", attendee.status ); writeString( e, "request-response", ( attendee.requestResponse ? "true" : "false" ) ); writeString( e, "invitation-sent", ( attendee.invitationSent ? "true" : "false" ) ); writeString( e, "role", attendee.role ); writeString( e, "delegated-to", attendee.delegate ); writeString( e, "delegated-from", attendee.delegator ); } void Incidence::saveAttendees( QDomElement& element ) const { foreach ( const Attendee& attendee, mAttendees ) saveAttendeeAttribute( element, attendee ); } void Incidence::saveAttachments( QDomElement& element ) const { foreach ( KCalCore::Attachment::Ptr a, mAttachments ) { if ( a->isUri() ) { writeString( element, "link-attachment", a->uri() ); } else if ( a->isBinary() ) { writeString( element, "inline-attachment", a->label() ); } } } void Incidence::saveAlarms( QDomElement& element ) const { if ( mAlarms.isEmpty() ) return; QDomElement list = element.ownerDocument().createElement( "advanced-alarms" ); element.appendChild( list ); foreach ( KCalCore::Alarm::Ptr a, mAlarms ) { QDomElement e = list.ownerDocument().createElement( "alarm" ); list.appendChild( e ); writeString( e, "enabled", a->enabled() ? "1" : "0" ); if ( a->hasStartOffset() ) { writeString( e, "start-offset", QString::number( a->startOffset().asSeconds()/60 ) ); } if ( a->hasEndOffset() ) { writeString( e, "end-offset", QString::number( a->endOffset().asSeconds()/60 ) ); } if ( a->repeatCount() ) { writeString( e, "repeat-count", QString::number( a->repeatCount() ) ); writeString( e, "repeat-interval", QString::number( a->snoozeTime().asSeconds() ) ); } switch ( a->type() ) { case KCalCore::Alarm::Invalid: break; case KCalCore::Alarm::Display: e.setAttribute( "type", "display" ); writeString( e, "text", a->text() ); break; case KCalCore::Alarm::Procedure: e.setAttribute( "type", "procedure" ); writeString( e, "program", a->programFile() ); writeString( e, "arguments", a->programArguments() ); break; case KCalCore::Alarm::Email: { e.setAttribute( "type", "email" ); QDomElement addresses = e.ownerDocument().createElement( "addresses" ); e.appendChild( addresses ); foreach ( const KCalCore::Person::Ptr &person, a->mailAddresses() ) { writeString( addresses, "address", person->fullName() ); } writeString( e, "subject", a->mailSubject() ); writeString( e, "mail-text", a->mailText() ); QDomElement attachments = e.ownerDocument().createElement( "attachments" ); e.appendChild( attachments ); foreach ( const QString &attachment, a->mailAttachments() ) { writeString( attachments, "attachment", attachment ); } break; } case KCalCore::Alarm::Audio: e.setAttribute( "type", "audio" ); writeString( e, "file", a->audioFile() ); break; default: qWarning() << "Unhandled alarm type:" << a->type(); break; } } } void Incidence::saveRecurrence( QDomElement& element ) const { QDomElement e = element.ownerDocument().createElement( "recurrence" ); element.appendChild( e ); e.setAttribute( "cycle", mRecurrence.cycle ); if ( !mRecurrence.type.isEmpty() ) e.setAttribute( "type", mRecurrence.type ); writeString( e, "interval", QString::number( mRecurrence.interval ) ); foreach ( const QString& recurrence, mRecurrence.days ) { writeString( e, "day", recurrence ); } if ( !mRecurrence.dayNumber.isEmpty() ) writeString( e, "daynumber", mRecurrence.dayNumber ); if ( !mRecurrence.month.isEmpty() ) writeString( e, "month", mRecurrence.month ); if ( !mRecurrence.rangeType.isEmpty() ) { QDomElement range = element.ownerDocument().createElement( "range" ); e.appendChild( range ); range.setAttribute( "type", mRecurrence.rangeType ); QDomText t = element.ownerDocument().createTextNode( mRecurrence.range ); range.appendChild( t ); } foreach ( const QDate& date, mRecurrence.exclusions ) { writeString( e, "exclusion", dateToString( date ) ); } } void Incidence::loadRecurrence( const QDomElement& element ) { mRecurrence.interval = 0; mRecurrence.cycle = element.attribute( "cycle" ); mRecurrence.type = element.attribute( "type" ); for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) { if ( n.isComment() ) continue; if ( n.isElement() ) { QDomElement e = n.toElement(); QString tagName = e.tagName(); if ( tagName == "interval" ) { //kolab/issue4229, sometimes the interval value can be empty if ( e.text().isEmpty() || e.text().toInt() <= 0 ) { mRecurrence.interval = 1; } else { mRecurrence.interval = e.text().toInt(); } } else if ( tagName == "day" ) // can be present multiple times mRecurrence.days.append( e.text() ); else if ( tagName == "daynumber" ) mRecurrence.dayNumber = e.text(); else if ( tagName == "month" ) mRecurrence.month = e.text(); else if ( tagName == "range" ) { mRecurrence.rangeType = e.attribute( "type" ); mRecurrence.range = e.text(); } else if ( tagName == "exclusion" ) { mRecurrence.exclusions.append( stringToDate( e.text() ) ); } else // TODO: Unhandled tag - save for later storage qDebug() <<"Warning: Unhandled tag" << e.tagName(); } } } static void loadAddressesHelper( const QDomElement& element, const KCalCore::Alarm::Ptr &a ) { for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) { if ( n.isComment() ) continue; if ( n.isElement() ) { QDomElement e = n.toElement(); QString tagName = e.tagName(); if ( tagName == "address" ) { a->addMailAddress( KCalCore::Person::fromFullName( e.text() ) ); } else { qWarning() << "Unhandled tag" << tagName; } } } } static void loadAttachmentsHelper( const QDomElement& element, const KCalCore::Alarm::Ptr &a ) { for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) { if ( n.isComment() ) continue; if ( n.isElement() ) { QDomElement e = n.toElement(); QString tagName = e.tagName(); if ( tagName == "attachment" ) { a->addMailAttachment( e.text() ); } else { qWarning() << "Unhandled tag" << tagName; } } } } static void loadAlarmHelper( const QDomElement& element, const KCalCore::Alarm::Ptr &a ) { for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) { if ( n.isComment() ) continue; if ( n.isElement() ) { QDomElement e = n.toElement(); QString tagName = e.tagName(); if ( tagName == "start-offset" ) { a->setStartOffset( e.text().toInt()*60 ); } else if ( tagName == "end-offset" ) { a->setEndOffset( e.text().toInt()*60 ); } else if ( tagName == "repeat-count" ) { a->setRepeatCount( e.text().toInt() ); } else if ( tagName == "repeat-interval" ) { a->setSnoozeTime( e.text().toInt() ); } else if ( tagName == "text" ) { a->setText( e.text() ); } else if ( tagName == "program" ) { a->setProgramFile( e.text() ); } else if ( tagName == "arguments" ) { a->setProgramArguments( e.text() ); } else if ( tagName == "addresses" ) { loadAddressesHelper( e, a ); } else if ( tagName == "subject" ) { a->setMailSubject( e.text() ); } else if ( tagName == "mail-text" ) { a->setMailText( e.text() ); } else if ( tagName == "attachments" ) { loadAttachmentsHelper( e, a ); } else if ( tagName == "file" ) { a->setAudioFile( e.text() ); } else if ( tagName == "enabled" ) { a->setEnabled( e.text().toInt() != 0 ); } else { qWarning() << "Unhandled tag" << tagName; } } } } void Incidence::loadAlarms( const QDomElement& element ) { for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) { if ( n.isComment() ) continue; if ( n.isElement() ) { QDomElement e = n.toElement(); QString tagName = e.tagName(); if ( tagName == "alarm" ) { KCalCore::Alarm::Ptr a = KCalCore::Alarm::Ptr( new KCalCore::Alarm( 0 ) ); a->setEnabled( true ); // default to enabled, unless some XML attribute says otherwise. QString type = e.attribute( "type" ); if ( type == "display" ) { a->setType( KCalCore::Alarm::Display ); } else if ( type == "procedure" ) { a->setType( KCalCore::Alarm::Procedure ); } else if ( type == "email" ) { a->setType( KCalCore::Alarm::Email ); } else if ( type == "audio" ) { a->setType( KCalCore::Alarm::Audio ); } else { qWarning() << "Unhandled alarm type:" << type; } loadAlarmHelper( e, a ); mAlarms << a; } else { qWarning() << "Unhandled tag" << tagName; } } } } bool Incidence::loadAttribute( QDomElement& element ) { QString tagName = element.tagName(); if ( tagName == "priority" ) { bool ok; int p = element.text().toInt( &ok ); if ( !ok || p < 1 || p > 9 ) { qWarning() << "Invalid \"priority\" value:" << element.text(); } else { setPriority( p ); } } else if ( tagName == "x-kcal-priority" ) { //for backwards compat bool ok; int p = element.text().toInt( &ok ); if ( !ok || p < 0 || p > 9 ) { qWarning() << "Invalid \"x-kcal-priority\" value:" << element.text(); } else { if ( priority() == 0 ) { setPriority(p); } } } else if ( tagName == "summary" ) setSummary( element.text() ); else if ( tagName == "location" ) setLocation( element.text() ); else if ( tagName == "organizer" ) { Email email; if ( loadEmailAttribute( element, email ) ) { setOrganizer( email ); return true; } else return false; } else if ( tagName == "start-date" ) setStartDate( element.text() ); else if ( tagName == "recurrence" ) loadRecurrence( element ); else if ( tagName == "attendee" ) { Attendee attendee; if ( loadAttendeeAttribute( element, attendee ) ) { addAttendee( attendee ); return true; } else return false; } else if ( tagName == "link-attachment" ) { mAttachments.push_back( KCalCore::Attachment::Ptr( new KCalCore::Attachment( element.text() ) ) ); } else if ( tagName == "alarm" ) // Alarms should be minutes before. Libkcal uses event time + alarm time setAlarm( - element.text().toInt() ); else if ( tagName == "advanced-alarms" ) loadAlarms( element ); else if ( tagName == "x-kde-internaluid" ) setInternalUID( element.text() ); else if ( tagName == "x-custom" ) { loadCustomAttributes( element ); } else if ( tagName == "inline-attachment" ) { // we handle that separately later on, so no need to create a KolabUnhandled entry for it } else { bool ok = KolabBase::loadAttribute( element ); if ( !ok ) { // Unhandled tag - save for later storage qDebug() <<"Saving unhandled tag" << element.tagName(); Custom c; c.key = QByteArray( "X-KDE-KolabUnhandled-" ) + element.tagName().toLatin1(); c.value = element.text(); mCustomList.append( c ); } } // We handled this return true; } bool Incidence::saveAttributes( QDomElement& element ) const { // Save the base class elements KolabBase::saveAttributes( element ); if (priority() != 0) { writeString( element, "priority", QString::number( priority() ) ); } if ( mFloatingStatus == HasTime ) writeString( element, "start-date", dateTimeToString( startDate() ) ); else writeString( element, "start-date", dateToString( startDate().date() ) ); writeString( element, "summary", summary() ); writeString( element, "location", location() ); saveEmailAttribute( element, organizer(), "organizer" ); if ( !mRecurrence.cycle.isEmpty() ) saveRecurrence( element ); saveAttendees( element ); saveAttachments( element ); if ( mHasAlarm ) { // Alarms should be minutes before. Libkcal uses event time + alarm time int alarmTime = qRound( -alarm() ); writeString( element, "alarm", QString::number( alarmTime ) ); } saveAlarms( element ); writeString( element, "x-kde-internaluid", internalUID() ); saveCustomAttributes( element ); return true; } void Incidence::saveCustomAttributes( QDomElement& element ) const { foreach ( const Custom& custom, mCustomList ) { QString key( custom.key ); Q_ASSERT( !key.isEmpty() ); if ( key.startsWith( QLatin1String( "X-KDE-KolabUnhandled-" ) ) ) { key = key.mid( strlen( "X-KDE-KolabUnhandled-" ) ); writeString( element, key, custom.value ); } else { // Let's use attributes so that other tag-preserving-code doesn't need sub-elements QDomElement e = element.ownerDocument().createElement( "x-custom" ); element.appendChild( e ); e.setAttribute( "key", key ); e.setAttribute( "value", custom.value ); } } } void Incidence::loadCustomAttributes( QDomElement& element ) { Custom custom; custom.key = element.attribute( "key" ).toLatin1(); custom.value = element.attribute( "value" ); mCustomList.append( custom ); } static KCalCore::Attendee::PartStat attendeeStringToStatus( const QString& s ) { if ( s == "none" ) return KCalCore::Attendee::NeedsAction; if ( s == "tentative" ) return KCalCore::Attendee::Tentative; if ( s == "declined" ) return KCalCore::Attendee::Declined; if ( s == "delegated" ) return KCalCore::Attendee::Delegated; // Default: return KCalCore::Attendee::Accepted; } static QString attendeeStatusToString( KCalCore::Attendee::PartStat status ) { switch( status ) { case KCalCore::Attendee::NeedsAction: return "none"; case KCalCore::Attendee::Accepted: return "accepted"; case KCalCore::Attendee::Declined: return "declined"; case KCalCore::Attendee::Tentative: return "tentative"; case KCalCore::Attendee::Delegated: return "delegated"; case KCalCore::Attendee::Completed: case KCalCore::Attendee::InProcess: // These don't have any meaning in the Kolab format, so just use: return "accepted"; default: // Default for the case that there are more added later: return "accepted"; } } static KCalCore::Attendee::Role attendeeStringToRole( const QString& s ) { if ( s == "optional" ) return KCalCore::Attendee::OptParticipant; if ( s == "resource" ) return KCalCore::Attendee::NonParticipant; return KCalCore::Attendee::ReqParticipant; } static QString attendeeRoleToString( KCalCore::Attendee::Role role ) { switch( role ) { case KCalCore::Attendee::ReqParticipant: return "required"; case KCalCore::Attendee::OptParticipant: return "optional"; case KCalCore::Attendee::Chair: // We don't have the notion of chair, so use return "required"; case KCalCore::Attendee::NonParticipant: // In Kolab, a non-participant is a resource return "resource"; } // Default for the case that there are more added later: return "required"; } static const char *s_weekDayName[] = { "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday" }; static const char *s_monthName[] = { "january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december" }; void Incidence::setRecurrence( KCalCore::Recurrence* recur ) { mRecurrence.interval = recur->frequency(); switch ( recur->recurrenceType() ) { case KCalCore::Recurrence::rMinutely: // Not handled by the kolab XML mRecurrence.cycle = "minutely"; break; case KCalCore::Recurrence::rHourly: // Not handled by the kolab XML mRecurrence.cycle = "hourly"; break; case KCalCore::Recurrence::rDaily: mRecurrence.cycle = "daily"; break; case KCalCore::Recurrence::rWeekly: // every X weeks mRecurrence.cycle = "weekly"; { QBitArray arr = recur->days(); for ( uint idx = 0 ; idx < 7 ; ++idx ) if ( arr.testBit( idx ) ) mRecurrence.days.append( s_weekDayName[idx] ); } break; case KCalCore::Recurrence::rMonthlyPos: { mRecurrence.cycle = "monthly"; mRecurrence.type = "weekday"; QList monthPositions = recur->monthPositions(); if ( !monthPositions.isEmpty() ) { KCalCore::RecurrenceRule::WDayPos monthPos = monthPositions.first(); // TODO: Handle multiple days in the same week mRecurrence.dayNumber = QString::number( monthPos.pos() ); mRecurrence.days.append( s_weekDayName[ monthPos.day()-1 ] ); // Not (properly) handled(?): monthPos.negative (nth days before end of month) } break; } case KCalCore::Recurrence::rMonthlyDay: { mRecurrence.cycle = "monthly"; mRecurrence.type = "daynumber"; QList monthDays = recur->monthDays(); // ####### Kolab XML limitation: only the first month day is used if ( !monthDays.isEmpty() ) mRecurrence.dayNumber = QString::number( monthDays.first() ); break; } case KCalCore::Recurrence::rYearlyMonth: // (day n of Month Y) { mRecurrence.cycle = "yearly"; mRecurrence.type = "monthday"; QList rmd = recur->yearDates(); int day = !rmd.isEmpty() ? rmd.first() : recur->startDate().day(); mRecurrence.dayNumber = QString::number( day ); QList months = recur->yearMonths(); if ( !months.isEmpty() ) mRecurrence.month = s_monthName[ months.first() - 1 ]; // #### Kolab XML limitation: only one month specified break; } case KCalCore::Recurrence::rYearlyDay: // YearlyDay (day N of the year). Not supported by Outlook mRecurrence.cycle = "yearly"; mRecurrence.type = "yearday"; mRecurrence.dayNumber = QString::number( recur->yearDays().first() ); break; case KCalCore::Recurrence::rYearlyPos: // (weekday X of week N of month Y) mRecurrence.cycle = "yearly"; mRecurrence.type = "weekday"; QList months = recur->yearMonths(); if ( !months.isEmpty() ) mRecurrence.month = s_monthName[ months.first() - 1 ]; // #### Kolab XML limitation: only one month specified QList monthPositions = recur->yearPositions(); if ( !monthPositions.isEmpty() ) { KCalCore::RecurrenceRule::WDayPos monthPos = monthPositions.first(); // TODO: Handle multiple days in the same week mRecurrence.dayNumber = QString::number( monthPos.pos() ); mRecurrence.days.append( s_weekDayName[ monthPos.day()-1 ] ); //mRecurrence.dayNumber = QString::number( *recur->yearNums().getFirst() ); // Not handled: monthPos.negative (nth days before end of month) } break; } int howMany = recur->duration(); if ( howMany > 0 ) { mRecurrence.rangeType = "number"; mRecurrence.range = QString::number( howMany ); } else if ( howMany == 0 ) { mRecurrence.rangeType = "date"; mRecurrence.range = dateToString( recur->endDate() ); } else { mRecurrence.rangeType = "none"; } } void Incidence::setFields( const KCalCore::Incidence::Ptr &incidence ) { KolabBase::setFields( incidence ); setPriority( incidence->priority() ); if ( incidence->allDay() ) { // This is a all-day event. Don't timezone move this one mFloatingStatus = AllDay; setStartDate( incidence->dtStart().date() ); } else { mFloatingStatus = HasTime; setStartDate( localToUTC( incidence->dtStart() ) ); } setSummary( incidence->summary() ); setLocation( incidence->location() ); // Alarm mHasAlarm = false; // Will be set to true, if we actually have one if ( incidence->hasEnabledAlarms() ) { const KCalCore::Alarm::List& alarms = incidence->alarms(); if ( !alarms.isEmpty() ) { const KCalCore::Alarm::Ptr alarm = alarms.first(); if ( alarm->hasStartOffset() ) { int dur = alarm->startOffset().asSeconds(); setAlarm( (float)dur / 60.0 ); } } } if (incidence->organizer()) { Email org( incidence->organizer()->name(), incidence->organizer()->email() ); setOrganizer( org ); } // Attendees: KCalCore::Attendee::List attendees = incidence->attendees(); foreach ( KCalCore::Attendee::Ptr kcalAttendee, attendees ) { Attendee attendee; attendee.displayName = kcalAttendee->name(); attendee.smtpAddress = kcalAttendee->email(); attendee.status = attendeeStatusToString( kcalAttendee->status() ); attendee.requestResponse = kcalAttendee->RSVP(); // TODO: KCalCore::Attendee::mFlag is not accessible // attendee.invitationSent = kcalAttendee->mFlag; // DF: Hmm? mFlag is set to true and never used at all.... Did you mean another field? attendee.role = attendeeRoleToString( kcalAttendee->role() ); attendee.delegate = kcalAttendee->delegate(); attendee.delegator = kcalAttendee->delegator(); addAttendee( attendee ); } mAttachments.clear(); // Attachments KCalCore::Attachment::List attachments = incidence->attachments(); foreach ( KCalCore::Attachment::Ptr a, attachments ) { mAttachments.push_back( a ); } mAlarms.clear(); // Alarms KCalCore::Alarm::List alarms = incidence->alarms(); foreach ( KCalCore::Alarm::Ptr a, alarms ) { mAlarms.push_back( a ); } if ( incidence->recurs() ) { setRecurrence( incidence->recurrence() ); mRecurrence.exclusions = incidence->recurrence()->exDates(); } // Handle the scheduling ID if ( incidence->schedulingID() == incidence->uid() ) { // There is no scheduling ID setInternalUID( QString::null ); //krazy:exclude=nullstrassign for old broken gcc } else { // We've internally been using a different uid, so save that as the // temporary (internal) uid and restore the original uid, the one that // is used in the folder and the outside world setUid( incidence->schedulingID() ); setInternalUID( incidence->uid() ); } // Unhandled tags and other custom properties (see libkcal/customproperties.h) const QMap map = incidence->customProperties(); QMap::ConstIterator cit = map.begin(); for ( ; cit != map.end() ; ++cit ) { Custom c; c.key = cit.key(); c.value = cit.value(); mCustomList.append( c ); } } static QBitArray daysListToBitArray( const QStringList& days ) { QBitArray arr( 7 ); arr.fill( false ); foreach ( const QString& day, days ) { for ( uint i = 0; i < 7 ; ++i ) if ( day == s_weekDayName[i] ) arr.setBit( i, true ); } return arr; } void Incidence::saveTo( const KCalCore::Incidence::Ptr &incidence ) { KolabBase::saveTo( incidence ); incidence->setPriority( priority() ); if ( mFloatingStatus == AllDay ) { // This is an all-day event. Don't timezone move this one incidence->setDtStart( startDate() ); incidence->setAllDay( true ); } else { incidence->setDtStart( utcToLocal( startDate() ) ); incidence->setAllDay( false ); } incidence->setSummary( summary() ); incidence->setLocation( location() ); if ( mHasAlarm && mAlarms.isEmpty() ) { KCalCore::Alarm::Ptr alarm = incidence->newAlarm(); alarm->setStartOffset( qRound( mAlarm * 60.0 ) ); alarm->setEnabled( true ); alarm->setType( KCalCore::Alarm::Display ); } else if ( !mAlarms.isEmpty() ) { foreach ( KCalCore::Alarm::Ptr a, mAlarms ) { a->setParent( incidence.data() ); incidence->addAlarm( a ); } } if ( organizer().displayName.isEmpty() ) incidence->setOrganizer( organizer().smtpAddress ); else incidence->setOrganizer( organizer().displayName + '<' + organizer().smtpAddress + '>' ); incidence->clearAttendees(); foreach ( const Attendee& attendee, mAttendees ) { KCalCore::Attendee::PartStat status = attendeeStringToStatus( attendee.status ); KCalCore::Attendee::Role role = attendeeStringToRole( attendee.role ); KCalCore::Attendee::Ptr a( new KCalCore::Attendee( attendee.displayName, attendee.smtpAddress, attendee.requestResponse, status, role ) ); a->setDelegate( attendee.delegate ); a->setDelegator( attendee.delegator ); incidence->addAttendee( a ); } incidence->clearAttachments(); foreach ( KCalCore::Attachment::Ptr a, mAttachments ) { // TODO should we copy? incidence->addAttachment( a ); } if ( !mRecurrence.cycle.isEmpty() ) { KCalCore::Recurrence* recur = incidence->recurrence(); // yeah, this creates it // done below recur->setFrequency( mRecurrence.interval ); if ( mRecurrence.cycle == "minutely" ) { recur->setMinutely( mRecurrence.interval ); } else if ( mRecurrence.cycle == "hourly" ) { recur->setHourly( mRecurrence.interval ); } else if ( mRecurrence.cycle == "daily" ) { recur->setDaily( mRecurrence.interval ); } else if ( mRecurrence.cycle == "weekly" ) { QBitArray rDays = daysListToBitArray( mRecurrence.days ); recur->setWeekly( mRecurrence.interval, rDays ); } else if ( mRecurrence.cycle == "monthly" ) { recur->setMonthly( mRecurrence.interval ); if ( mRecurrence.type == "weekday" ) { recur->addMonthlyPos( mRecurrence.dayNumber.toInt(), daysListToBitArray( mRecurrence.days ) ); } else if ( mRecurrence.type == "daynumber" ) { recur->addMonthlyDate( mRecurrence.dayNumber.toInt() ); } else qWarning() <<"Unhandled monthly recurrence type" << mRecurrence.type; } else if ( mRecurrence.cycle == "yearly" ) { recur->setYearly( mRecurrence.interval ); if ( mRecurrence.type == "monthday" ) { recur->addYearlyDate( mRecurrence.dayNumber.toInt() ); for ( int i = 0; i < 12; ++i ) if ( s_monthName[ i ] == mRecurrence.month ) recur->addYearlyMonth( i+1 ); } else if ( mRecurrence.type == "yearday" ) { recur->addYearlyDay( mRecurrence.dayNumber.toInt() ); } else if ( mRecurrence.type == "weekday" ) { for ( int i = 0; i < 12; ++i ) if ( s_monthName[ i ] == mRecurrence.month ) recur->addYearlyMonth( i+1 ); recur->addYearlyPos( mRecurrence.dayNumber.toInt(), daysListToBitArray( mRecurrence.days ) ); } else qWarning() <<"Unhandled yearly recurrence type" << mRecurrence.type; } else qWarning() <<"Unhandled recurrence cycle" << mRecurrence.cycle; if ( mRecurrence.rangeType == "number" ) { recur->setDuration( mRecurrence.range.toInt() ); } else if ( mRecurrence.rangeType == "date" ) { recur->setEndDate( stringToDate( mRecurrence.range ) ); } // "none" is default since tje set*ly methods set infinite recurrence incidence->recurrence()->setExDates( mRecurrence.exclusions ); } /* If we've stored a uid to be used internally instead of the real one * (to deal with duplicates of events in different folders) before, then * restore it, so it does not change. Keep the original uid around for * scheduling purposes. */ if ( !internalUID().isEmpty() ) { incidence->setUid( internalUID() ); incidence->setSchedulingID( uid() ); } foreach ( const Custom& custom, mCustomList ) { incidence->setNonKDECustomProperty( custom.key, custom.value ); } } QString Incidence::productID() const { return QString( "%1, Kolab resource" ).arg( LIBKOLAB_LIB_VERSION_STRING ); } // Unhandled KCalCore::Incidence fields: // revision, status (unused), attendee.uid, // mComments, mReadOnly libkolab-1.0.2/kolabformatV2/incidence.h000066400000000000000000000127121262531616600201070ustar00rootroot00000000000000/* This file is part of the kolab resource - the implementation of the Kolab storage format. See www.kolab.org for documentation on this. Copyright (c) 2004 Bo Thorsen 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. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef KOLABV2_INCIDENCE_H #define KOLABV2_INCIDENCE_H #include #include "kolabbase.h" class QDomElement; namespace KolabV2 { /** * This abstract class represents an incidence which has the shared * fields, of events and tasks and knows how to load/save these * from/to XML, and from/to a KCalCore::Incidence. */ class Incidence : public KolabBase { public: struct Recurrence { QString cycle; QString type; int interval; QStringList days; // list of days-of-the-week QString dayNumber; QString month; QString rangeType; QString range; // date or number or nothing QList exclusions; }; struct Attendee : Email { Attendee() : requestResponse( true ), invitationSent( false ) {} QString status; bool requestResponse; bool invitationSent; QString role; QString delegate; QString delegator; }; explicit Incidence( const QString& tz, const KCalCore::Incidence::Ptr &incidence = KCalCore::Incidence::Ptr() ); public: virtual ~Incidence(); void saveTo( const KCalCore::Incidence::Ptr &incidence ); virtual void setPriority( int priority ); virtual int priority() const; virtual void setSummary( const QString& summary ); virtual QString summary() const; virtual void setLocation( const QString& location ); virtual QString location() const; virtual void setOrganizer( const Email& organizer ); virtual Email organizer() const; virtual void setStartDate( const KDateTime& startDate ); virtual void setStartDate( const QDate& startDate ); virtual void setStartDate( const QString& startDate ); virtual KDateTime startDate() const; virtual void setAlarm( float alarm ); virtual float alarm() const; virtual void setRecurrence( KCalCore::Recurrence* recur ); virtual Recurrence recurrence() const; virtual void addAttendee( const Attendee& attendee ); QList& attendees(); const QList& attendees() const; virtual QString type() const { return "Incidence"; } /** * The internal uid is used as the uid inside KOrganizer whenever * two or more events with the same uid appear, which KOrganizer * can't handle. To avoid keep that interal uid from changing all the * time, it is persisted in the XML between a save and the next load. */ void setInternalUID( const QString& iuid ); QString internalUID() const; // Load the attributes of this class virtual bool loadAttribute( QDomElement& ); // Save the attributes of this class virtual bool saveAttributes( QDomElement& ) const; protected: enum FloatingStatus { Unset, AllDay, HasTime }; // Read all known fields from this ical incidence void setFields( const KCalCore::Incidence::Ptr & ); bool loadAttendeeAttribute( QDomElement&, Attendee& ); void saveAttendeeAttribute( QDomElement& element, const Attendee& attendee ) const; void saveAttendees( QDomElement& element ) const; void saveAttachments( QDomElement& element ) const; void loadAlarms( const QDomElement& element ); void saveAlarms( QDomElement& element ) const; void loadRecurrence( const QDomElement& element ); void saveRecurrence( QDomElement& element ) const; void saveCustomAttributes( QDomElement& element ) const; void loadCustomAttributes( QDomElement& element ); QString productID() const; QString mSummary; QString mLocation; Email mOrganizer; KDateTime mStartDate; FloatingStatus mFloatingStatus; float mAlarm; bool mHasAlarm; Recurrence mRecurrence; QList mAttendees; QList mAlarms; QList mAttachments; QString mInternalUID; struct Custom { QByteArray key; QString value; }; QList mCustomList; // This is the KCal priority, not the Kolab priority. // See kcalPriorityToKolab() and kolabPrioritytoKCal(). int mPriority; }; } #endif // KOLAB_INCIDENCE_H libkolab-1.0.2/kolabformatV2/journal.cpp000066400000000000000000000115141262531616600201720ustar00rootroot00000000000000/* This file is part of the kolab resource - the implementation of the Kolab storage format. See www.kolab.org for documentation on this. Copyright (c) 2004 Bo Thorsen 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. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "journal.h" #include "libkolab-version.h" #include using namespace KolabV2; KCalCore::Journal::Ptr Journal::fromXml( const QDomDocument& xmlDoc, const QString& tz ) { Journal journal( tz ); journal.loadXML( xmlDoc ); KCalCore::Journal::Ptr kcalJournal( new KCalCore::Journal() ); journal.saveTo( kcalJournal ); return kcalJournal; } QString Journal::journalToXML( const KCalCore::Journal::Ptr &kcalJournal, const QString& tz ) { Journal journal( tz, kcalJournal ); return journal.saveXML(); } Journal::Journal( const QString& tz, const KCalCore::Journal::Ptr &journal ) : KolabBase( tz ) { if ( journal ) { setFields( journal ); } } Journal::~Journal() { } void Journal::setSummary( const QString& summary ) { mSummary = summary; } QString Journal::summary() const { return mSummary; } void Journal::setStartDate( const KDateTime& startDate ) { mStartDate = startDate; } KDateTime Journal::startDate() const { return mStartDate; } void Journal::setEndDate( const KDateTime& endDate ) { mEndDate = endDate; } KDateTime Journal::endDate() const { return mEndDate; } bool Journal::loadAttribute( QDomElement& element ) { QString tagName = element.tagName(); if ( tagName == "summary" ) setSummary( element.text() ); else if ( tagName == "start-date" ) setStartDate( stringToDateTime( element.text() ) ); else // Not handled here return KolabBase::loadAttribute( element ); // We handled this return true; } bool Journal::saveAttributes( QDomElement& element ) const { // Save the base class elements KolabBase::saveAttributes( element ); writeString( element, "summary", summary() ); writeString( element, "start-date", dateTimeToString( startDate() ) ); return true; } bool Journal::loadXML( const QDomDocument& document ) { QDomElement top = document.documentElement(); if ( top.tagName() != "journal" ) { qWarning( "XML error: Top tag was %s instead of the expected Journal", top.tagName().toAscii().data() ); return false; } for ( QDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling() ) { if ( n.isComment() ) continue; if ( n.isElement() ) { QDomElement e = n.toElement(); if ( !loadAttribute( e ) ) { // Unhandled tag - save for later storage //qDebug( "Unhandled tag: %s", e.toCString().data() ); } } else qDebug( "Node is not a comment or an element???" ); } return true; } QString Journal::saveXML() const { QDomDocument document = domTree(); QDomElement element = document.createElement( "journal" ); element.setAttribute( "version", "1.0" ); saveAttributes( element ); document.appendChild( element ); return document.toString(); } void Journal::saveTo( const KCalCore::Journal::Ptr &journal ) { KolabBase::saveTo( journal ); journal->setSummary( summary() ); journal->setDtStart( utcToLocal( startDate() ) ); } void Journal::setFields( const KCalCore::Journal::Ptr &journal ) { // Set baseclass fields KolabBase::setFields( journal ); // Set our own fields setSummary( journal->summary() ); setStartDate( localToUTC( journal->dtStart() ) ); } QString Journal::productID() const { return QString::fromLatin1(LIBKOLAB_LIB_VERSION_STRING) + ", Kolab resource"; } libkolab-1.0.2/kolabformatV2/journal.h000066400000000000000000000066731262531616600176510ustar00rootroot00000000000000/* This file is part of the kolab resource - the implementation of the Kolab storage format. See www.kolab.org for documentation on this. Copyright (c) 2004 Bo Thorsen 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. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef KOLABV2_JOURNAL_H #define KOLABV2_JOURNAL_H #include #include "kolabbase.h" class QDomElement; namespace KolabV2 { /** * This class represents a journal entry, and knows how to load/save it * from/to XML, and from/to a KCalCore::Journal. * The instances of this class are temporary, only used to convert * one to the other. */ class Journal : public KolabBase { public: /// Use this to parse an xml string to a journal entry /// The caller is responsible for deleting the returned journal static KCalCore::Journal::Ptr fromXml( const QDomDocument& xmlDoc, const QString& tz ); /// Use this to get an xml string describing this journal entry static QString journalToXML( const KCalCore::Journal::Ptr &, const QString& tz ); explicit Journal( const QString& tz, const KCalCore::Journal::Ptr &journal = KCalCore::Journal::Ptr() ); virtual ~Journal(); virtual QString type() const { return "Journal"; } void saveTo( const KCalCore::Journal::Ptr &journal ); virtual void setSummary( const QString& summary ); virtual QString summary() const; virtual void setStartDate( const KDateTime& startDate ); virtual KDateTime startDate() const; virtual void setEndDate( const KDateTime& endDate ); virtual KDateTime endDate() const; // Load the attributes of this class virtual bool loadAttribute( QDomElement& ); // Save the attributes of this class virtual bool saveAttributes( QDomElement& ) const; // Load this journal by reading the XML file virtual bool loadXML( const QDomDocument& xml ); // Serialize this journal to an XML string virtual QString saveXML() const; protected: // Read all known fields from this ical journal void setFields( const KCalCore::Journal::Ptr & ); QString productID() const; QString mSummary; KDateTime mStartDate; KDateTime mEndDate; }; } #endif // KOLAB_JOURNAL_H libkolab-1.0.2/kolabformatV2/kolabbase.cpp000066400000000000000000000326311262531616600204460ustar00rootroot00000000000000/* This file is part of the kolab resource - the implementation of the Kolab storage format. See www.kolab.org for documentation on this. Copyright (c) 2004 Bo Thorsen 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. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "kolabbase.h" #include #include #include #include #include #include using namespace KolabV2; KolabBase::KolabBase( const QString& tz ) : mCreationDate( QDateTime::currentDateTime() ), mLastModified( KDateTime::currentUtcDateTime() ), mSensitivity( Public ), mTimeZone( KTimeZone( tz ) ), mHasPilotSyncId( false ), mHasPilotSyncStatus( false ) { } KolabBase::~KolabBase() { } void KolabBase::setFields( const KCalCore::Incidence::Ptr &incidence ) { // So far unhandled KCalCore::IncidenceBase fields: // mPilotID, mSyncStatus, mFloats setUid( incidence->uid() ); setBody( incidence->description() ); setCategories( incidence->categoriesStr() ); setCreationDate( localToUTC( incidence->created() ) ); setLastModified( incidence->lastModified() ); setSensitivity( static_cast( incidence->secrecy() ) ); // TODO: Attachments } void KolabBase::saveTo( const KCalCore::Incidence::Ptr &incidence ) const { incidence->setUid( uid() ); incidence->setDescription( body() ); incidence->setCategories( categories() ); incidence->setCreated( utcToLocal( creationDate() ) ); incidence->setLastModified( lastModified() ); switch( sensitivity() ) { case 1: incidence->setSecrecy( KCalCore::Incidence::SecrecyPrivate ); break; case 2: incidence->setSecrecy( KCalCore::Incidence::SecrecyConfidential ); break; default: incidence->setSecrecy( KCalCore::Incidence::SecrecyPublic ); break; } // TODO: Attachments } void KolabBase::setFields( const KContacts::Addressee* addressee ) { // An addressee does not have a creation date, so somehow we should // make one, if this is a new entry setUid( addressee->uid() ); setBody( addressee->note() ); setCategories( addressee->categories().join( "," ) ); // Set creation-time and last-modification-time const QString creationString = addressee->custom( "KOLAB", "CreationDate" ); qDebug() <<"Creation time string:" << creationString; KDateTime creationDate; if ( creationString.isEmpty() ) { creationDate = KDateTime::currentDateTime(KDateTime::Spec( mTimeZone ) ); qDebug() <<"Creation date set to current time"; } else { creationDate = stringToDateTime( creationString ); qDebug() <<"Creation date loaded"; } KDateTime modified = KDateTime( addressee->revision(), mTimeZone ); if ( !modified.isValid() ) modified = KDateTime::currentUtcDateTime(); setLastModified( modified ); if ( modified < creationDate ) { // It's not possible that the modification date is earlier than creation creationDate = modified; qDebug() <<"Creation date set to modification date"; } setCreationDate( creationDate ); const QString newCreationDate = dateTimeToString( creationDate ); if ( creationString != newCreationDate ) { // We modified the creation date, so store it for future reference const_cast( addressee ) ->insertCustom( "KOLAB", "CreationDate", newCreationDate ); qDebug() <<"Creation date modified. New one:" << newCreationDate; } switch( addressee->secrecy().type() ) { case KContacts::Secrecy::Private: setSensitivity( Private ); break; case KContacts::Secrecy::Confidential: setSensitivity( Confidential ); break; default: setSensitivity( Public ); } // TODO: Attachments } void KolabBase::saveTo( KContacts::Addressee* addressee ) const { addressee->setUid( uid() ); addressee->setNote( body() ); addressee->setCategories( categories().split( ',', QString::SkipEmptyParts ) ); addressee->setRevision( lastModified().toZone( mTimeZone ).dateTime() ); addressee->insertCustom( "KOLAB", "CreationDate", dateTimeToString( creationDate() ) ); switch( sensitivity() ) { case Private: addressee->setSecrecy( KContacts::Secrecy( KContacts::Secrecy::Private ) ); break; case Confidential: addressee->setSecrecy( KContacts::Secrecy( KContacts::Secrecy::Confidential ) ); break; default: addressee->setSecrecy( KContacts::Secrecy( KContacts::Secrecy::Public ) ); break; } // TODO: Attachments } void KolabBase::setFields( const KContacts::ContactGroup* contactGroup ) { // A contactgroup does not have a creation date, so somehow we should // make one, if this is a new entry setUid( contactGroup->id() ); // Set creation-time and last-modification-time KDateTime creationDate = KDateTime::currentDateTime( KDateTime::Spec( mTimeZone ) ); qDebug() <<"Creation date set to current time"; KDateTime modified = KDateTime::currentUtcDateTime(); setLastModified( modified ); if ( modified < creationDate ) { // It's not possible that the modification date is earlier than creation creationDate = modified; qDebug() <<"Creation date set to modification date"; } setCreationDate( creationDate ); } void KolabBase::saveTo( KContacts::ContactGroup* contactGroup ) const { contactGroup->setId( uid() ); } void KolabBase::setUid( const QString& uid ) { mUid = uid; } QString KolabBase::uid() const { return mUid; } void KolabBase::setBody( const QString& body ) { mBody = body; } QString KolabBase::body() const { return mBody; } void KolabBase::setCategories( const QString& categories ) { mCategories = categories; } QString KolabBase::categories() const { return mCategories; } void KolabBase::setCreationDate( const KDateTime& date ) { mCreationDate = date; } KDateTime KolabBase::creationDate() const { return mCreationDate; } void KolabBase::setLastModified( const KDateTime& date ) { mLastModified = date; } KDateTime KolabBase::lastModified() const { return mLastModified; } void KolabBase::setSensitivity( Sensitivity sensitivity ) { mSensitivity = sensitivity; } KolabBase::Sensitivity KolabBase::sensitivity() const { return mSensitivity; } void KolabBase::setPilotSyncId( unsigned long id ) { mHasPilotSyncId = true; mPilotSyncId = id; } bool KolabBase::hasPilotSyncId() const { return mHasPilotSyncId; } unsigned long KolabBase::pilotSyncId() const { return mPilotSyncId; } void KolabBase::setPilotSyncStatus( int status ) { mHasPilotSyncStatus = true; mPilotSyncStatus = status; } bool KolabBase::hasPilotSyncStatus() const { return mHasPilotSyncStatus; } int KolabBase::pilotSyncStatus() const { return mPilotSyncStatus; } bool KolabBase::loadEmailAttribute( QDomElement& element, Email& email ) { for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) { if ( n.isComment() ) continue; if ( n.isElement() ) { QDomElement e = n.toElement(); const QString tagName = e.tagName(); if ( tagName == "display-name" ) email.displayName = e.text(); else if ( tagName == "smtp-address" ) email.smtpAddress = e.text(); else // TODO: Unhandled tag - save for later storage qDebug() <<"Warning: Unhandled tag" << e.tagName(); } else qDebug() <<"Node is not a comment or an element???"; } return true; } void KolabBase::saveEmailAttribute( QDomElement& element, const Email& email, const QString& tagName ) const { QDomElement e = element.ownerDocument().createElement( tagName ); element.appendChild( e ); writeString( e, "display-name", email.displayName ); writeString( e, "smtp-address", email.smtpAddress ); } bool KolabBase::loadAttribute( QDomElement& element ) { const QString tagName = element.tagName(); switch ( tagName[0].toLatin1() ) { case 'u': if ( tagName == "uid" ) { setUid( element.text() ); return true; } break; case 'b': if ( tagName == "body" ) { setBody( element.text() ); return true; } break; case 'c': if ( tagName == "categories" ) { setCategories( element.text() ); return true; } if ( tagName == "creation-date" ) { setCreationDate( stringToDateTime( element.text() ) ); return true; } break; case 'l': if ( tagName == "last-modification-date" ) { setLastModified( stringToDateTime( element.text() ) ); return true; } break; case 's': if ( tagName == "sensitivity" ) { setSensitivity( stringToSensitivity( element.text() ) ); return true; } break; case 'p': if ( tagName == "product-id" ) return true; // ignore this field if ( tagName == "pilot-sync-id" ) { setPilotSyncId( element.text().toULong() ); return true; } if ( tagName == "pilot-sync-status" ) { setPilotSyncStatus( element.text().toInt() ); return true; } break; default: break; } return false; } bool KolabBase::saveAttributes( QDomElement& element ) const { writeString( element, "product-id", productID() ); writeString( element, "uid", uid() ); writeString( element, "body", body() ); writeString( element, "categories", categories() ); writeString( element, "creation-date", dateTimeToString( creationDate().toUtc() ) ); writeString( element, "last-modification-date", dateTimeToString( lastModified().toUtc() ) ); writeString( element, "sensitivity", sensitivityToString( sensitivity() ) ); if ( hasPilotSyncId() ) writeString( element, "pilot-sync-id", QString::number( pilotSyncId() ) ); if ( hasPilotSyncStatus() ) writeString( element, "pilot-sync-status", QString::number( pilotSyncStatus() ) ); return true; } bool KolabBase::load( const QString& xml ) { const QDomDocument document = loadDocument( xml ); if ( document.isNull() ) return false; // XML file loaded into tree. Now parse it return loadXML( document ); } QDomDocument KolabBase::loadDocument( const QString& xmlData ) { QString errorMsg; int errorLine, errorColumn; QDomDocument document; bool ok = document.setContent( xmlData, &errorMsg, &errorLine, &errorColumn ); if ( !ok ) { qWarning( "Error loading document: %s, line %d, column %d", qPrintable( errorMsg ), errorLine, errorColumn ); return QDomDocument(); } return document; } QDomDocument KolabBase::domTree() { QDomDocument document; QString p = "version=\"1.0\" encoding=\"UTF-8\""; document.appendChild(document.createProcessingInstruction( "xml", p ) ); return document; } QString KolabBase::dateTimeToString( const KDateTime& time ) { return time.toString( KDateTime::ISODate ); } QString KolabBase::dateToString( const QDate& date ) { return date.toString( Qt::ISODate ); } KDateTime KolabBase::stringToDateTime( const QString& _date ) { const QString date( _date ); return KDateTime::fromString( date, KDateTime::ISODate ); } QDate KolabBase::stringToDate( const QString& date ) { return QDate::fromString( date, Qt::ISODate ); } QString KolabBase::sensitivityToString( Sensitivity s ) { switch( s ) { case Private: return "private"; case Confidential: return "confidential"; case Public: return "public"; } return "What what what???"; } KolabBase::Sensitivity KolabBase::stringToSensitivity( const QString& s ) { if ( s == "private" ) return Private; if ( s == "confidential" ) return Confidential; return Public; } QString KolabBase::colorToString( const QColor& color ) { // Color is in the format "#RRGGBB" return color.name(); } QColor KolabBase::stringToColor( const QString& s ) { return QColor( s ); } void KolabBase::writeString( QDomElement& element, const QString& tag, const QString& tagString ) { if ( !tagString.isEmpty() ) { QDomElement e = element.ownerDocument().createElement( tag ); QDomText t = element.ownerDocument().createTextNode( tagString ); e.appendChild( t ); element.appendChild( e ); } } KDateTime KolabBase::localToUTC( const KDateTime& time ) const { return time.toUtc(); } KDateTime KolabBase::utcToLocal( const KDateTime& time ) const { KDateTime dt = time; dt.setTimeSpec( KDateTime::UTC ); return dt; } libkolab-1.0.2/kolabformatV2/kolabbase.h000066400000000000000000000132211262531616600201050ustar00rootroot00000000000000/* This file is part of the kolab resource - the implementation of the Kolab storage format. See www.kolab.org for documentation on this. Copyright (c) 2004 Bo Thorsen 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. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef KOLABV2BASE_H #define KOLABV2BASE_H #include #include #include #include #include namespace KContacts { class Addressee; class ContactGroup; } namespace KolabV2 { class KolabBase { public: struct Email { public: Email( const QString& name = QString(), const QString& email = QString() ) : displayName( name ), smtpAddress( email ) { } QString displayName; QString smtpAddress; }; enum Sensitivity { Public = 0, Private = 1, Confidential = 2 }; explicit KolabBase( const QString& time_zone = QString() ); virtual ~KolabBase(); // Return a string identifying this type virtual QString type() const = 0; virtual void setUid( const QString& uid ); virtual QString uid() const; virtual void setBody( const QString& body ); virtual QString body() const; virtual void setCategories( const QString& categories ); virtual QString categories() const; virtual void setCreationDate( const KDateTime& date ); virtual KDateTime creationDate() const; virtual void setLastModified( const KDateTime& date ); virtual KDateTime lastModified() const; virtual void setSensitivity( Sensitivity sensitivity ); virtual Sensitivity sensitivity() const; virtual void setPilotSyncId( unsigned long id ); virtual bool hasPilotSyncId() const; virtual unsigned long pilotSyncId() const; virtual void setPilotSyncStatus( int status ); virtual bool hasPilotSyncStatus() const; virtual int pilotSyncStatus() const; // String - Date conversion methods static QString dateTimeToString( const KDateTime& time ); static QString dateToString( const QDate& date ); static KDateTime stringToDateTime( const QString& time ); static QDate stringToDate( const QString& date ); // String - Sensitivity conversion methods static QString sensitivityToString( Sensitivity ); static Sensitivity stringToSensitivity( const QString& ); // String - Color conversion methods static QString colorToString( const QColor& ); static QColor stringToColor( const QString& ); // Load this object by reading the XML file bool load( const QString& xml ); static QDomDocument loadDocument( const QString& xmlData ); // Load this QDomDocument virtual bool loadXML( const QDomDocument& xml ) = 0; // Serialize this object to an XML string virtual QString saveXML() const = 0; protected: /// Read all known fields from this ical incidence void setFields( const KCalCore::Incidence::Ptr & ); /// Save all known fields into this ical incidence void saveTo( const KCalCore::Incidence::Ptr & ) const; /// Read all known fields from this contact void setFields( const KContacts::Addressee* ); /// Save all known fields into this contact void saveTo( KContacts::Addressee* ) const; /// Read all known fields from this contact group void setFields( const KContacts::ContactGroup* ); /// Save all known fields into this contact groupd void saveTo( KContacts::ContactGroup* ) const; // This just makes the initial dom tree with version and doctype static QDomDocument domTree(); bool loadEmailAttribute( QDomElement& element, Email& email ); void saveEmailAttribute( QDomElement& element, const Email& email, const QString& tagName = "email" ) const; // Load the attributes of this class virtual bool loadAttribute( QDomElement& ); // Save the attributes of this class virtual bool saveAttributes( QDomElement& ) const; // Return the product ID virtual QString productID() const = 0; // Write a string tag static void writeString( QDomElement&, const QString&, const QString& ); KDateTime localToUTC( const KDateTime& time ) const; KDateTime utcToLocal( const KDateTime& time ) const; QString mUid; QString mBody; QString mCategories; KDateTime mCreationDate; KDateTime mLastModified; Sensitivity mSensitivity; KTimeZone mTimeZone; // KPilot synchronization stuff bool mHasPilotSyncId, mHasPilotSyncStatus; unsigned long mPilotSyncId; int mPilotSyncStatus; }; } #endif // KOLABBASE_H libkolab-1.0.2/kolabformatV2/note.cpp000066400000000000000000000143631262531616600174720ustar00rootroot00000000000000/* This file is part of the kolab resource - the implementation of the Kolab storage format. See www.kolab.org for documentation on this. Copyright (c) 2004 Bo Thorsen 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. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "note.h" #include "libkolab-version.h" #include #include using namespace KolabV2; KCalCore::Journal::Ptr Note::xmlToJournal( const QString& xml ) { Note note; note.load( xml ); KCalCore::Journal::Ptr journal( new KCalCore::Journal() ); note.saveTo( journal ); return journal; } QString Note::journalToXML( const KCalCore::Journal::Ptr &journal ) { Note note( journal ); return note.saveXML(); } Note::Note( const KCalCore::Journal::Ptr &journal ) : mRichText( false ) { if ( journal ) setFields( journal ); } Note::~Note() { } void Note::setSummary( const QString& summary ) { mSummary = summary; } QString Note::summary() const { return mSummary; } void Note::setBackgroundColor( const QColor& bgColor ) { mBackgroundColor = bgColor; } QColor Note::backgroundColor() const { return mBackgroundColor; } void Note::setForegroundColor( const QColor& fgColor ) { mForegroundColor = fgColor; } QColor Note::foregroundColor() const { return mForegroundColor; } void Note::setRichText( bool richText ) { mRichText = richText; } bool Note::richText() const { return mRichText; } bool Note::loadAttribute( QDomElement& element ) { QString tagName = element.tagName(); if ( tagName == "summary" ) setSummary( element.text() ); else if ( tagName == "foreground-color" ) setForegroundColor( stringToColor( element.text() ) ); else if ( tagName == "background-color" ) setBackgroundColor( stringToColor( element.text() ) ); else if ( tagName == "knotes-richtext" ) mRichText = ( element.text() == "true" ); else return KolabBase::loadAttribute( element ); // We handled this return true; } bool Note::saveAttributes( QDomElement& element ) const { // Save the base class elements KolabBase::saveAttributes( element ); // Save the elements #if 0 QDomComment c = element.ownerDocument().createComment( "Note specific attributes" ); element.appendChild( c ); #endif writeString( element, "summary", summary() ); if ( foregroundColor().isValid() ) writeString( element, "foreground-color", colorToString( foregroundColor() ) ); if ( backgroundColor().isValid() ) writeString( element, "background-color", colorToString( backgroundColor() ) ); writeString( element, "knotes-richtext", mRichText ? "true" : "false" ); return true; } bool Note::loadXML( const QDomDocument& document ) { QDomElement top = document.documentElement(); if ( top.tagName() != "note" ) { qWarning( "XML error: Top tag was %s instead of the expected note", top.tagName().toAscii().data() ); return false; } for ( QDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling() ) { if ( n.isComment() ) continue; if ( n.isElement() ) { QDomElement e = n.toElement(); if ( !loadAttribute( e ) ) // TODO: Unhandled tag - save for later storage qDebug() <<"Warning: Unhandled tag" << e.tagName(); } else qDebug() <<"Node is not a comment or an element???"; } return true; } QString Note::saveXML() const { QDomDocument document = domTree(); QDomElement element = document.createElement( "note" ); element.setAttribute( "version", "1.0" ); saveAttributes( element ); document.appendChild( element ); return document.toString(); } void Note::setFields( const KCalCore::Journal::Ptr &journal ) { KolabBase::setFields( journal ); setSummary( journal->summary() ); QString property = journal->customProperty( "KNotes", "BgColor" ); if ( !property.isEmpty() ) { setBackgroundColor( property ); } else { setBackgroundColor( "yellow" ); } property = journal->customProperty( "KNotes", "FgColor" ); if ( !property.isEmpty() ) { setForegroundColor( property ); } else { setForegroundColor( "black" ); } property = journal->customProperty( "KNotes", "RichText" ); if ( !property.isEmpty() ) { setRichText( property == "true" ? true : false ); } else { setRichText( "false" ); } } void Note::saveTo( const KCalCore::Journal::Ptr &journal ) { KolabBase::saveTo( journal ); // TODO: background and foreground journal->setSummary( summary() ); if ( foregroundColor().isValid() ) journal->setCustomProperty( "KNotes", "FgColor", colorToString( foregroundColor() ) ); if ( backgroundColor().isValid() ) journal->setCustomProperty( "KNotes", "BgColor", colorToString( backgroundColor() ) ); journal->setCustomProperty( "KNotes", "RichText", richText() ? "true" : "false" ); } QString Note::productID() const { return QString( "KNotes %1, Kolab resource" ).arg( LIBKOLAB_LIB_VERSION_STRING ); } libkolab-1.0.2/kolabformatV2/note.h000066400000000000000000000071451262531616600171370ustar00rootroot00000000000000/* This file is part of the kolab resource - the implementation of the Kolab storage format. See www.kolab.org for documentation on this. Copyright (c) 2004 Bo Thorsen 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. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef KOLABV2_NOTE_H #define KOLABV2_NOTE_H #include #include "kolabbase.h" class QDomElement; namespace KolabV2 { /** * This class represents a note, and knows how to load/save it * from/to XML, and from/to a KCalCore::Journal. * The instances of this class are temporary, only used to convert * one to the other. */ class Note : public KolabBase { public: /// Use this to parse an xml string to a journal entry /// The caller is responsible for deleting the returned journal static KCalCore::Journal::Ptr xmlToJournal( const QString& xml ); /// Use this to get an xml string describing this journal entry static QString journalToXML( const KCalCore::Journal::Ptr & ); /// Create a note object and explicit Note( const KCalCore::Journal::Ptr &journal = KCalCore::Journal::Ptr() ); virtual ~Note(); void saveTo( const KCalCore::Journal::Ptr &journal ); virtual QString type() const { return "Note"; } virtual void setSummary( const QString& summary ); virtual QString summary() const; virtual void setBackgroundColor( const QColor& bgColor ); virtual QColor backgroundColor() const; virtual void setForegroundColor( const QColor& fgColor ); virtual QColor foregroundColor() const; virtual void setRichText( bool richText ); virtual bool richText() const; // Load the attributes of this class virtual bool loadAttribute( QDomElement& ); // Save the attributes of this class virtual bool saveAttributes( QDomElement& ) const; // Load this note by reading the XML file virtual bool loadXML( const QDomDocument& xml ); // Serialize this note to an XML string virtual QString saveXML() const; protected: // Read all known fields from this ical incidence void setFields( const KCalCore::Journal::Ptr & ); // Save all known fields into this ical incidence void saveTo( const KCalCore::Incidence::Ptr & ) const; QString productID() const; QString mSummary; QColor mBackgroundColor; QColor mForegroundColor; bool mRichText; }; } #endif // KOLAB_NOTE_H libkolab-1.0.2/kolabformatV2/task.cpp000066400000000000000000000223551262531616600174670ustar00rootroot00000000000000/* This file is part of the kolab resource - the implementation of the Kolab storage format. See www.kolab.org for documentation on this. Copyright (c) 2004 Bo Thorsen 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. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "task.h" #include #include using namespace KolabV2; KCalCore::Todo::Ptr Task::fromXml( const QDomDocument& xmlDoc, const QString& tz ) { Task task( tz ); task.loadXML( xmlDoc ); KCalCore::Todo::Ptr todo( new KCalCore::Todo() ); task.saveTo( todo ); return todo; } QString Task::taskToXML( const KCalCore::Todo::Ptr &todo, const QString& tz ) { Task task( tz, todo ); return task.saveXML(); } Task::Task( const QString& tz, const KCalCore::Todo::Ptr &task ) : Incidence( tz, task ), mPercentCompleted( 0 ), mStatus( KCalCore::Incidence::StatusNone ), mHasStartDate( false ), mHasDueDate( false ), mHasCompletedDate( false ) { if ( task ) { setFields( task ); } } Task::~Task() { } void Task::setPercentCompleted( int percent ) { mPercentCompleted = percent; } int Task::percentCompleted() const { return mPercentCompleted; } void Task::setStatus( KCalCore::Incidence::Status status ) { mStatus = status; } KCalCore::Incidence::Status Task::status() const { return mStatus; } void Task::setParent( const QString& parentUid ) { mParent = parentUid; } QString Task::parent() const { return mParent; } void Task::setDueDate( const KDateTime &date ) { mDueDate = date; mHasDueDate = true; } void Task::setDueDate( const QDate &date ) { mDueDate = KDateTime( date ); mHasDueDate = true; mFloatingStatus = AllDay; } void Task::setDueDate( const QString &date ) { if ( date.length() > 10 ) { // This is a date + time setDueDate( stringToDateTime( date ) ); } else { // This is only a date setDueDate( stringToDate( date ) ); } } KDateTime Task::dueDate() const { return mDueDate; } void Task::setHasStartDate( bool v ) { mHasStartDate = v; } bool Task::hasStartDate() const { return mHasStartDate; } bool Task::hasDueDate() const { return mHasDueDate; } void Task::setCompletedDate( const KDateTime& date ) { mCompletedDate = date; mHasCompletedDate = true; } KDateTime Task::completedDate() const { return mCompletedDate; } bool Task::hasCompletedDate() const { return mHasCompletedDate; } bool Task::loadAttribute( QDomElement& element ) { QString tagName = element.tagName(); if ( tagName == "completed" ) { bool ok; int percent = element.text().toInt( &ok ); if ( !ok || percent < 0 || percent > 100 ) percent = 0; setPercentCompleted( percent ); } else if ( tagName == "status" ) { if ( element.text() == "in-progress" ) setStatus( KCalCore::Incidence::StatusInProcess ); else if ( element.text() == "completed" ) setStatus( KCalCore::Incidence::StatusCompleted ); else if ( element.text() == "waiting-on-someone-else" ) setStatus( KCalCore::Incidence::StatusNeedsAction ); else if ( element.text() == "deferred" ) // Guessing a status here setStatus( KCalCore::Incidence::StatusCanceled ); else // Default setStatus( KCalCore::Incidence::StatusNone ); } else if ( tagName == "due-date" ) { setDueDate( element.text() ); } else if ( tagName == "parent" ) { setParent( element.text() ); } else if ( tagName == "x-completed-date" ) { setCompletedDate( stringToDateTime( element.text() ) ); } else if ( tagName == "start-date" ) { setHasStartDate( true ); setStartDate( element.text() ); } else return Incidence::loadAttribute( element ); // We handled this return true; } bool Task::saveAttributes( QDomElement& element ) const { // Save the base class elements Incidence::saveAttributes( element ); writeString( element, "completed", QString::number( percentCompleted() ) ); switch( status() ) { case KCalCore::Incidence::StatusInProcess: writeString( element, "status", "in-progress" ); break; case KCalCore::Incidence::StatusCompleted: writeString( element, "status", "completed" ); break; case KCalCore::Incidence::StatusNeedsAction: writeString( element, "status", "waiting-on-someone-else" ); break; case KCalCore::Incidence::StatusCanceled: writeString( element, "status", "deferred" ); break; case KCalCore::Incidence::StatusNone: writeString( element, "status", "not-started" ); break; case KCalCore::Incidence::StatusTentative: case KCalCore::Incidence::StatusConfirmed: case KCalCore::Incidence::StatusDraft: case KCalCore::Incidence::StatusFinal: case KCalCore::Incidence::StatusX: // All of these are saved as StatusNone. writeString( element, "status", "not-started" ); break; } if ( hasDueDate() ) { if ( mFloatingStatus == HasTime ) { writeString( element, "due-date", dateTimeToString( dueDate() ) ); } else { writeString( element, "due-date", dateToString( dueDate().date() ) ); } } if ( !parent().isNull() ) { writeString( element, "parent", parent() ); } if ( hasCompletedDate() && percentCompleted() == 100 ) { writeString( element, "x-completed-date", dateTimeToString( completedDate() ) ); } return true; } bool Task::loadXML( const QDomDocument& document ) { QDomElement top = document.documentElement(); if ( top.tagName() != "task" ) { qWarning( "XML error: Top tag was %s instead of the expected task", top.tagName().toAscii().data() ); return false; } setHasStartDate( false ); // todo's don't necessarily have one for ( QDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling() ) { if ( n.isComment() ) continue; if ( n.isElement() ) { QDomElement e = n.toElement(); if ( !loadAttribute( e ) ) // TODO: Unhandled tag - save for later storage qDebug() <<"Warning: Unhandled tag" << e.tagName(); } else qDebug() <<"Node is not a comment or an element???"; } return true; } QString Task::saveXML() const { QDomDocument document = domTree(); QDomElement element = document.createElement( "task" ); element.setAttribute( "version", "1.0" ); saveAttributes( element ); if ( !hasStartDate() && startDate().isValid() ) { // events and journals always have a start date, but tasks don't. // Remove the entry done by the inherited save above, because we // don't have one. QDomNodeList l = element.elementsByTagName( "start-date" ); Q_ASSERT( l.count() == 1 ); element.removeChild( l.item( 0 ) ); } document.appendChild( element ); return document.toString(); } void Task::setFields( const KCalCore::Todo::Ptr &task ) { Incidence::setFields( task ); setPercentCompleted( task->percentComplete() ); setStatus( task->status() ); setHasStartDate( task->hasStartDate() ); if ( task->hasDueDate() ) { if ( task->allDay() ) { // This is a floating task. Don't timezone move this one mFloatingStatus = AllDay; setDueDate( KDateTime( task->dtDue().date() ) ); } else { mFloatingStatus = HasTime; setDueDate( localToUTC( task->dtDue() ) ); } } else { mHasDueDate = false; } if ( !task->relatedTo().isEmpty() ) { setParent( task->relatedTo() ); } else{ setParent( QString() ); } if ( task->hasCompletedDate() && task->percentComplete() == 100 ) { setCompletedDate( localToUTC( task->completed() ) ); } else { mHasCompletedDate = false; } } void Task::saveTo( const KCalCore::Todo::Ptr &task ) { Incidence::saveTo( task ); task->setPercentComplete( percentCompleted() ); task->setStatus( status() ); //PORT KF5 task->setHasStartDate( hasStartDate() ); //PORT KF5 task->setHasDueDate( hasDueDate() ); if ( hasDueDate() ) task->setDtDue( utcToLocal( dueDate() ) ); if ( !parent().isEmpty() ) { task->setRelatedTo( parent() ); } if ( hasCompletedDate() && task->percentComplete() == 100 ) task->setCompleted( utcToLocal( mCompletedDate ) ); } libkolab-1.0.2/kolabformatV2/task.h000066400000000000000000000103041262531616600171230ustar00rootroot00000000000000/* This file is part of the kolab resource - the implementation of the Kolab storage format. See www.kolab.org for documentation on this. Copyright (c) 2004 Bo Thorsen 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. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef KOLABV2_TASK_H #define KOLABV2_TASK_H #include "incidence.h" #include #include class QDomElement; namespace KCal { class ResourceKolab; } namespace KolabV2 { /** * This class represents a task, and knows how to load/save it * from/to XML, and from/to a KCalCore::Todo. * The instances of this class are temporary, only used to convert * one to the other. */ class Task : public Incidence { public: /// Use this to parse an xml string to a task entry /// The caller is responsible for deleting the returned task static KCalCore::Todo::Ptr fromXml( const QDomDocument& xmlDoc, const QString& tz/*, KCalCore::ResourceKolab *res = 0, const QString& subResource = QString(), quint32 sernum = 0 */); /// Use this to get an xml string describing this task entry static QString taskToXML( const KCalCore::Todo::Ptr &, const QString& tz ); explicit Task( /*KCalCore::ResourceKolab *res, const QString& subResource, quint32 sernum,*/ const QString& tz, const KCalCore::Todo::Ptr &todo = KCalCore::Todo::Ptr() ); virtual ~Task(); virtual QString type() const { return "Task"; } void saveTo( const KCalCore::Todo::Ptr &todo ); virtual void setPercentCompleted( int percent ); virtual int percentCompleted() const; virtual void setStatus( KCalCore::Incidence::Status status ); virtual KCalCore::Incidence::Status status() const; virtual void setParent( const QString& parentUid ); virtual QString parent() const; virtual void setHasStartDate( bool ); virtual bool hasStartDate() const; virtual void setDueDate( const KDateTime& date ); virtual void setDueDate( const QString &date ); virtual void setDueDate( const QDate &date ); virtual KDateTime dueDate() const; virtual bool hasDueDate() const; virtual void setCompletedDate( const KDateTime& date ); virtual KDateTime completedDate() const; virtual bool hasCompletedDate() const; // Load the attributes of this class virtual bool loadAttribute( QDomElement& ); // Save the attributes of this class virtual bool saveAttributes( QDomElement& ) const; // Load this task by reading the XML file virtual bool loadXML( const QDomDocument& xml ); // Serialize this task to an XML string virtual QString saveXML() const; protected: // Read all known fields from this ical todo void setFields( const KCalCore::Todo::Ptr & ); int mPercentCompleted; KCalCore::Incidence::Status mStatus; QString mParent; bool mHasStartDate; bool mHasDueDate; KDateTime mDueDate; bool mHasCompletedDate; KDateTime mCompletedDate; }; } #endif // KOLAB_TASK_H libkolab-1.0.2/libkolab-version.h.cmake000066400000000000000000000017121262531616600177740ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef LIBKOLAB_VERSION_H #define LIBKOLAB_VERSION_H #define LIBKOLAB_LIBNAME "@CMAKE_PROJECT_NAME@" #define LIBKOLAB_LIB_VERSION "@Libkolab_VERSION@" #define LIBKOLAB_LIB_VERSION_STRING "@Libkolab_VERSION_STRING@" #endiflibkolab-1.0.2/mime/000077500000000000000000000000001262531616600142305ustar00rootroot00000000000000libkolab-1.0.2/mime/mimeutils.cpp000066400000000000000000000217661262531616600167600ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include "mimeutils.h" #include #include #include #include #include "kolabformat/kolabdefinitions.h" #include "kolabformat/errorhandler.h" #include #include "libkolab-version.h" namespace Kolab { namespace Mime { KMime::Content* findContentByType(const KMime::Message::Ptr &data, const QByteArray &type) { if (type.isEmpty()) { Error() << "Empty type"; return 0; } Q_ASSERT(!data->contents().isEmpty()); Q_FOREACH(KMime::Content *c, data->contents()) { // qDebug() << c->contentType()->mimeType() << type; if (c->contentType()->mimeType() == type) { return c; } } return 0; } KMime::Content* findContentByName(const KMime::Message::Ptr &data, const QString &name, QByteArray &type) { Q_ASSERT(!data->contents().isEmpty()); Q_FOREACH(KMime::Content *c, data->contents()) { // qDebug() << "searching: " << c->contentType()->name().toUtf8(); if ( c->contentType()->name() == name ) { type = c->contentType()->mimeType(); return c; } } return 0; } KMime::Content* findContentById(const KMime::Message::Ptr &data, const QByteArray &id, QByteArray &type, QString &name) { if (id.isEmpty()) { Error() << "looking for empty cid"; return 0; } Q_ASSERT(!data->contents().isEmpty()); Q_FOREACH(KMime::Content *c, data->contents()) { // qDebug() << "searching: " << c->contentID()->identifier(); if ( c->contentID()->identifier() == id ) { type = c->contentType()->mimeType(); name = c->contentType()->name(); return c; } } return 0; } QList getContentMimeTypeList(const KMime::Message::Ptr& data) { QList typeList; Q_ASSERT(!data->contents().isEmpty()); Q_FOREACH(KMime::Content *c, data->contents()) { typeList.append(c->contentType()->mimeType()); } return typeList; } QString fromCid(const QString &cid) { if (cid.left(4) != QString::fromLatin1("cid:")) { //Don't set if not a cid, happens when serializing format v2 return QString(); } return cid.right(cid.size()-4); } KMime::Message::Ptr createMessage(const QByteArray &mimetype, const QByteArray &xKolabType, const QByteArray &xml, bool v3, const QByteArray &productId, const QByteArray &fromEmail, const QString &fromName, const QString &subject) { KMime::Message::Ptr message = createMessage(xKolabType, v3, productId); message->subject()->fromUnicodeString(subject, "utf-8"); if (!fromEmail.isEmpty()) { KMime::Types::Mailbox mb; mb.setName(fromName); mb.setAddress(fromEmail); message->from()->addAddress(mb); } message->addContent(createMainPart(mimetype, xml)); return message; } KMime::Message::Ptr createMessage(const std::string &mimetype, const std::string &xKolabType, const std::string &xml, bool v3, const std::string &productId, const std::string &fromEmail, const std::string &fromName, const std::string &subject) { return createMessage(QByteArray(mimetype.c_str()), QByteArray(xKolabType.c_str()), QByteArray(xml.c_str()), v3, QByteArray(productId.data()), QByteArray(fromEmail.c_str()), QString::fromStdString(fromName), QString::fromStdString(subject)); } KMime::Message::Ptr createMessage(const QString &subject, const QString &mimetype, const QString &xKolabType, const QByteArray &xml, bool v3, const QString &prodid) { KMime::Message::Ptr message = createMessage( xKolabType.toLatin1(), v3, prodid.toLatin1() ); if (!subject.isEmpty()) { message->subject()->fromUnicodeString( subject, "utf-8" ); } KMime::Content *content = createMainPart( mimetype.toLatin1(), xml ); message->addContent( content ); message->assemble(); return message; } KMime::Content* createExplanationPart(bool v3) { KMime::Content *content = new KMime::Content(); content->contentType()->setMimeType( "text/plain" ); content->contentType()->setCharset( "us-ascii" ); content->contentTransferEncoding()->setEncoding( KMime::Headers::CE7Bit ); if (v3) { content->setBody( "This is a Kolab Groupware object.\n" "To view this object you will need an email client that can understand the Kolab Groupware format.\n" "For a list of such email clients please visit\n" "http://www.kolab.org/get-kolab\n" ); } else { content->setBody( "This is a Kolab Groupware object.\n" "To view this object you will need an email client that can understand the Kolab Groupware format.\n" "For a list of such email clients please visit\n" "http://www.kolab.org/get-kolab\n" ); } return content; } KMime::Message::Ptr createMessage(const QByteArray& xKolabType, bool v3, const QByteArray &prodid) { KMime::Message::Ptr message(new KMime::Message); message->date()->setDateTime(KDateTime::currentUtcDateTime().dateTime()); KMime::Headers::Generic* h = new KMime::Headers::Generic(X_KOLAB_TYPE_HEADER); h->fromUnicodeString(xKolabType, "utf-8"); message->appendHeader(h); if (v3) { KMime::Headers::Generic* hv3 = new KMime::Headers::Generic(X_KOLAB_MIME_VERSION_HEADER); hv3->fromUnicodeString(KOLAB_VERSION_V3, "utf-8"); message->appendHeader(hv3); } message->userAgent()->from7BitString(prodid); message->contentType()->setMimeType("multipart/mixed"); message->contentType()->setBoundary(KMime::multiPartBoundary()); message->addContent(createExplanationPart(v3)); return message; } KMime::Content* createMainPart(const QByteArray& mimeType, const QByteArray& decodedContent) { KMime::Content* content = new KMime::Content(); content->contentType()->setMimeType(mimeType); content->contentType()->setName(KOLAB_OBJECT_FILENAME, "us-ascii"); content->contentTransferEncoding()->setEncoding( KMime::Headers::CEquPr ); content->contentDisposition()->setDisposition( KMime::Headers::CDattachment ); content->contentDisposition()->setFilename( KOLAB_OBJECT_FILENAME ); content->setBody(decodedContent); return content; } KMime::Content* createAttachmentPart(const QByteArray& cid, const QByteArray& mimeType, const QString& fileName, const QByteArray& base64EncodedContent) { KMime::Content* content = new KMime::Content(); if (!cid.isEmpty()) { content->contentID()->setIdentifier( cid ); } content->contentType()->setMimeType( mimeType ); content->contentType()->setName( fileName, "utf-8" ); content->contentTransferEncoding()->setEncoding( KMime::Headers::CEbase64 ); content->contentDisposition()->setDisposition( KMime::Headers::CDattachment ); content->contentDisposition()->setFilename( fileName ); content->setBody( base64EncodedContent ); return content; } Kolab::Attachment getAttachment(const std::string &id, const KMime::Message::Ptr &mimeData) { if (!QString::fromStdString(id).contains("cid:")) { Error() << "not a cid reference"; return Kolab::Attachment(); } QByteArray type; QString name; KMime::Content *content = findContentById(mimeData, fromCid(QString::fromStdString(id)).toLatin1(), type, name); if (!content) { // guard against malformed events with non-existent attachments Error() << "could not find attachment: "<< name << type; return Kolab::Attachment(); } // Debug() << id << content->decodedContent().toBase64().toStdString(); Kolab::Attachment attachment; attachment.setData(content->decodedContent().toStdString(), type.toStdString()); attachment.setLabel(name.toStdString()); return attachment; } Kolab::Attachment getAttachmentByName(const QString &name, const KMime::Message::Ptr &mimeData) { QByteArray type; KMime::Content *content = findContentByName(mimeData, name, type); if (!content) { // guard against malformed events with non-existent attachments Warning() << "could not find attachment: "<< name.toUtf8() << type; return Kolab::Attachment(); } Kolab::Attachment attachment; attachment.setData(content->decodedContent().toStdString(), type.toStdString()); attachment.setLabel(name.toStdString()); return attachment; } }; //Namespace }; //Namespace libkolab-1.0.2/mime/mimeutils.h000066400000000000000000000052661262531616600164220ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef KOLABMIMEUTILS_H #define KOLABMIMEUTILS_H #include "kolab_export.h" #include class QDomDocument; namespace Kolab { class Attachment; namespace Mime { KMime::Content* findContentByName(const KMime::Message::Ptr &data, const QString &name, QByteArray &type); KMime::Content* findContentByType(const KMime::Message::Ptr &data, const QByteArray &type); QList getContentMimeTypeList(const KMime::Message::Ptr &data); /** * Get Attachments from a Mime message * * Set the attachments listed in @param attachments on @param incidence from @param mimeData */ Kolab::Attachment getAttachment(const std::string &id, const KMime::Message::Ptr &mimeData); Kolab::Attachment getAttachmentByName(const QString &name, const KMime::Message::Ptr &mimeData); KMime::Message::Ptr createMessage(const QByteArray &mimetype, const QByteArray &xKolabType, const QByteArray &xml, bool v3, const QByteArray &productId, const QByteArray &fromEmail, const QString &fromName, const QString &subject); KMime::Message::Ptr createMessage(const std::string &mimetype, const std::string &xKolabType, const std::string &xml, bool v3, const std::string &productId, const std::string &fromEmail, const std::string &fromName, const std::string &subject); ///Generic serializing functions KMime::Message::Ptr createMessage(const QString &subject, const QString &mimetype, const QString &xKolabType, const QByteArray &xml, bool v3, const QString &prodid); KMime::Message::Ptr createMessage(const QByteArray& mimeType, bool v3, const QByteArray &prodid); KMime::Content* createExplanationPart(); KMime::Content* createMainPart(const QByteArray& mimeType, const QByteArray& decodedContent); KMime::Content* createAttachmentPart(const QByteArray& cid, const QByteArray& mimeType, const QString& fileName, const QByteArray& decodedContent); QString fromCid(const QString &cid); }; }; //Namespace #endif libkolab-1.0.2/shared.i000066400000000000000000000010151262531616600147160ustar00rootroot00000000000000 %{ /* This macro ensures that return vectors remain a vector also in python and are not converted to tuples */ #define SWIG_PYTHON_EXTRA_NATIVE_CONTAINERS #include %} %include "std_vector.i" %import(module="kolabformat") namespace std { /* vectorevent moved to libkolabxml, vectorevent2 breaks the pythonbindings without vectorevent in here (compile error) */ /* %template(vectorevent) vector; */ /* %template(vectorevent2) vector< vector >; */ }; libkolab-1.0.2/tests/000077500000000000000000000000001262531616600144435ustar00rootroot00000000000000libkolab-1.0.2/tests/CMakeLists.txt000066400000000000000000000026271262531616600172120ustar00rootroot00000000000000 include_directories(${CMAKE_CURRENT_BINARY_DIR}) add_definitions(-DTEST_DATA_PATH="${CMAKE_CURRENT_SOURCE_DIR}") set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) macro(addTest TEST_NAME) add_executable(${TEST_NAME} ${TEST_NAME}.cpp) target_link_libraries(${TEST_NAME} Qt5::Test kolab_static) add_test(${TEST_NAME} ${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME}) endmacro() add_executable(benchmarktest benchmark.cpp) target_link_libraries(benchmarktest ${QT_QTTEST_LIBRARY} kolab_static) addTest(formattest) addTest(upgradetest) addTest(kcalconversiontest) addTest(calendaringtest) addTest(icalendartest) addTest(freebusytest) addTest(kolabobjecttest) addTest(timezonetest) addTest(mimeobjecttest) addTest(xmlobjecttest) addTest(debugstreamtest) addTest(legacyformattest) if(PHP_BINDINGS) find_path(PHP_KOLABFORMAT_PATH NAMES kolabformat.php PATHS /usr/local/lib/php/modules /usr/lib/php/modules PATH_SUFFIXES lib/php/modules lib64/php/modules) message("php kolabformat include path for testing ${PHP_KOLABFORMAT_PATH}") add_test(phptest php -d enable_dl=On -d include_path='.:/usr/share/pear:${CMAKE_BINARY_DIR}:${CMAKE_BINARY_DIR}/calendaring/php:${PHP_KOLABFORMAT_PATH}' -d extension=${CMAKE_BINARY_DIR}/lib/kolabcalendaring.so -d extension=${CMAKE_BINARY_DIR}/lib/kolabshared.so -d extension=${PHP_KOLABFORMAT_PATH}/kolabformat.so ${CMAKE_SOURCE_DIR}/calendaring/php/test.php --verbose) endif() libkolab-1.0.2/tests/benchmark.cpp000066400000000000000000000062001262531616600170770ustar00rootroot00000000000000/* * Copyright (C) 2011 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include "benchmark.h" #include "kolabformatV2/event.h" #include "conversion/kcalconversion.h" #include #include #include "testutils.h" KMime::Message::Ptr readMimeFile( const QString &fileName ) { QFile file( fileName ); file.open( QFile::ReadOnly ); const QByteArray data = file.readAll(); Q_ASSERT( !data.isEmpty() ); KMime::Message *msg = new KMime::Message; msg->setContent( data ); msg->parse(); return KMime::Message::Ptr(msg); } KMime::Content* findContentByType(const KMime::Message::Ptr &data, const QByteArray &type) { const KMime::Content::List list = data->contents(); Q_FOREACH(KMime::Content *c, list) { if (c->contentType()->mimeType() == type) return c; } return 0; } void BenchmarkTests::parsingBenchmarkComparison_data() { QTest::addColumn("v2Parser"); QTest::newRow("v2") << true; QTest::newRow("v3") << false; } void BenchmarkTests::parsingBenchmarkComparison() { const KMime::Message::Ptr kolabItem = readMimeFile( TESTFILEDIR+QString::fromLatin1("/v2/event/complex.ics.mime") ); KMime::Content *xmlContent = findContentByType( kolabItem, "application/x-vnd.kolab.event" ); QVERIFY ( xmlContent ); const QByteArray xmlData = xmlContent->decodedContent(); // qDebug() << xmlData; const QDomDocument xmlDoc = KolabV2::Event::loadDocument( QString::fromUtf8(xmlData) ); QVERIFY ( !xmlDoc.isNull() ); const KCalCore::Event::Ptr i = KolabV2::Event::fromXml( xmlDoc, QString::fromLatin1("Europe/Berlin") ); QVERIFY ( i ); const Kolab::Event &event = Kolab::Conversion::fromKCalCore(*i); const std::string &v3String = Kolab::writeEvent(event); QFETCH(bool, v2Parser); // Kolab::readEvent(v3String, false); //init parser (doesn't really change the results it seems) // qDebug() << QString::fromUtf8(xmlData); // qDebug() << "------------------------------------------------------------------------------------"; // qDebug() << QString::fromStdString(v3String); if (v2Parser) { QBENCHMARK { KolabV2::Event::fromXml( KolabV2::Event::loadDocument( QString::fromUtf8(xmlData) ), QString::fromLatin1("Europe/Berlin") ); } } else { QBENCHMARK { Kolab::readEvent(v3String, false); } } } QTEST_MAIN( BenchmarkTests ) #include "benchmark.moc" libkolab-1.0.2/tests/benchmark.h000066400000000000000000000020021262531616600165400ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef BENCHMARK_TEST_H #define BENCHMARK_TEST_H #include #include class BenchmarkTests : public QObject { Q_OBJECT private slots: void parsingBenchmarkComparison_data(); void parsingBenchmarkComparison(); }; #endif libkolab-1.0.2/tests/calendaringtest.cpp000066400000000000000000000454561262531616600203340ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include "calendaringtest.h" #include #include #include #include #include #include #include "testhelpers.h" #include "testutils.h" void compareEvents(const std::vector &list1, const std::vector &list2) { QCOMPARE(list1.size(), list2.size()); for (std::size_t i = 0; i < list1.size(); i++) { const Kolab::Event &e1 = list1.at(i); const Kolab::Event &e2 = list2.at(i); // qDebug() << i; // QCOMPARE(e1.uid(), e2.uid()); QCOMPARE(e1.start(), e2.start()); QCOMPARE(e1.end(), e2.end()); } } void CalendaringTest::initTestCase() { } void CalendaringTest::testCalendaringEvent() { Kolab::Event event; event.setUid("uid"); event.setStart(Kolab::cDateTime(2011,10,10,12,1,1,true)); event.setEnd(Kolab::cDateTime(2011,10,11,12,1,1,true)); Kolab::Calendaring::Event calEvent(event); QCOMPARE(event.start(), calEvent.start()); QCOMPARE(event.uid(), calEvent.uid()); Kolab::Calendaring::Event calEvent2; Kolab::Calendaring::Event calEvent3 = calEvent2; QVERIFY(!calEvent2.uid().empty()); QCOMPARE(calEvent2.uid(), calEvent3.uid()); } void CalendaringTest::testEventConflict_data() { QTest::addColumn( "e1" ); QTest::addColumn( "e2" ); QTest::addColumn( "result" ); { Kolab::Event e1; e1.setStart(Kolab::cDateTime(2011,10,10,12,1,1,true)); e1.setEnd(Kolab::cDateTime(2011,10,11,12,1,1,true)); Kolab::Event e2; e2.setStart(Kolab::cDateTime(2011,11,10,12,1,1,true)); e2.setEnd(Kolab::cDateTime(2011,11,11,12,1,1,true)); QTest::newRow( "after" ) << e1 << e2 << false; } { Kolab::Event e1; e1.setStart(Kolab::cDateTime(2011,10,10,12,1,1,true)); e1.setEnd(Kolab::cDateTime(2011,10,11,12,1,1,true)); Kolab::Event e2; e2.setStart(Kolab::cDateTime(2011,9,10,12,1,1,true)); e2.setEnd(Kolab::cDateTime(2011,9,11,12,1,1,true)); QTest::newRow( "before" ) << e1 << e2 << false; } { Kolab::Event e1; e1.setStart(Kolab::cDateTime(2011,10,10,12,1,1,true)); e1.setEnd(Kolab::cDateTime(2011,10,11,12,1,1,true)); Kolab::Event e2; e2.setStart(Kolab::cDateTime(2011,10,10,12,1,1,true)); e2.setEnd(Kolab::cDateTime(2011,10,11,12,1,1,true)); QTest::newRow( "conflict" ) << e1 << e2 << true; } { Kolab::Event e1; e1.setStart(Kolab::cDateTime("Europe/Zurich", 2011,10,10,6,1,1)); e1.setEnd(Kolab::cDateTime("Europe/Zurich", 2011,10,10,6,1,2)); Kolab::Event e2; e2.setStart(Kolab::cDateTime("Asia/Dubai",2011,10,10,6,1,1)); e2.setEnd(Kolab::cDateTime("Asia/Dubai",2011,10,10,6,1,2)); QTest::newRow( "tz non-conflict" ) << e1 << e2 << false; } { Kolab::Event e1; e1.setStart(Kolab::cDateTime("Europe/Berlin", 2011,10,10,6,1,1)); e1.setEnd(Kolab::cDateTime("Europe/Berlin", 2011,10,10,6,1,2)); Kolab::Event e2; e2.setStart(Kolab::cDateTime("Europe/Zurich",2011,10,10,6,1,1)); e2.setEnd(Kolab::cDateTime("Europe/Zurich",2011,10,10,6,1,2)); QTest::newRow( "tz conflict" ) << e1 << e2 << true; } } void CalendaringTest::testEventConflict() { QFETCH(Kolab::Event, e1); QFETCH(Kolab::Event, e2); QFETCH(bool, result); QCOMPARE(Kolab::Calendaring::conflicts(e1,e2), result); } void CalendaringTest::testEventConflictSet() { std::vector events; events.push_back(createEvent(Kolab::cDateTime(2011,10,6,12,1,1,true), Kolab::cDateTime(2011,10,8,12,1,1,true))); events.push_back(createEvent(Kolab::cDateTime(2011,10,7,12,1,1,true), Kolab::cDateTime(2011,10,10,12,1,1,true))); events.push_back(createEvent(Kolab::cDateTime(2011,10,9,12,1,1,true), Kolab::cDateTime(2011,10,11,12,1,1,true))); const std::vector< std::vector > &result = Kolab::Calendaring::getConflictingSets(events); std::vector< std::vector > expectedResult; std::vector r1; r1.push_back(createEvent(Kolab::cDateTime(2011,10,6,12,1,1,true), Kolab::cDateTime(2011,10,8,12,1,1,true))); r1.push_back(createEvent(Kolab::cDateTime(2011,10,7,12,1,1,true), Kolab::cDateTime(2011,10,10,12,1,1,true))); expectedResult.push_back(r1); std::vector r2; r2.push_back(createEvent(Kolab::cDateTime(2011,10,7,12,1,1,true), Kolab::cDateTime(2011,10,10,12,1,1,true))); r2.push_back(createEvent(Kolab::cDateTime(2011,10,9,12,1,1,true), Kolab::cDateTime(2011,10,11,12,1,1,true))); expectedResult.push_back(r2); for (std::size_t i = 0; i < result.size(); i++) { const std::vector &list = result.at(i); qDebug() << "---------_Set--------------"; foreach(const Kolab::Event &event, list) { qDebug() << QTest::toString(event.start()) << QTest::toString(event.end()); } compareEvents(result.at(i), expectedResult.at(i)); } } void CalendaringTest::testTimesInInterval_data() { QTest::addColumn( "event" ); QTest::addColumn( "start" ); QTest::addColumn( "end" ); QTest::addColumn< std::vector >( "result" ); { { Kolab::Event event; event.setStart(Kolab::cDateTime(2011,1,1,1,1,1,true)); event.setEnd(Kolab::cDateTime(2011,1,1,2,1,1,true)); Kolab::RecurrenceRule rrule; rrule.setFrequency(Kolab::RecurrenceRule::Daily); rrule.setInterval(1); rrule.setCount(5); event.setRecurrenceRule(rrule); std::vector result; result.push_back(Kolab::cDateTime(2011,1,1,1,1,1,true)); result.push_back(Kolab::cDateTime(2011,1,2,1,1,1,true)); result.push_back(Kolab::cDateTime(2011,1,3,1,1,1,true)); result.push_back(Kolab::cDateTime(2011,1,4,1,1,1,true)); result.push_back(Kolab::cDateTime(2011,1,5,1,1,1,true)); QTest::newRow( "simple" ) << event << Kolab::cDateTime(2011,1,1,1,1,1,true) << Kolab::cDateTime(2011,1,5,1,1,1,true) << result; } } } void CalendaringTest::testTimesInInterval() { QFETCH(Kolab::Event, event); QFETCH(Kolab::cDateTime, start); QFETCH(Kolab::cDateTime, end); QFETCH(std::vector, result); QCOMPARE(Kolab::Calendaring::timeInInterval(event,start, end), result); } void CalendaringTest::testTimesInIntervalBenchmark() { Kolab::Event event; event.setStart(Kolab::cDateTime(2011,1,1,1,1,1)); event.setEnd(Kolab::cDateTime(2011,1,1,2,1,1)); Kolab::RecurrenceRule rrule; rrule.setFrequency(Kolab::RecurrenceRule::Daily); rrule.setInterval(1); rrule.setCount(500); event.setRecurrenceRule(rrule); QBENCHMARK { Kolab::Calendaring::timeInInterval(event, Kolab::cDateTime(2011,1,1,1,1,1), Kolab::cDateTime(2013,1,1,1,1,1)); } const std::vector &result = Kolab::Calendaring::timeInInterval(event, Kolab::cDateTime(2011,1,1,1,1,1), Kolab::cDateTime(2013,1,1,1,1,1)); QVERIFY(result.size() == 500); // qDebug() << QTest::toString(result); } void CalendaringTest::testCalendar_data() { QTest::addColumn< std::vector >( "inputevents" ); QTest::addColumn( "start" ); QTest::addColumn( "end" ); QTest::addColumn< std::vector >( "expectedResult" ); { std::vector inputevents; for (int day = 1; day < 28; day++) { for (int hour = 1; hour < 20; hour+=2) { inputevents.push_back(createEvent(Kolab::cDateTime(2012,5,day,hour,4,4, true), Kolab::cDateTime(2012,5,day,hour+1,4,4, true))); } } std::vector expectedResult; expectedResult.push_back(createEvent(Kolab::cDateTime(2012,5,5,3,4,4, true), Kolab::cDateTime(2012,5,5,3+1,4,4, true))); expectedResult.push_back(createEvent(Kolab::cDateTime(2012,5,5,5,4,4, true), Kolab::cDateTime(2012,5,5,5+1,4,4, true))); expectedResult.push_back(createEvent(Kolab::cDateTime(2012,5,5,7,4,4, true), Kolab::cDateTime(2012,5,5,7+1,4,4, true))); expectedResult.push_back(createEvent(Kolab::cDateTime(2012,5,5,9,4,4, true), Kolab::cDateTime(2012,5,5,9+1,4,4, true))); expectedResult.push_back(createEvent(Kolab::cDateTime(2012,5,5,11,4,4, true), Kolab::cDateTime(2012,5,5,11+1,4,4, true))); expectedResult.push_back(createEvent(Kolab::cDateTime(2012,5,5,13,4,4, true), Kolab::cDateTime(2012,5,5,13+1,4,4, true))); expectedResult.push_back(createEvent(Kolab::cDateTime(2012,5,5,15,4,4, true), Kolab::cDateTime(2012,5,5,15+1,4,4, true))); expectedResult.push_back(createEvent(Kolab::cDateTime(2012,5,5,17,4,4, true), Kolab::cDateTime(2012,5,5,17+1,4,4, true))); expectedResult.push_back(createEvent(Kolab::cDateTime(2012,5,5,19,4,4, true), Kolab::cDateTime(2012,5,5,19+1,4,4, true))); expectedResult.push_back(createEvent(Kolab::cDateTime(2012,5,6,1,4,4, true), Kolab::cDateTime(2012,5,6,1+1,4,4, true))); expectedResult.push_back(createEvent(Kolab::cDateTime(2012,5,6,3,4,4, true), Kolab::cDateTime(2012,5,6,3+1,4,4, true))); QTest::newRow( "simple" ) << inputevents << Kolab::cDateTime(2012,5,5,4,4,4, true) << Kolab::cDateTime(2012,5,6,4,4,4, true) << expectedResult; } { //Start and end time inclusive std::vector inputevents; inputevents.push_back(createEvent(Kolab::cDateTime(2012,5,5,1,4,4, true), Kolab::cDateTime(2012,5,5,1+1,4,4, true))); inputevents.push_back(createEvent(Kolab::cDateTime(2012,5,5,3,4,4, true), Kolab::cDateTime(2012,5,5,3+1,4,4, true))); inputevents.push_back(createEvent(Kolab::cDateTime(2012,5,5,5,4,4, true), Kolab::cDateTime(2012,5,5,5+1,4,4, true))); inputevents.push_back(createEvent(Kolab::cDateTime(2012,5,5,7,4,4, true), Kolab::cDateTime(2012,5,5,7+1,4,4, true))); inputevents.push_back(createEvent(Kolab::cDateTime(2012,5,5,9,4,4, true), Kolab::cDateTime(2012,5,5,9+1,4,4, true))); std::vector expectedResult; expectedResult.push_back(createEvent(Kolab::cDateTime(2012,5,5,3,4,4, true), Kolab::cDateTime(2012,5,5,3+1,4,4, true))); expectedResult.push_back(createEvent(Kolab::cDateTime(2012,5,5,5,4,4, true), Kolab::cDateTime(2012,5,5,5+1,4,4, true))); expectedResult.push_back(createEvent(Kolab::cDateTime(2012,5,5,7,4,4, true), Kolab::cDateTime(2012,5,5,7+1,4,4, true))); QTest::newRow( "startEndTimeInclusive" ) << inputevents << Kolab::cDateTime(2012,5,5,3,4,4, true) << Kolab::cDateTime(2012,5,5,7,4,4, true) << expectedResult; } { //Start and end time inclusive (floating time) std::vector inputevents; inputevents.push_back(createEvent(Kolab::cDateTime(2012,5,5,1,4,4, false), Kolab::cDateTime(2012,5,5,1+1,4,4, false))); inputevents.push_back(createEvent(Kolab::cDateTime(2012,5,5,3,4,4, false), Kolab::cDateTime(2012,5,5,3+1,4,4, false))); inputevents.push_back(createEvent(Kolab::cDateTime(2012,5,5,5,4,4, false), Kolab::cDateTime(2012,5,5,5+1,4,4, false))); inputevents.push_back(createEvent(Kolab::cDateTime(2012,5,5,7,4,4, false), Kolab::cDateTime(2012,5,5,7+1,4,4, false))); inputevents.push_back(createEvent(Kolab::cDateTime(2012,5,5,9,4,4, false), Kolab::cDateTime(2012,5,5,9+1,4,4, false))); std::vector expectedResult; expectedResult.push_back(createEvent(Kolab::cDateTime(2012,5,5,3,4,4, false), Kolab::cDateTime(2012,5,5,3+1,4,4, false))); expectedResult.push_back(createEvent(Kolab::cDateTime(2012,5,5,5,4,4, false), Kolab::cDateTime(2012,5,5,5+1,4,4, false))); expectedResult.push_back(createEvent(Kolab::cDateTime(2012,5,5,7,4,4, false), Kolab::cDateTime(2012,5,5,7+1,4,4, false))); QTest::newRow( "startEndTimeInclusive" ) << inputevents << Kolab::cDateTime(2012,5,5,3,4,4, false) << Kolab::cDateTime(2012,5,5,7,4,4, false) << expectedResult; } { //Start and end time inclusive (timezone) std::vector inputevents; inputevents.push_back(createEvent(Kolab::cDateTime("Europe/Zurich",2012,5,5,1,4,4), Kolab::cDateTime("Europe/Zurich",2012,5,5,1+1,4,4))); inputevents.push_back(createEvent(Kolab::cDateTime("Europe/Zurich",2012,5,5,3,4,4), Kolab::cDateTime("Europe/Zurich",2012,5,5,3+1,4,4))); inputevents.push_back(createEvent(Kolab::cDateTime("Europe/Zurich",2012,5,5,5,4,4), Kolab::cDateTime("Europe/Zurich",2012,5,5,5+1,4,4))); inputevents.push_back(createEvent(Kolab::cDateTime("Europe/Zurich",2012,5,5,7,4,4), Kolab::cDateTime("Europe/Zurich",2012,5,5,7+1,4,4))); inputevents.push_back(createEvent(Kolab::cDateTime("Europe/Zurich",2012,5,5,9,4,4), Kolab::cDateTime("Europe/Zurich",2012,5,5,9+1,4,4))); std::vector expectedResult; expectedResult.push_back(createEvent(Kolab::cDateTime("Europe/Zurich",2012,5,5,3,4,4), Kolab::cDateTime("Europe/Zurich",2012,5,5,3+1,4,4))); expectedResult.push_back(createEvent(Kolab::cDateTime("Europe/Zurich",2012,5,5,5,4,4), Kolab::cDateTime("Europe/Zurich",2012,5,5,5+1,4,4))); expectedResult.push_back(createEvent(Kolab::cDateTime("Europe/Zurich",2012,5,5,7,4,4), Kolab::cDateTime("Europe/Zurich",2012,5,5,7+1,4,4))); QTest::newRow( "startEndTimeInclusive" ) << inputevents << Kolab::cDateTime("Europe/Zurich",2012,5,5,3,4,4) << Kolab::cDateTime("Europe/Zurich",2012,5,5,7,4,4) << expectedResult; } } void CalendaringTest::testCalendar() { QFETCH(std::vector, inputevents); QFETCH(Kolab::cDateTime, start); QFETCH(Kolab::cDateTime, end); QFETCH(std::vector, expectedResult); Kolab::Calendaring::Calendar cal; foreach (const Kolab::Event &event, inputevents) { cal.addEvent(event); } const std::vector result = cal.getEvents(start, end, true); foreach (const Kolab::Event &event, result) { qDebug() << QTest::toString(event.start()) << QTest::toString(event.end()); } compareEvents(result, expectedResult); } void CalendaringTest::delegationTest() { Kolab::Calendaring::Event event; event.setStart(Kolab::cDateTime("Europe/Zurich",2012,5,5,3,4,4)); Kolab::Attendee att1(Kolab::ContactReference("email1", "name1", "uid1")); att1.setCutype(Kolab::CutypeIndividual); Kolab::Attendee att2(Kolab::ContactReference("email2", "name2", "uid2")); Kolab::Attendee att3(Kolab::ContactReference("email3", "name3", "uid3")); Kolab::Attendee att4(Kolab::ContactReference("email4", "name4", "uid4")); std::vector attendees; attendees.push_back(att1); attendees.push_back(att2); attendees.push_back(att3); event.setAttendees(attendees); std::vector delegators; delegators.push_back(att1); delegators.push_back(att2); std::vector delegatees; delegatees.push_back(att3); delegatees.push_back(att4); event.delegate(delegators, delegatees); std::cout << event.write(); //TODO write an actual test } void CalendaringTest::testICal() { Kolab::Calendaring::Event event; event.setStart(Kolab::cDateTime("Europe/Zurich",2012,5,5,3,4,4)); const std::string &result = event.toICal(); //TODO write an actual test event.setStart(Kolab::cDateTime(1,1,1)); event.fromICal(result); QCOMPARE(event.start(), Kolab::cDateTime("Europe/Zurich",2012,5,5,3,4,4)); } void CalendaringTest::testMime() { Kolab::Calendaring::Event event; event.setStart(Kolab::cDateTime("Europe/Zurich",2012,5,5,3,4,4)); std::cout << event.toMime(); const std::string &result = event.toMime(); event.setStart(Kolab::cDateTime(1,1,1)); event.fromMime(result); QCOMPARE(event.start(), Kolab::cDateTime("Europe/Zurich",2012,5,5,3,4,4)); } void CalendaringTest::testIMip() { Kolab::Calendaring::Event event; Kolab::Attendee att1(Kolab::ContactReference("email1", "name1", "uid1")); std::vector attendees; attendees.push_back(att1); event.setAttendees(attendees); event.setOrganizer(Kolab::ContactReference("organizer@test.org", "organizer", "uid3")); event.setSummary("summary"); event.setStart(Kolab::cDateTime("Europe/Zurich",2012,5,5,3,4,4)); const std::string &result = event.toIMip(Kolab::Calendaring::Event::iTIPRequest); event.setStart(Kolab::cDateTime(1,1,1)); event.fromIMip(result); QEXPECT_FAIL("", "returns UTC instead of local timezone", Continue); QCOMPARE(event.start(), Kolab::cDateTime("Europe/Zurich",2012,5,5,3,4,4)); QCOMPARE(event.getSchedulingMethod(), Kolab::Calendaring::Event::iTIPRequest); } void CalendaringTest::testRecurrence() { Kolab::Calendaring::Event event; event.setStart(Kolab::cDateTime(2011,1,1,1,1,1)); event.setEnd(Kolab::cDateTime(2011,1,1,2,1,1)); Kolab::RecurrenceRule rrule; rrule.setFrequency(Kolab::RecurrenceRule::Daily); rrule.setInterval(1); rrule.setCount(10); event.setRecurrenceRule(rrule); Kolab::cDateTime previousDate = event.start(); for (int i = 0; i < 9; i++) { const Kolab::cDateTime nextDate = event.getNextOccurence(previousDate); // qDebug() << QTest::toString(nextDate); QCOMPARE(nextDate, Kolab::cDateTime(previousDate.year(), previousDate.month(), previousDate.day()+1, previousDate.hour(), previousDate.minute(), previousDate.second())); const Kolab::cDateTime endDate = event.getOccurenceEndDate(nextDate); // qDebug() << QTest::toString(endDate); QCOMPARE(endDate, Kolab::cDateTime(nextDate.year(), nextDate.month(), nextDate.day(), event.end().hour(), event.end().minute(), event.end().second())); previousDate = nextDate; } Kolab::cDateTime outOfScopeDate = event.getNextOccurence(previousDate); QVERIFY(!outOfScopeDate.isValid()); } void CalendaringTest::testDateTimeUtils() { std::cout << Kolab::DateTimeUtils::getLocalTimezone() << std::endl; } QTEST_MAIN( CalendaringTest ) #include "calendaringtest.moc" libkolab-1.0.2/tests/calendaringtest.h000066400000000000000000000025701262531616600177670ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef CALENDARINGTEST_H #define CALENDARINGTEST_H #include class CalendaringTest: public QObject { Q_OBJECT private slots: void initTestCase(); void testCalendaringEvent(); void testEventConflict_data(); void testEventConflict(); void testEventConflictSet(); void testTimesInInterval_data(); void testTimesInInterval(); void testTimesInIntervalBenchmark(); void testCalendar_data(); void testCalendar(); void delegationTest(); void testMime(); void testICal(); void testIMip(); void testRecurrence(); void testDateTimeUtils(); }; #endif // CALENDARINGTEST_H libkolab-1.0.2/tests/debugstreamtest.cpp000066400000000000000000000036411262531616600203550ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include "debugstreamtest.h" #include "kolabformat/errorhandler.h" #include void DebugStreamTest::testDebugstream() { Error() << "test1"; Error() << "test2" << "bla" << 3 << QMap(); QCOMPARE(Kolab::ErrorHandler::instance().getErrors().size(), 2); QVERIFY(Kolab::ErrorHandler::instance().getErrors().first().message.contains("test1")); QCOMPARE(Kolab::ErrorHandler::instance().getErrors().first().severity, Kolab::ErrorHandler::Error); QVERIFY(Kolab::ErrorHandler::instance().getErrors().last().message.contains("bla")); } void DebugStreamTest::testDebugNotLogged() { Kolab::ErrorHandler::instance().clear(); Debug() << "test1"; QCOMPARE(Kolab::ErrorHandler::instance().getErrors().size(), 0); } void DebugStreamTest::testHasError() { Debug() << "test1"; QCOMPARE(Kolab::ErrorHandler::errorOccured(), false); Warning() << "test1"; QCOMPARE(Kolab::ErrorHandler::errorOccured(), false); Error() << "test1"; QCOMPARE(Kolab::ErrorHandler::errorOccured(), true); Kolab::ErrorHandler::clearErrors(); QCOMPARE(Kolab::ErrorHandler::errorOccured(), false); } QTEST_MAIN( DebugStreamTest ) #include "debugstreamtest.moc"libkolab-1.0.2/tests/debugstreamtest.h000066400000000000000000000017531262531616600200240ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef DEBUGSTREAMTEST_H #define DEBUGSTREAMTEST_H #include class DebugStreamTest: public QObject { Q_OBJECT private slots: void testDebugstream(); void testDebugNotLogged(); void testHasError(); }; #endif // DEBUGSTREAMTEST_H libkolab-1.0.2/tests/formattest.cpp000066400000000000000000000555321262531616600173510ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include "formattest.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "testutils.h" #include "kolabformat/kolabobject.h" #include "kolabformat/errorhandler.h" #include "kolabformat/kolabdefinitions.h" static bool compareMimeMessage( const KMime::Message::Ptr &msg, const KMime::Message::Ptr &expectedMsg ) { // headers KCOMPARE( msg->subject()->asUnicodeString(), expectedMsg->subject()->asUnicodeString() ); if ( msg->from()->isEmpty() || expectedMsg->from()->isEmpty() ) { KCOMPARE( msg->from()->asUnicodeString(), expectedMsg->from()->asUnicodeString() ); } else { KCOMPARE( msg->from()->mailboxes().first().address(), expectedMsg->from()->mailboxes().first().address() ); // matching address is enough, we don't need a display name } KCOMPARE( msg->contentType()->mimeType(), expectedMsg->contentType()->mimeType() ); KCOMPARE( msg->headerByType( X_KOLAB_TYPE_HEADER )->as7BitString(), expectedMsg->headerByType( X_KOLAB_TYPE_HEADER )->as7BitString() ); // date contains conversion time... // KCOMPARE( msg->date()->asUnicodeString(), expectedMsg->date()->asUnicodeString() ); // body parts KCOMPARE( msg->contents().size(), expectedMsg->contents().size() ); for ( int i = 0; i < msg->contents().size(); ++i ) { KMime::Content *part = msg->contents().at( i ); KMime::Content *expectedPart = expectedMsg->contents().at( i ); // part headers KCOMPARE( part->contentType()->mimeType(), expectedPart->contentType()->mimeType() ); KCOMPARE( part->contentDisposition()->filename(), expectedPart->contentDisposition()->filename() ); KCOMPARE( part->decodedContent().isEmpty(), false ); QString content(part->decodedContent()); normalizeMimemessage(content); QString expected(expectedPart->decodedContent()); normalizeMimemessage(expected); // showDiff(expected, content); // part content KCOMPARE( content.simplified(), expected.simplified() ); } return true; } void FormatTest::initTestCase() { } void FormatTest::testIncidence_data() { QTest::addColumn( "version" ); QTest::addColumn( "type" ); QTest::addColumn( "icalFileName" ); QTest::addColumn( "mimeFileName" ); QTest::newRow( "v2eventSimple" ) << Kolab::KolabV2 << Kolab::EventObject << getPath("v2/event/simple.ics") << getPath("v2/event/simple.ics.mime"); QTest::newRow( "v2eventComplex" ) << Kolab::KolabV2 << Kolab::EventObject << getPath("v2/event/complex.ics") << getPath("v2/event/complex.ics.mime"); QTest::newRow( "v2eventAttachment" ) << Kolab::KolabV2 << Kolab::EventObject << getPath("v2/event/attachment.ics") << getPath("v2/event/attachment.ics.mime"); QTest::newRow( "v2eventAllday" ) << Kolab::KolabV2 << Kolab::EventObject << getPath("v2/event/allday.ics") << getPath("v2/event/allday.ics.mime"); QTest::newRow( "v2eventUtf8Attachment" ) << Kolab::KolabV2 << Kolab::EventObject << getPath("v2/event/attachmentUtf8.ics") << getPath("v2/event/attachmentUtf8.ics.mime"); //The following test just fails because we have a nicer mime message output than horde // QTest::newRow( "v2eventHorde" ) << Kolab::KolabV2 << Kolab::EventObject << getPath("v2/event/horde.ics") << getPath("v2/event/horde.ics.mime"); QTest::newRow( "v2todoSimple" ) << Kolab::KolabV2 << Kolab::TodoObject << getPath("v2/task/simple.ics") << getPath("v2/task/simple.ics.mime"); QTest::newRow( "v2todoComplex" ) << Kolab::KolabV2 << Kolab::TodoObject << getPath("v2/task/complex.ics") << getPath("v2/task/complex.ics.mime"); QTest::newRow( "v2todoPrio1" ) << Kolab::KolabV2 << Kolab::TodoObject << getPath("v2/task/prioritytest1.ics") << getPath("v2/task/prioritytest1.ics.mime"); QTest::newRow( "v2todoPrio2" ) << Kolab::KolabV2 << Kolab::TodoObject << getPath("v2/task/prioritytest2.ics") << getPath("v2/task/prioritytest2.ics.mime"); QTest::newRow( "v2journalSimple" ) << Kolab::KolabV2 << Kolab::JournalObject << getPath("v2/journal/simple.ics") << getPath("v2/journal/simple.ics.mime"); QTest::newRow( "v2journalComplex" ) << Kolab::KolabV2 << Kolab::JournalObject << getPath("v2/journal/complex.ics") << getPath("v2/journal/complex.ics.mime"); QTest::newRow( "v3eventSimple" ) << Kolab::KolabV3 << Kolab::EventObject << getPath("v3/event/simple.ics") << getPath("v3/event/simple.ics.mime"); QTest::newRow( "v3eventComplex" ) << Kolab::KolabV3 << Kolab::EventObject << getPath("v3/event/complex.ics") << getPath("v3/event/complex.ics.mime"); QTest::newRow( "v3todoSimple" ) << Kolab::KolabV3 << Kolab::TodoObject << getPath("v3/task/simple.ics") << getPath("v3/task/simple.ics.mime"); QTest::newRow( "v3todoComplex" ) << Kolab::KolabV3 << Kolab::TodoObject << getPath("v3/task/complex.ics") << getPath("v3/task/complex.ics.mime"); QTest::newRow( "v3journalSimple" ) << Kolab::KolabV3 << Kolab::JournalObject << getPath("v3/journal/simple.ics") << getPath("v3/journal/simple.ics.mime"); QTest::newRow( "v3journalComplex" ) << Kolab::KolabV3 << Kolab::JournalObject << getPath("v3/journal/complex.ics") << getPath("v3/journal/complex.ics.mime"); QTest::newRow( "v3utf8quotedPrintable" ) << Kolab::KolabV3 << Kolab::EventObject << getPath("v3/event/utf8.ics") << getPath("v3/event/utf8quotedPrintable.ics.mime"); QTest::newRow( "v3utf8base64" ) << Kolab::KolabV3 << Kolab::EventObject << getPath("v3/event/utf8.ics") << getPath("v3/event/utf8base64.ics.mime"); QTest::newRow( "v3utf88bit" ) << Kolab::KolabV3 << Kolab::EventObject << getPath("v3/event/utf8.ics") << getPath("v3/event/utf88bit.ics.mime"); } void FormatTest::testIncidence() { QFETCH( Kolab::Version, version ); QFETCH( Kolab::ObjectType, type ); QFETCH( QString, icalFileName ); //To compare QFETCH( QString, mimeFileName ); //For parsing //Parse mime message bool ok = false; const KMime::Message::Ptr &msg = readMimeFile( mimeFileName, ok ); QVERIFY(ok); Kolab::KolabObjectReader reader; Kolab::ObjectType t = reader.parseMimeMessage(msg); QCOMPARE(t, type); QCOMPARE(reader.getVersion(), version); QCOMPARE(Kolab::ErrorHandler::instance().error(), Kolab::ErrorHandler::Debug); KCalCore::Incidence::Ptr convertedIncidence = reader.getIncidence(); //Parse ICalFile for comparison QFile icalFile( icalFileName ); QVERIFY( icalFile.open( QFile::ReadOnly ) ); KCalCore::ICalFormat format; KCalCore::Incidence::Ptr realIncidence( format.fromString( QString::fromUtf8( icalFile.readAll() ) ) ); // fix up the converted incidence for comparisson normalizeIncidence(convertedIncidence); normalizeIncidence(realIncidence); // recurrence objects are created on demand, but KCalCore::Incidence::operator==() doesn't take that into account // so make sure both incidences have one realIncidence->recurrence(); convertedIncidence->recurrence(); realIncidence->setLastModified(convertedIncidence->lastModified()); //The following test is just for debugging and not really relevant if ( *(realIncidence.data()) != *(convertedIncidence.data()) ) { showDiff(format.toString( realIncidence ), format.toString( convertedIncidence )); } QVERIFY( *(realIncidence.data()) == *(convertedIncidence.data()) ); //Write Kolab::overrideTimestamp(Kolab::cDateTime(2012, 5, 5, 5,5,5, true)); KMime::Message::Ptr convertedMime = Kolab::KolabObjectWriter::writeIncidence(realIncidence, version); if ( !compareMimeMessage( convertedMime, msg )) { showDiff(msg->encodedContent(), convertedMime->encodedContent()); QVERIFY( false ); } QCOMPARE(Kolab::ErrorHandler::instance().error(), Kolab::ErrorHandler::Debug); } enum TestMode { ReadOnly, ReadWrite }; Q_DECLARE_METATYPE(TestMode); void FormatTest::testContact_data() { QTest::addColumn( "version" ); QTest::addColumn( "type" ); QTest::addColumn( "vcardFileName" ); QTest::addColumn( "mimeFileName" ); QTest::addColumn( "mode" ); QTest::newRow( "v2contactSimple" ) << Kolab::KolabV2 << Kolab::ContactObject << getPath("v2/contacts/simple.vcf") << getPath("v2/contacts/simple.vcf.mime") << ReadWrite; //FIXME Reference files needs to be adjusted due to fix in how pictures are stored // QTest::newRow( "v2contactComplex" ) << Kolab::KolabV2 << Kolab::ContactObject << getPath("v2/contacts/complex.vcf") << getPath("v2/contacts/complex.vcf.mime") << ReadWrite; QTest::newRow( "v2contactAddress" ) << Kolab::KolabV2 << Kolab::ContactObject << getPath("v2/contacts/address.vcf") << getPath("v2/contacts/address.vcf.mime") << ReadWrite; QTest::newRow( "v2contactBug238996" ) << Kolab::KolabV2 << Kolab::ContactObject << getPath("v2/contacts/bug238996.vcf") << getPath("v2/contacts/bug238996.vcf.mime") << ReadWrite; QTest::newRow( "v2contactDisplayname" ) << Kolab::KolabV2 << Kolab::ContactObject << getPath("v2/contacts/displayname.vcf") << getPath("v2/contacts/displayname.vcf.mime") << ReadWrite; QTest::newRow( "v2contactEmails" ) << Kolab::KolabV2 << Kolab::ContactObject << getPath("v2/contacts/emails.vcf") << getPath("v2/contacts/emails.vcf.mime") << ReadWrite; QTest::newRow( "v2contactPhonenumbers" ) << Kolab::KolabV2 << Kolab::ContactObject << getPath("v2/contacts/phonenumbers.vcf") << getPath("v2/contacts/phonenumbers.vcf.mime") << ReadWrite; // FIXME Reference files needs to be adjusted due to fix in how pictures are stored // QTest::newRow( "v2contactPicture" ) << Kolab::KolabV2 << Kolab::ContactObject << getPath("v2/contacts/picture.vcf") << getPath("v2/contacts/picture.vcf.mime") << ReadWrite; //FIXME the following test fails because the vcard implementation always writes jpeg (which is lossy). The reference vcf file is therefore probably also not really useful // QTest::newRow( "v2pictureJPGHorde" ) << Kolab::KolabV2 << Kolab::ContactObject << getPath("v2/contacts/pictureJPGHorde.vcf") << getPath("v2/contacts/pictureJPGHorde.vcf.mime"); QTest::newRow( "v3contactSimple" ) << Kolab::KolabV3 << Kolab::ContactObject << getPath("v3/contacts/simple.vcf") << getPath("v3/contacts/simple.vcf.mime") << ReadWrite; QTest::newRow( "v3contactComplex" ) << Kolab::KolabV3 << Kolab::ContactObject << getPath("v3/contacts/complex.vcf") << getPath("v3/contacts/complex.vcf.mime") << ReadWrite; QTest::newRow( "v3contactPng" ) << Kolab::KolabV3 << Kolab::ContactObject << getPath("v3/readonly/png.vcf") << getPath("v3/readonly/png.vcf.mime") << ReadOnly; } bool comparePictureToReference(const QImage &picture) { QImage img(getPath("picture.jpg")); QByteArray pic; QBuffer buffer(&pic); buffer.open(QIODevice::WriteOnly); img.save(&buffer, "JPEG"); buffer.close(); QByteArray pic2; QBuffer buffer2(&pic2); buffer2.open(QIODevice::WriteOnly); picture.save(&buffer2, "JPEG"); buffer2.close(); if(pic.toBase64() != pic2.toBase64()) { qDebug() << pic.toBase64(); qDebug() << pic2.toBase64(); return false; } return true; } void FormatTest::testContact() { QFETCH( Kolab::Version, version ); QFETCH( Kolab::ObjectType, type ); QFETCH( QString, vcardFileName ); //To compare QFETCH( QString, mimeFileName ); //For parsing QFETCH( TestMode, mode ); //For parsing //Parse mime message bool ok = false; const KMime::Message::Ptr &msg = readMimeFile( mimeFileName, ok ); QVERIFY(ok); Kolab::KolabObjectReader reader; Kolab::ObjectType t = reader.parseMimeMessage(msg); QCOMPARE(t, type); QCOMPARE(reader.getVersion(), version); QCOMPARE(Kolab::ErrorHandler::instance().error(), Kolab::ErrorHandler::Debug); KContacts::Addressee convertedAddressee = reader.getContact(); QVERIFY(!convertedAddressee.isEmpty()); //Parse vcard QFile vcardFile( vcardFileName ); QVERIFY( vcardFile.open( QFile::ReadOnly ) ); KContacts::VCardConverter converter; const QByteArray &c = vcardFile.readAll(); KContacts::Addressee realAddressee = converter.parseVCard( c ); // fix up the converted addressee for comparisson convertedAddressee.setName( realAddressee.name() ); // name() apparently is something strange if (version == Kolab::KolabV2) { //No creation date in xcal QVERIFY( !convertedAddressee.custom( "KOLAB", "CreationDate" ).isEmpty() ); convertedAddressee.removeCustom( "KOLAB", "CreationDate" ); // that's conversion time !? } else { normalizeContact(convertedAddressee); normalizeContact(realAddressee); } QVERIFY( normalizePhoneNumbers( convertedAddressee, realAddressee ) ); // phone number ids are random QVERIFY( normalizeAddresses( convertedAddressee, realAddressee ) ); // same here QCOMPARE(realAddressee.photo().type(), convertedAddressee.photo().type()); if (realAddressee != convertedAddressee) { showDiff(normalizeVCardMessage(converter.createVCard(realAddressee)), normalizeVCardMessage(converter.createVCard(convertedAddressee))); } QEXPECT_FAIL("v2contactBug238996", "Currently fails due to missing type=pref attribute of preffered email address. Requires fix in KContacts.", Continue); QEXPECT_FAIL("v2contactEmails", "Currently fails due to missing type=pref attribute of preffered email address. Requires fix in KContacts.", Continue); QEXPECT_FAIL("v3contactComplex", "Currently fails due to missing type=pref attribute of preffered email address. Requires fix in KContacts.", Continue); QCOMPARE( realAddressee, convertedAddressee ); //Write if (mode == ReadWrite) { Kolab::overrideTimestamp(Kolab::cDateTime(2012, 5, 5, 5,5,5, true)); const KMime::Message::Ptr &convertedMime = Kolab::KolabObjectWriter::writeContact(realAddressee, version); if ( !compareMimeMessage( convertedMime, msg )) { QString expected = msg->encodedContent(); normalizeMimemessage(expected); QString converted = convertedMime->encodedContent(); normalizeMimemessage(converted); showDiff(expected, converted); QEXPECT_FAIL("v2contactSimple", "The kolab v3 containers don't support postbox, and we therefore loose it in the transformations.", Continue); QEXPECT_FAIL("v2contactAddress", "The kolab v3 containers don't support postbox, and we therefore loose it in the transformations.", Continue); QEXPECT_FAIL("v2contactBug238996", "The kolab v3 containers don't support postbox, and we therefore loose it in the transformations.", Continue); QVERIFY( false ); } } QCOMPARE(Kolab::ErrorHandler::instance().error(), Kolab::ErrorHandler::Debug); } void FormatTest::testDistlist_data() { QTest::addColumn( "version" ); QTest::addColumn( "type" ); QTest::addColumn( "vcardFileName" ); QTest::addColumn( "mimeFileName" ); QTest::newRow( "v3distlistSimple" ) << Kolab::KolabV3 << Kolab::DistlistObject << getPath("v3/contacts/distlist.vcf") << getPath("v3/contacts/distlist.vcf.mime"); } void FormatTest::testDistlist() { QFETCH( Kolab::Version, version ); QFETCH( Kolab::ObjectType, type ); QFETCH( QString, vcardFileName ); //To compare QFETCH( QString, mimeFileName ); //For parsing //Parse mime message bool ok = false; const KMime::Message::Ptr &msg = readMimeFile( mimeFileName, ok ); QVERIFY(ok); Kolab::KolabObjectReader reader; Kolab::ObjectType t = reader.parseMimeMessage(msg); QCOMPARE(t, type); QCOMPARE(reader.getVersion(), version); QCOMPARE(Kolab::ErrorHandler::instance().error(), Kolab::ErrorHandler::Debug); KContacts::ContactGroup convertedAddressee = reader.getDistlist(); //Parse vcard QFile vcardFile( vcardFileName ); QVERIFY( vcardFile.open( QFile::ReadOnly ) ); KContacts::VCardConverter converter; QByteArray c = vcardFile.readAll(); QBuffer data(&c); data.open(QIODevice::ReadOnly); KContacts::ContactGroup realAddressee; KContacts::ContactGroupTool::convertFromXml( &data, realAddressee ); { QBuffer expected; expected.open(QIODevice::WriteOnly); KContacts::ContactGroupTool::convertToXml(realAddressee, &expected); QBuffer converted; converted.open(QIODevice::WriteOnly); KContacts::ContactGroupTool::convertToXml(convertedAddressee, &converted); showDiff(expected.buffer(), converted.buffer()); } QCOMPARE( realAddressee, convertedAddressee ); //Write const KMime::Message::Ptr &convertedMime = Kolab::KolabObjectWriter::writeDistlist(realAddressee, version); if ( !compareMimeMessage( convertedMime, msg )) { QString expected = msg->encodedContent(); normalizeMimemessage(expected); QString converted = convertedMime->encodedContent(); normalizeMimemessage(converted); showDiff(expected, converted); QVERIFY( false ); } QCOMPARE(Kolab::ErrorHandler::instance().error(), Kolab::ErrorHandler::Debug); } void FormatTest::testNote_data() { QTest::addColumn( "version" ); QTest::addColumn( "type" ); QTest::addColumn( "noteFileName" ); QTest::addColumn( "mimeFileName" ); QTest::newRow( "v3noteSimple" ) << Kolab::KolabV3 << Kolab::NoteObject << getPath("v3/note/note.mime") << getPath("v3/note/note.mime.mime"); } void FormatTest::testNote() { QFETCH( Kolab::Version, version ); QFETCH( Kolab::ObjectType, type ); QFETCH( QString, noteFileName ); //To compare QFETCH( QString, mimeFileName ); //For parsing //Parse mime message bool ok = false; const KMime::Message::Ptr &msg = readMimeFile( mimeFileName, ok ); QVERIFY(ok); Kolab::KolabObjectReader reader; Kolab::ObjectType t = reader.parseMimeMessage(msg); QCOMPARE(t, type); QCOMPARE(reader.getVersion(), version); QCOMPARE(Kolab::ErrorHandler::instance().error(), Kolab::ErrorHandler::Debug); KMime::Message::Ptr convertedNote = reader.getNote(); QVERIFY(convertedNote.data()); //Parse note const KMime::Message::Ptr &realNote = readMimeFile( noteFileName, ok ); QVERIFY(ok); QVERIFY(realNote.data()); QString expected = realNote->encodedContent(); normalizeMimemessage(expected); QString converted = convertedNote->encodedContent(); normalizeMimemessage(converted); QEXPECT_FAIL("", "Header sorting is off", Continue); QCOMPARE(expected, converted); // showDiff(expected, converted); //Write const KMime::Message::Ptr &convertedMime = Kolab::KolabObjectWriter::writeNote(realNote, version); QVERIFY(convertedMime.data()); QVERIFY(msg.data()); QString expected2 = msg->encodedContent(); normalizeMimemessage(expected2); QString converted2 = convertedMime->encodedContent(); normalizeMimemessage(converted2); QEXPECT_FAIL("", "Header sorting is off", Continue); QCOMPARE(expected2, converted2); // showDiff(expected2, converted2); QCOMPARE(Kolab::ErrorHandler::instance().error(), Kolab::ErrorHandler::Debug); } //This function exists only to generate the reference files, it's not a real test. void FormatTest::generateMimefile() { // QFile icalFile( getPath("v3/journal/complex.ics") ); // QVERIFY( icalFile.open( QFile::ReadOnly ) ); // KCalCore::ICalFormat format; // const KCalCore::Incidence::Ptr realIncidence( format.fromString( QString::fromUtf8( icalFile.readAll() ) ) ); // // QString result; // QTextStream s(&result); // Kolab::overrideTimestamp(Kolab::cDateTime(2012, 5, 5, 5,5,5, true)); // Kolab::KolabObjectWriter::writeIncidence(realIncidence, Kolab::KolabV3)->toStream(s); // QFile vcardFile( getPath("v3/contacts/complex.vcf") ); // QVERIFY( vcardFile.open( QFile::ReadOnly ) ); // KContacts::VCardConverter converter; // const KContacts::Addressee realAddressee = converter.parseVCard( vcardFile.readAll() ); // // qDebug() << realAddressee.photo().data(); // // QString result; // QTextStream s(&result); // Kolab::overrideTimestamp(Kolab::cDateTime(2012, 5, 5, 5,5,5, true)); // Kolab::KolabObjectWriter::writeContact(realAddressee, Kolab::KolabV3)->toStream(s); // qDebug() << result; } void FormatTest::generateVCard() { // bool ok = false; // const KMime::Message::Ptr &msg = readMimeFile( QString::fromLatin1("../")+getPath("v2/contacts/pictureJPGHorde.vcf.mime"), ok ); // qDebug() << msg->encodedContent(); // Kolab::KolabObjectReader reader; // Kolab::ObjectType t = reader.parseMimeMessage(msg); // // KContacts::Addressee convertedAddressee = reader.getContact(); // KContacts::VCardConverter converter; // qDebug() << converter.createVCard(convertedAddressee); // bool ok = false; // const KMime::Message::Ptr &msg = readMimeFile( getPath("v3/contacts/distlist.vcf.mime"), ok ); // qDebug() << msg->encodedContent(); // Kolab::KolabObjectReader reader; // Kolab::ObjectType t = reader.parseMimeMessage(msg); // // KContacts::ContactGroup convertedAddressee = reader.getDistlist(); // QBuffer buf; // buf.open(QIODevice::WriteOnly); // KContacts::ContactGroupTool::convertToXml(convertedAddressee, &buf); // qDebug() << buf.buffer(); } //Pseudo test to show that JPG is always lossy, even with quality set to 100 void FormatTest::proveJPGisLossy() { // QImage img(getPath("picture.jpg")); // QByteArray pic; // QBuffer buffer(&pic); // buffer.open(QIODevice::WriteOnly); // img.save(&buffer, "JPEG"); // buffer.close(); // qDebug() << pic.toBase64(); // // QImage img2; // QByteArray pic2; // QBuffer buffer2(&pic2); // img2.loadFromData(pic); // img2.save(&buffer2, "JPEG"); // buffer2.close(); // qDebug() << pic2.toBase64(); } QTEST_MAIN( FormatTest ) #include "formattest.moc" libkolab-1.0.2/tests/formattest.h000066400000000000000000000050551262531616600170110ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef FORMATTEST_H #define FORMATTEST_H #include /** * Test complete serialization from mime message to KCalCore/KContacts containers. * * The .ics .vcf files serve as reference, under the assumption that the iCal/vCard implementations don't have bugs. * * The .ics.mime/.vcf.mime messages are first used to test parsing, and then to compare the result after serialization. * The mime files are of course just a snapshot of how it is thought that the result should be. * The files may have bugs themselves and will need to be updated to reflect future changes. * * kompare (the kde diff tool) is launched if a test fails to show you the difference between expected and actual conversion. * Comment the code if you don't want it. * * Note that some parts of the mime message are not compared, but show up in kompare as difference: * * Date-Header * * Content-Type-Header * * next-part markers * * Content-ID Header * * These are safe to be ignored as they are randomly generated. * * To generate the reference files, you can write the vcf/ics by hand and generate the mime message from that one (using the generateMimefile() function). * You may need to sort some things manually (addresses/phonenumbers), and generally check manually if everything is as it should be. * The test will then remain to ensure the same for future versions. * */ class FormatTest: public QObject { Q_OBJECT private slots: void initTestCase(); void testIncidence_data(); void testIncidence(); void testContact_data(); void testContact(); void testDistlist_data(); void testDistlist(); void testNote_data(); void testNote(); //Some pseudo tests and helper functions void generateMimefile(); void generateVCard(); void proveJPGisLossy(); }; #endif // FORMATTEST_H libkolab-1.0.2/tests/freebusytest.cpp000066400000000000000000000151161262531616600176770ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include "freebusytest.h" #include "testutils.h" #include "testhelpers.h" #include #include "freebusy/freebusy.h" #include #include void FreebusyTest::testFB_data() { QTest::addColumn( "start" ); QTest::addColumn( "end" ); QTest::addColumn< std::vector >( "events" ); QTest::addColumn< std::vector >( "output" ); //UTC check { Kolab::Period p1(Kolab::cDateTime(2011,10,6,12,1,1,true), Kolab::cDateTime(2011,10,7,12,1,1,true)); Kolab::Period p2(Kolab::cDateTime(2011,10,8,12,1,1,true), Kolab::cDateTime(2011,10,9,12,1,1,true)); Kolab::Period p3(Kolab::cDateTime(2011,10,10,12,1,1,true), Kolab::cDateTime(2011,10,11,12,1,1,true)); std::vector events; events.push_back(createEvent(p1.start, p1.end)); events.push_back(createEvent(p2.start, p2.end)); events.push_back(createEvent(p3.start, p3.end)); Kolab::FreebusyPeriod period1; period1.setType(Kolab::FreebusyPeriod::Busy); period1.setEvent(events.at(0).uid(), events.at(0).summary(), events.at(0).location()); period1.setPeriods(std::vector() << p1); Kolab::FreebusyPeriod period2; period2.setType(Kolab::FreebusyPeriod::Busy); period2.setEvent(events.at(1).uid(), events.at(1).summary(), events.at(1).location()); period2.setPeriods(std::vector() << p2); Kolab::FreebusyPeriod period3; period3.setType(Kolab::FreebusyPeriod::Busy); period3.setEvent(events.at(2).uid(), events.at(2).summary(), events.at(2).location()); period3.setPeriods(std::vector() << p3); { std::vector output; output.push_back(period1); output.push_back(period2); output.push_back(period3); QTest::newRow( "simple utc" ) << Kolab::cDateTime(2010, 1, 1,1,1,1,true) << Kolab::cDateTime(2012, 1, 1,1,1,1,true) << events << output; } { std::vector output; output.push_back(period2); output.push_back(period3); QTest::newRow( "limit utc below" ) << Kolab::cDateTime(2011,10,8,12,1,1,true) << Kolab::cDateTime(2012, 1, 1,1,1,1,true) << events << output; } { std::vector output; output.push_back(period1); output.push_back(period2); QTest::newRow( "limit utc above" ) << Kolab::cDateTime(2010, 1, 1,1,1,1,true) << Kolab::cDateTime(2011,10,9,12,1,1,true) << events << output; } } { Kolab::Event event; event.setUid(QUuid::createUuid().toString().toStdString()); event.setStart(Kolab::cDateTime(2011,1,1,0,0,0,true)); event.setEnd(Kolab::cDateTime(2011,1,1,1,0,0,true)); Kolab::RecurrenceRule rrule; rrule.setFrequency(Kolab::RecurrenceRule::Daily); rrule.setInterval(1); rrule.setCount(2); event.setRecurrenceRule(rrule); std::vector events; events.push_back(event); std::vector output; Kolab::FreebusyPeriod period1; period1.setType(Kolab::FreebusyPeriod::Busy); period1.setEvent(event.uid(), event.summary(), event.location()); period1.setPeriods(std::vector() << Kolab::Period(Kolab::cDateTime(2011,1,1,0,0,0,true), Kolab::cDateTime(2011,1,1,1,0,0,true)) << Kolab::Period(Kolab::cDateTime(2011,1,2,0,0,0,true), Kolab::cDateTime(2011,1,2,1,0,0,true)) ); output.push_back(period1); QTest::newRow( "fullday recurrence" ) << Kolab::cDateTime(2010, 1, 1,1,1,1,true) << Kolab::cDateTime(2012,10,9,12,1,1,true) << events << output; } } void FreebusyTest::testFB() { QFETCH(Kolab::cDateTime, start); QFETCH(Kolab::cDateTime, end); QFETCH(std::vector, events); QFETCH(std::vector, output); Kolab::Freebusy fb = Kolab::FreebusyUtils::generateFreeBusy(events, start, end); QCOMPARE((int)fb.periods().size(), (int)output.size()); for (std::size_t i = 0; i events; // events.push_back(createEvent(p1.start, p1.end)); // events.push_back(createEvent(p2.start, p2.end)); // events.push_back(createEvent(p3.start, p3.end)); // // Kolab::FreebusyPeriod period1; // period1.setType(Kolab::FreebusyPeriod::Busy); // period1.setPeriods(std::vector() << p1); // // Kolab::FreebusyPeriod period2; // period2.setType(Kolab::FreebusyPeriod::Busy); // period2.setPeriods(std::vector() << p2); // // Kolab::FreebusyPeriod period3; // period3.setType(Kolab::FreebusyPeriod::Busy); // period3.setPeriods(std::vector() << p3); // // // Kolab::Freebusy fb = Kolab::FreebusyUtils::generateFreeBusy(events, Kolab::cDateTime(2010, 1, 1,1,1,1,true), Kolab::cDateTime(2012, 1, 1,1,1,1,true)); // QCOMPARE((int)fb.periods().size(), 3); // QCOMPARE(fb.periods().at(0), period1); // QCOMPARE(fb.periods().at(1), period2); // QCOMPARE(fb.periods().at(2), period3); // } QTEST_MAIN( FreebusyTest ) #include "freebusytest.moc"libkolab-1.0.2/tests/freebusytest.h000066400000000000000000000016671262531616600173520ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef FREEBUSYTEST_H #define FREEBUSYTEST_H #include class FreebusyTest: public QObject { Q_OBJECT private slots: void testFB_data(); void testFB(); }; #endif // FREEBUSYTEST_H libkolab-1.0.2/tests/icalendartest.cpp000066400000000000000000000070431262531616600177750ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include "icalendartest.h" #include #include #include "icalendar/icalendar.h" #include "testhelpers.h" void ICalendarTest::testFromICalEvent() { std::vector events; Kolab::Event ev1; ev1.setStart(Kolab::cDateTime(2011,10,10,12,1,1,true)); ev1.setEnd(Kolab::cDateTime(2011,10,11,12,1,1,true)); events.push_back(ev1); events.push_back(ev1); const std::vector &result = Kolab::fromICalEvents(Kolab::toICal(events)); qDebug() << QString::fromStdString(Kolab::toICal(result)); } void ICalendarTest::testToICal() { std::vector events; Kolab::Event ev1; ev1.setStart(Kolab::cDateTime(2011,10,10,12,1,1,true)); ev1.setEnd(Kolab::cDateTime(2011,10,11,12,1,1,true)); events.push_back(ev1); events.push_back(ev1); qDebug() << QString::fromStdString(Kolab::toICal(events)); } void ICalendarTest::testToITip() { Kolab::ITipHandler handler; Kolab::Event ev1; ev1.setStart(Kolab::cDateTime(2011,10,10,12,1,1,true)); ev1.setEnd(Kolab::cDateTime(2011,10,11,12,1,1,true)); ev1.setLastModified(Kolab::cDateTime(2011,10,11,12,1,2,true)); ev1.setCreated(Kolab::cDateTime(2011,10,11,12,1,3,true)); qDebug() << QString::fromStdString(handler.toITip(ev1, Kolab::ITipHandler::iTIPRequest)); } void ICalendarTest::testToIMip() { Kolab::ITipHandler handler; Kolab::Event ev1; ev1.setStart(Kolab::cDateTime("Europe/Zurich",2011,10,10,12,1,1)); ev1.setEnd(Kolab::cDateTime("Europe/Zurich",2012,5,5,3,4,4)); ev1.setLastModified(Kolab::cDateTime(2011,10,11,12,1,2,true)); ev1.setCreated(Kolab::cDateTime(2011,10,11,12,1,3,true)); std::vector attendees; attendees.push_back(Kolab::Attendee(Kolab::ContactReference("email1@test.org", "name1", "uid1"))); attendees.push_back(Kolab::Attendee (Kolab::ContactReference("email2@test.org", "name2", "uid2"))); ev1.setAttendees(attendees); ev1.setOrganizer(Kolab::ContactReference("organizer@test.org", "organizer", "uid3")); ev1.setSummary("summary"); const std::string mimeResult = handler.toIMip(ev1, Kolab::ITipHandler::iTIPRequest, "test@test.com"); qDebug() << QString::fromStdString(mimeResult); qDebug() << QString::fromStdString(handler.toIMip(ev1, Kolab::ITipHandler::iTIPReply, "test@test.com")); const std::vector &eventResult = handler.fromIMip(mimeResult); // qDebug() << QString::fromStdString(Kolab::toICal(eventResult)); QCOMPARE((int)eventResult.size(), 1); QEXPECT_FAIL("", "to imip converts dates to utc", Continue); QCOMPARE(eventResult.front().start(), ev1.start()); QEXPECT_FAIL("", "to imip converts dates to utc", Continue); QCOMPARE(eventResult.front().end(), ev1.end()); } QTEST_MAIN( ICalendarTest ) #include "icalendartest.moc" libkolab-1.0.2/tests/icalendartest.h000066400000000000000000000020311262531616600174320ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef ICALENDARTEST_H #define ICALENDARTEST_H #include class ICalendarTest: public QObject { Q_OBJECT private slots: // void testEventConflict_data(); void testToICal(); void testFromICalEvent(); void testToITip(); void testToIMip(); }; #endif // ICALENDARTEST_H libkolab-1.0.2/tests/kcalconversiontest.cpp000066400000000000000000000545021262531616600210750ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include "kcalconversiontest.h" #include #include #include #include #include #include #include #include #include "conversion/kcalconversion.h" #include "conversion/kcalconversion.cpp" #include "conversion/kabcconversion.h" #include "testhelpers.h" using namespace Kolab::Conversion; template void comparePointerVectors(const QVector &list, const QVector &other) { QCOMPARE(list.size(), other.size()); for (int i = 0 ; i < list.size(); i++) { QCOMPARE(*list.at(i), *other.at(i)); } } void compareAttendeesVectors(const KCalCore::Attendee::List &list, const KCalCore::Attendee::List &other) { QCOMPARE(list.size(), other.size()); for (int i = 0 ; i < list.size(); i++) { KCalCore::Attendee::Ptr at1 = list.at(i).constCast(); at1->setUid(QString()); KCalCore::Attendee::Ptr at2 = other.at(i).constCast(); at2->setUid(QString()); QCOMPARE(*at1, *at2); } } void KCalConversionTest::initTestCase() { } void KCalConversionTest::testDate_data() { QTest::addColumn( "input" ); QTest::addColumn( "result" ); QTest::newRow( "datetime with tz" ) << Kolab::cDateTime("Europe/Zurich",2006,1,8,12,0,0) << KDateTime(QDate(2006, 1, 8), QTime(12, 0, 0), KSystemTimeZones::zone("Europe/Zurich")); QTest::newRow( "floating datetime" ) << Kolab::cDateTime(2006,1,8,12,0,0, false) << KDateTime(QDate(2006, 1, 8), QTime(12, 0, 0), KDateTime::Spec(KDateTime::ClockTime)); QTest::newRow( "utc datetime" ) << Kolab::cDateTime(2006,1,8,12,0,0, true) << KDateTime(KDateTime(QDate(2006, 1, 8), QTime(12, 0, 0), KDateTime::UTC)); QTest::newRow( "date only" ) << Kolab::cDateTime(2006,1,8) << KDateTime(QDate(2006, 1, 8)); } void KCalConversionTest::testDate() { QFETCH(Kolab::cDateTime, input); QFETCH(KDateTime, result); const KDateTime &r = Kolab::Conversion::toDate(input); QCOMPARE(r, result); const Kolab::cDateTime &r2 = Kolab::Conversion::fromDate(result); QCOMPARE(r2, input); } void KCalConversionTest::testDuration_data() { QTest::addColumn( "input" ); QTest::addColumn( "result" ); QTest::addColumn( "fromResult" ); QTest::newRow( "seconds" ) << Kolab::Duration(0,0,0,30,false) << KCalCore::Duration(30, KCalCore::Duration::Seconds) << Kolab::Duration(0,0,0,30,false); QTest::newRow( "minutes" ) << Kolab::Duration(0,0,1,30,false) << KCalCore::Duration(90, KCalCore::Duration::Seconds) << Kolab::Duration(0,0,0,90,false); QTest::newRow( "hours" ) << Kolab::Duration(0,1,1,30,false) << KCalCore::Duration(60*60+90, KCalCore::Duration::Seconds) << Kolab::Duration(0,0,0,60*60+90,false); QTest::newRow( "days" ) << Kolab::Duration(1,1,1,30,false) << KCalCore::Duration(24*60*60+60*60+90, KCalCore::Duration::Seconds) << Kolab::Duration(0,0,0,24*60*60+60*60+90,false); QTest::newRow( "daysonly" ) << Kolab::Duration(30,0,0,0, false) << KCalCore::Duration(30, KCalCore::Duration::Days) << Kolab::Duration(30,0,0,0,false); QTest::newRow( "weeks" ) << Kolab::Duration(30,false) << KCalCore::Duration(30*7, KCalCore::Duration::Days) << Kolab::Duration(30*7,0,0,0,false); } void KCalConversionTest::testDuration() { QFETCH(Kolab::Duration, input); QFETCH(KCalCore::Duration, result); QFETCH(Kolab::Duration, fromResult); const KCalCore::Duration &r = Kolab::Conversion::toDuration(input); QCOMPARE(r, result); const Kolab::Duration &r2 = Kolab::Conversion::fromDuration(result); QCOMPARE(r2, fromResult); } void KCalConversionTest::testDateTZ_data() { QTest::addColumn( "input" ); QTest::addColumn( "result" ); QTest::newRow( "berlin" ) << Kolab::cDateTime("Europe/Berlin",2006,1,8,12,0,0) << KDateTime(QDate(2006, 1, 8), QTime(12, 0, 0), KSystemTimeZones::zone("Europe/Berlin")); } void KCalConversionTest::testDateTZ() { QFETCH(Kolab::cDateTime, input); QFETCH(KDateTime, result); const KDateTime &r = Kolab::Conversion::toDate(input); QCOMPARE(result.timeZone().name(), QString::fromStdString(input.timezone())); QCOMPARE(r.timeZone().currentOffset(), result.timeZone().currentOffset()); const Kolab::cDateTime &r2 = Kolab::Conversion::fromDate(result); QCOMPARE(QString::fromStdString(r2.timezone()), result.timeZone().name()); } void KCalConversionTest::testConversion_data() { QTest::addColumn( "kcal" ); QTest::addColumn( "kolab" ); Kolab::cDateTime date(2011,2,2,12,11,10,true); Kolab::cDateTime date2(2011,2,2,12,12,10,true); Kolab::cDateTime date3(2012,2,2,12,12,10,true); std::vector intVector; intVector.push_back(1); intVector.push_back(-3); intVector.push_back(2); std::vector stringVector; stringVector.push_back("cat1"); stringVector.push_back("cat2"); stringVector.push_back("parent/child"); { KCalCore::Event kcal; kcal.setUid("uid"); kcal.setCreated(toDate(date)); kcal.setLastModified(toDate(date)); kcal.setRevision(3); kcal.setSecrecy(KCalCore::Incidence::SecrecyConfidential); kcal.setCategories(toStringList(stringVector)); kcal.setDtStart(toDate(date)); kcal.setDtEnd(toDate(date2)); kcal.setTransparency(KCalCore::Event::Transparent); kcal.setRecurrenceId(toDate(date2)); //TODO THISANDFUTURE kcal.recurrence()->setDaily(3); kcal.recurrence()->setDuration(5); kcal.recurrence()->addRDateTime(toDate(date2)); kcal.recurrence()->addRDate(toDate(date2).date()); kcal.recurrence()->addExDateTime(toDate(date3)); kcal.recurrence()->addExDate(toDate(date3).date()); KCalCore::RecurrenceRule *rr = kcal.recurrence()->defaultRRule(true); QList intList = QVector::fromStdVector(intVector).toList(); rr->setBySeconds(intList); rr->setByMinutes(intList); rr->setByHours(intList); rr->setByDays(QList() << KCalCore::RecurrenceRule::WDayPos(3,1) << KCalCore::RecurrenceRule::WDayPos(5,4)); rr->setByMonthDays(intList); rr->setByYearDays(intList); rr->setByMonths(intList); rr->setByWeekNumbers(intList); kcal.setSummary("summary"); kcal.setDescription("description"); kcal.setPriority(3); kcal.setStatus(KCalCore::Incidence::StatusConfirmed); kcal.setLocation("location"); kcal.setOrganizer(KCalCore::Person::Ptr(new KCalCore::Person("organizer", "organizer@email"))); //Url kcal.setNonKDECustomProperty("X-KOLAB-URL", "http://test.org"); KCalCore::Attendee::Ptr att(new KCalCore::Attendee("attendee", "attendee@email", false, KCalCore::Attendee::NeedsAction, KCalCore::Attendee::ReqParticipant)); att->setDelegate("mailto:delegatee"); att->setDelegator("mailto:delegator"); kcal.addAttendee(att); kcal.addAttachment(KCalCore::Attachment::Ptr(new KCalCore::Attachment(QString("uri"), "mimetype/mime"))); KCalCore::Alarm::Ptr alarm = KCalCore::Alarm::Ptr(new KCalCore::Alarm(&kcal)); KCalCore::Person::List addressees; addressees.append(KCalCore::Person::Ptr(new KCalCore::Person("name", "email@email"))); alarm->setEmailAlarm("subject", "text", addressees, QStringList()); //No support for attachments kcal.addAlarm(alarm); //TODO alarms kcal.setNonKDECustomProperty("X-KOLAB-key1", "value1"); kcal.setNonKDECustomProperty("X-KOLAB-key2", "value2"); kcal.setCustomProperty("SOMEOTHERAPP", "key2", "value2"); Q_ASSERT(kcal.nonKDECustomProperty("X-KOLAB-key1") == "value1"); Kolab::Event kolab; kolab.setUid("uid"); kolab.setCreated(date); kolab.setLastModified(date); kolab.setSequence(3); kolab.setClassification(Kolab::ClassConfidential); kolab.setCategories(stringVector); kolab.setStart(date); kolab.setEnd(date2); kolab.setTransparency(true); Kolab::RecurrenceRule rrule; rrule.setInterval(3); rrule.setFrequency(Kolab::RecurrenceRule::Daily); rrule.setCount(5); rrule.setBysecond(intVector); rrule.setByminute(intVector); rrule.setByhour(intVector); rrule.setByday(std::vector() << Kolab::DayPos(3, Kolab::Monday) << Kolab::DayPos(5, Kolab::Thursday)); rrule.setBymonthday(intVector); rrule.setByyearday(intVector); rrule.setByweekno(intVector); rrule.setBymonth(intVector); kolab.setRecurrenceRule(rrule); kolab.setRecurrenceID(date2, true); kolab.setRecurrenceDates(std::vector() << date2 << Kolab::cDateTime(date2.year(), date2.month(), date2.day())); kolab.setExceptionDates(std::vector() << date3 << Kolab::cDateTime(date3.year(), date3.month(), date3.day())); kolab.setSummary("summary"); kolab.setDescription("description"); kolab.setPriority(3); kolab.setStatus(Kolab::StatusConfirmed); kolab.setLocation("location"); kolab.setOrganizer(Kolab::ContactReference(Kolab::ContactReference::EmailReference,"organizer@email", "organizer")); //TODO uid kolab.setUrl("http://test.org"); Kolab::Attendee a(Kolab::ContactReference(Kolab::ContactReference::EmailReference,"attendee@email", "attendee"));//TODO uid a.setDelegatedTo(std::vector() << Kolab::ContactReference(Kolab::ContactReference::EmailReference,"delegatee@email", "delegatee")); a.setDelegatedFrom(std::vector() << Kolab::ContactReference(Kolab::ContactReference::EmailReference,"delegator@email", "delegator")); a.setCutype(Kolab::CutypeIndividual); kolab.setAttendees(std::vector() << a); Kolab::Attachment attach; attach.setUri("uri", "mimetype/mime"); kolab.setAttachments(std::vector() << attach); // std::vector receipents; // receipents.push_back("email@email"); // Kolab::Alarm alarm2("summary", "description", receipents); // kolab.setAlarms(std::vector() << alarm2); //The sorting is random, just sort them here how we think they should arrive so we don't have to sort during compare (due to lazyness). std::vector customproperties; customproperties.push_back(Kolab::CustomProperty("X-KDE-SOMEOTHERAPP-key2", "value2")); customproperties.push_back(Kolab::CustomProperty("key1", "value1")); customproperties.push_back(Kolab::CustomProperty("key2", "value2")); kolab.setCustomProperties(customproperties); QTest::newRow( "with endDate and recurrence duration" ) << kcal << kolab; } { KCalCore::Event kcal; kcal.setUid("uid"); kcal.setCreated(toDate(date)); kcal.setLastModified(toDate(date)); kcal.setRevision(3); kcal.setDtStart(toDate(date)); kcal.setDuration(KCalCore::Duration(toDate(date), toDate(date2))); kcal.recurrence()->setDaily(3); kcal.recurrence()->setEndDateTime(toDate(date3)); Kolab::Event kolab; kolab.setUid("uid"); kolab.setCreated(date); kolab.setLastModified(date); kolab.setSequence(3); kolab.setStart(date); kolab.setDuration(Kolab::Duration(0, 0, 1, 0)); Kolab::RecurrenceRule rrule; rrule.setInterval(3); rrule.setFrequency(Kolab::RecurrenceRule::Daily); rrule.setEnd(date3); kolab.setRecurrenceRule(rrule); QTest::newRow("with duration and recurrence endDate") << kcal << kolab; } { Kolab::cDateTime start(2011,1,1); Kolab::cDateTime end(2011,1,3); KCalCore::Event kcal; kcal.setUid("uid"); kcal.setCreated(toDate(date)); kcal.setLastModified(toDate(date)); kcal.setDtStart(toDate(start)); kcal.setDtEnd(toDate(end)); kcal.recurrence()->setDaily(3); kcal.recurrence()->setEndDateTime(toDate(end)); Kolab::Event kolab; kolab.setUid("uid"); kolab.setCreated(date); kolab.setLastModified(date); kolab.setStart(start); kolab.setEnd(end); Kolab::RecurrenceRule rrule; rrule.setInterval(3); rrule.setFrequency(Kolab::RecurrenceRule::Daily); rrule.setEnd(end); kolab.setRecurrenceRule(rrule); QTest::newRow("date only dates") << kcal << kolab; } { KCalCore::Event kcal; kcal.setUid("uid"); kcal.setCreated(toDate(date)); kcal.setLastModified(toDate(date)); kcal.setDtStart(toDate(date)); kcal.setSummary("äöü%@$£é¤¼²°€Š�"); Kolab::Event kolab; kolab.setUid("uid"); kolab.setCreated(date); kolab.setLastModified(date); kolab.setStart(date); kolab.setSummary(std::string(QString("äöü%@$£é¤¼²°€Š�").toUtf8().constData())); QTest::newRow("latin1+Unicode") << kcal << kolab; } } void KCalConversionTest::testConversion() { QFETCH(KCalCore::Event, kcal); QFETCH(Kolab::Event, kolab); KCalCore::Event::Ptr e = toKCalCore(kolab); const Kolab::Event &b = fromKCalCore(kcal); QCOMPARE(e->uid(), kcal.uid()); QCOMPARE(e->created(), kcal.created()); QCOMPARE(e->lastModified(), kcal.lastModified()); QCOMPARE(e->revision(), kcal.revision()); QCOMPARE(e->secrecy(), kcal.secrecy()); QCOMPARE(e->categories(), kcal.categories()); QCOMPARE(e->dtStart(), kcal.dtStart()); QCOMPARE(e->dtEnd(), kcal.dtEnd()); QCOMPARE(e->duration(), kcal.duration()); QCOMPARE(e->transparency(), kcal.transparency()); QCOMPARE(*e->recurrence(), *kcal.recurrence()); QCOMPARE(e->recurrenceId(), kcal.recurrenceId()); QCOMPARE(e->recurrenceType(), kcal.recurrenceType()); QCOMPARE(e->summary(), kcal.summary()); QCOMPARE(e->description(), kcal.description()); QCOMPARE(e->priority(), kcal.priority()); QCOMPARE(e->status(), kcal.status()); QCOMPARE(e->location(), kcal.location()); QCOMPARE(e->organizer()->name(), kcal.organizer()->name()); QCOMPARE(e->organizer()->email(), kcal.organizer()->email()); QCOMPARE(e->nonKDECustomProperty("X-KOLAB-URL"), kcal.nonKDECustomProperty("X-KOLAB-URL")); //otherwise we'd break the customProperties comparison e->removeNonKDECustomProperty("X-KOLAB-URL"); kcal.removeNonKDECustomProperty("X-KOLAB-URL"); compareAttendeesVectors(e->attendees(), kcal.attendees()); comparePointerVectors(e->attachments(), kcal.attachments()); // QCOMPARE(e->alarms(), kcal.alarms()); //TODO QCOMPARE(e->customProperties(), kcal.customProperties()); // QBENCHMARK { // toKCalCore(kolab); // } QCOMPARE(b.uid(), kolab.uid()); QCOMPARE(b.created(), kolab.created()); QCOMPARE(b.lastModified(), kolab.lastModified()); QCOMPARE(b.sequence(), kolab.sequence()); QCOMPARE(b.classification(), kolab.classification()); QCOMPARE(b.categories(), kolab.categories()); QCOMPARE(b.start(), kolab.start()); QCOMPARE(b.end(), kolab.end()); QCOMPARE(b.duration(), kolab.duration()); QCOMPARE(b.transparency(), kolab.transparency()); QCOMPARE(b.recurrenceRule(), kolab.recurrenceRule()); QCOMPARE(b.recurrenceID(), kolab.recurrenceID()); QCOMPARE(b.recurrenceDates(), kolab.recurrenceDates()); QCOMPARE(b.exceptionDates(), kolab.exceptionDates()); QCOMPARE(b.summary(), kolab.summary()); QCOMPARE(b.description(), kolab.description()); QCOMPARE(b.status(), kolab.status()); QCOMPARE(b.location(), kolab.location()); QCOMPARE(b.organizer(), kolab.organizer()); QCOMPARE(b.url(), kolab.url()); QCOMPARE(b.attendees(), kolab.attendees()); QCOMPARE(b.attachments(), kolab.attachments()); QCOMPARE(b.customProperties(), kolab.customProperties()); } void KCalConversionTest::testTodoConversion_data() { QTest::addColumn( "kcal" ); QTest::addColumn( "kolab" ); Kolab::cDateTime date(2011,2,2,12,11,10,true); Kolab::cDateTime date2(2011,2,2,12,12,10,true); { KCalCore::Todo kcal; kcal.setUid("uid"); kcal.setDtStart(toDate(date)); kcal.setDtDue(toDate(date2)); kcal.setRelatedTo("uid2", KCalCore::Incidence::RelTypeParent); Kolab::Todo kolab; kolab.setUid("uid"); kolab.setStart(date); kolab.setDue(date2); std::vector relateds; relateds.push_back("uid2"); kolab.setRelatedTo(relateds); QTest::newRow( "todo" ) << kcal << kolab; } } void KCalConversionTest::testTodoConversion() { QFETCH(KCalCore::Todo, kcal); QFETCH(Kolab::Todo, kolab); const KCalCore::Todo::Ptr e = toKCalCore(kolab); QCOMPARE(e->uid(), kcal.uid()); QCOMPARE(e->dtStart(), kcal.dtStart()); QCOMPARE(e->dtDue(), kcal.dtDue()); QCOMPARE(e->relatedTo(KCalCore::Incidence::RelTypeParent), kcal.relatedTo(KCalCore::Incidence::RelTypeParent)); const Kolab::Todo &b = fromKCalCore(kcal); QCOMPARE(b.uid(), kolab.uid()); QCOMPARE(b.start(), kolab.start()); QCOMPARE(b.due(), kolab.due()); QCOMPARE(b.relatedTo(), kolab.relatedTo()); } void KCalConversionTest::testJournalConversion_data() { QTest::addColumn( "kcal" ); QTest::addColumn( "kolab" ); Kolab::cDateTime date(2011,2,2,12,11,10,true); Kolab::cDateTime date2(2011,2,2,12,12,10,true); { KCalCore::Journal kcal; kcal.setUid("uid"); kcal.setDtStart(toDate(date)); kcal.setSummary("summary"); Kolab::Journal kolab; kolab.setUid("uid"); kolab.setStart(date); kolab.setSummary("summary"); QTest::newRow( "journal" ) << kcal << kolab; } } void KCalConversionTest::testJournalConversion() { QFETCH(KCalCore::Journal, kcal); QFETCH(Kolab::Journal, kolab); const KCalCore::Journal::Ptr e = toKCalCore(kolab); QCOMPARE(e->uid(), kcal.uid()); QCOMPARE(e->dtStart(), kcal.dtStart()); QCOMPARE(e->summary(), kcal.summary()); const Kolab::Journal &b = fromKCalCore(kcal); QCOMPARE(b.uid(), kolab.uid()); QCOMPARE(b.start(), kolab.start()); QCOMPARE(b.summary(), kolab.summary()); } void KCalConversionTest::testContactConversion_data() { QTest::addColumn( "kcal" ); QTest::addColumn( "kolab" ); { KContacts::Addressee kcal; kcal.setUid("uid"); kcal.setFormattedName("name"); Kolab::Contact kolab; kolab.setUid("uid"); kolab.setName("name"); QTest::newRow("basic") << kcal << kolab; } { KContacts::Addressee kcal; kcal.setUid("uid"); kcal.setFormattedName("name"); kcal.setBirthday(QDateTime(QDate(2012,2,2))); //Because QDateTime doesn't know date-only values we always end up with a date-time Kolab::Contact kolab; kolab.setUid("uid"); kolab.setName("name"); kolab.setBDay(Kolab::cDateTime(2012,2,2,0,0,0)); QTest::newRow("bday") << kcal << kolab; } { KContacts::Addressee kcal; kcal.setUid("uid"); //The first address is always the preferred kcal.setEmails(QStringList() << "email1@example.org" << "email2@example.org"); kcal.insertCustom("KOLAB", "EmailTypesemail1@example.org", "home,work"); Kolab::Contact kolab; kolab.setUid("uid"); Kolab::Email email1("email1@example.org", Kolab::Email::Work|Kolab::Email::Home); Kolab::Email email2("email2@example.org"); std::vector emails; emails.push_back(email1); emails.push_back(email2); kolab.setEmailAddresses(emails, 0); QTest::newRow("emailTypesAndPreference") << kcal << kolab; } } void KCalConversionTest::testContactConversion() { QFETCH(KContacts::Addressee, kcal); QFETCH(Kolab::Contact, kolab); const KContacts::Addressee &e = toKABC(kolab); QCOMPARE(e.uid(), kcal.uid()); QCOMPARE(e.formattedName(), kcal.formattedName()); QCOMPARE(e.emails(), kcal.emails()); QCOMPARE(e.preferredEmail(), kcal.preferredEmail()); foreach (const QString &mail, e.emails()) { QCOMPARE(e.custom(QLatin1String("KOLAB"), QString::fromLatin1("EmailTypes%1").arg(mail)), kcal.custom(QLatin1String("KOLAB"), QString::fromLatin1("EmailTypes%1").arg(mail))); } QCOMPARE(e.birthday(), kcal.birthday()); const Kolab::Contact &b = fromKABC(kcal); QCOMPARE(b.uid(), kolab.uid()); QCOMPARE(b.name(), kolab.name()); QCOMPARE(b.emailAddresses(), kolab.emailAddresses()); QCOMPARE(b.emailAddressPreferredIndex(), kolab.emailAddressPreferredIndex()); QCOMPARE(b.bDay(), kolab.bDay()); } // void KCalConversionTest::BenchmarkRoundtripKCAL() // { // const Kolab::Event &event = Kolab::readEvent(TEST_DATA_PATH "/testfiles/icalEvent.xml", true); // std::string result = Kolab::writeEvent(event); // QBENCHMARK { // Kolab::Conversion::toKCalCore(Kolab::readEvent(result, false)); // } // } QTEST_MAIN( KCalConversionTest ) #include "kcalconversiontest.moc" libkolab-1.0.2/tests/kcalconversiontest.h000066400000000000000000000026111262531616600205340ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef KCALCONVERSIONTEST_H #define KCALCONVERSIONTEST_H #include #include class KCalConversionTest : public QObject { Q_OBJECT private slots: void initTestCase(); void testDate_data(); void testDate(); void testDuration_data(); void testDuration(); void testConversion_data(); void testConversion(); void testTodoConversion_data(); void testTodoConversion(); void testJournalConversion_data(); void testJournalConversion(); void testContactConversion_data(); void testContactConversion(); void testDateTZ_data(); void testDateTZ(); }; #endiflibkolab-1.0.2/tests/kolabobjecttest.cpp000066400000000000000000000161331262531616600203320ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include "kolabobjecttest.h" #include #include "kolabformat/kolabobject.h" #include void KolabObjectTest::preserveLatin1() { KCalCore::Event::Ptr event(new KCalCore::Event()); event->setDtStart(KDateTime(QDate(2014, 1, 1))); const QString summary(QLatin1String("äöü%@$£é¤¼²°")); event->setSummary(summary); QCOMPARE(event->summary(), summary); //std::cout << event->summary().toStdString() << std::endl; KMime::Message::Ptr msg = Kolab::KolabObjectWriter::writeEvent(event); // qDebug() << msg->encodedContent(); KCalCore::Event::Ptr readEvent = Kolab::KolabObjectReader(msg).getEvent(); QVERIFY(readEvent); // std::cout << readEvent->summary().toStdString() << std::endl; QCOMPARE(readEvent->summary(), summary); } void KolabObjectTest::preserveUnicode() { KCalCore::Event::Ptr event(new KCalCore::Event()); event->setDtStart(KDateTime(QDate(2014, 1, 1))); QString summary(QString::fromUtf8("€Š�ـأبـ☺")); event->setSummary(summary); QCOMPARE(event->summary(), summary); // std::cout << event->summary().toStdString() << std::endl; KMime::Message::Ptr msg = Kolab::KolabObjectWriter::writeEvent(event); // qDebug() << msg->encodedContent(); KCalCore::Event::Ptr readEvent = Kolab::KolabObjectReader(msg).getEvent(); QVERIFY(readEvent); // std::cout << readEvent->summary().toStdString() << std::endl; QCOMPARE(readEvent->summary(), summary); } void KolabObjectTest::dontCrashWithEmptyOrganizer() { KCalCore::Event::Ptr event(new KCalCore::Event()); event->setOrganizer(KCalCore::Person::Ptr()); event->setDtStart(KDateTime(QDate(2012,11,11))); Kolab::KolabObjectWriter::writeEvent(event, Kolab::KolabV2); QCOMPARE(Kolab::ErrorHandler::instance().error(), Kolab::ErrorHandler::Debug); Kolab::KolabObjectWriter::writeEvent(event); qDebug() << Kolab::ErrorHandler::instance().error(); QCOMPARE(Kolab::ErrorHandler::instance().error(), Kolab::ErrorHandler::Debug); } void KolabObjectTest::dontCrashWithEmptyIncidence() { Kolab::KolabObjectWriter::writeEvent(KCalCore::Event::Ptr()); QCOMPARE(Kolab::ErrorHandler::instance().error(), Kolab::ErrorHandler::Critical); Kolab::KolabObjectWriter::writeTodo(KCalCore::Todo::Ptr()); QCOMPARE(Kolab::ErrorHandler::instance().error(), Kolab::ErrorHandler::Critical); Kolab::KolabObjectWriter::writeJournal(KCalCore::Journal::Ptr()); QCOMPARE(Kolab::ErrorHandler::instance().error(), Kolab::ErrorHandler::Critical); Kolab::KolabObjectWriter::writeIncidence(KCalCore::Event::Ptr()); QCOMPARE(Kolab::ErrorHandler::instance().error(), Kolab::ErrorHandler::Critical); Kolab::KolabObjectWriter::writeNote(KMime::Message::Ptr()); QCOMPARE(Kolab::ErrorHandler::instance().error(), Kolab::ErrorHandler::Critical); } void KolabObjectTest::parseRelationMembers() { { QString memberString("imap:/user/jan.aachen%40lhm.klab.cc/INBOX/20?message-id=%3Cf06aa3345a25005380b47547ad161d36%40lhm.klab.cc%3E&subject=Re%3A+test&date=Tue%2C+12+Aug+2014+20%3A42%3A59+%2B0200"); Kolab::RelationMember member = Kolab::parseMemberUrl(memberString); QString result = Kolab::generateMemberUrl(member); qDebug() << result; result.replace(QLatin1String("%20"),QLatin1String("+")); QEXPECT_FAIL("", "This is currently failing, probably a bug in the recent changes regarding the encoding.", Continue); QCOMPARE(result, memberString); } //user namespace by uid { Kolab::RelationMember member; member.uid = 20; member.mailbox = QList() << "INBOX"; member.user = "john.doe@example.org"; member.messageId = "messageid"; member.date = "date"; member.subject = "subject"; QString url = Kolab::generateMemberUrl(member); qDebug() << url; Kolab::RelationMember result = Kolab::parseMemberUrl(url); QCOMPARE(result.uid, member.uid); QCOMPARE(result.mailbox, member.mailbox); QEXPECT_FAIL("", "This is currently failing, probably a bug in the recent changes regarding the encoding.", Continue); QCOMPARE(result.user, member.user); QCOMPARE(result.messageId, member.messageId); QCOMPARE(result.date, member.date); QCOMPARE(result.subject, member.subject); } //shared namespace by uid { Kolab::RelationMember member; member.uid = 20; member.mailbox = QList() << "foo" << "bar"; member.messageId = "messageid"; member.date = "date"; member.subject = "subject"; QString url = Kolab::generateMemberUrl(member); qDebug() << url; Kolab::RelationMember result = Kolab::parseMemberUrl(url); QCOMPARE(result.uid, member.uid); QCOMPARE(result.mailbox, member.mailbox); QVERIFY(result.user.isEmpty()); QCOMPARE(result.messageId, member.messageId); QCOMPARE(result.date, member.date); QCOMPARE(result.subject, member.subject); } //by uuid/gid { Kolab::RelationMember member; member.gid = "fooobar"; QString url = Kolab::generateMemberUrl(member); qDebug() << url; Kolab::RelationMember result = Kolab::parseMemberUrl(url); QCOMPARE(result.gid, member.gid); } // chars to en/decode { Kolab::RelationMember member; member.uid = 20; member.mailbox = QList() << "spaces in folders" << "+^,:@"; member.user = "john.doe:^@example.org"; member.messageId = "messageid+^,:@"; member.date = "date+^,:@"; member.subject = "subject+^,:@"; QString url = Kolab::generateMemberUrl(member); qDebug() << url; Kolab::RelationMember result = Kolab::parseMemberUrl(url); QCOMPARE(result.uid, member.uid); QEXPECT_FAIL("", "This is currently failing, probably a bug in the recent changes regarding the encoding.", Continue); QCOMPARE(result.mailbox, member.mailbox); QEXPECT_FAIL("", "This is currently failing, probably a bug in the recent changes regarding the encoding.", Continue); QCOMPARE(result.user, member.user); QCOMPARE(result.messageId, member.messageId); QCOMPARE(result.date, member.date); QCOMPARE(result.subject, member.subject); } } QTEST_MAIN( KolabObjectTest ) #include "kolabobjecttest.moc" libkolab-1.0.2/tests/kolabobjecttest.h000066400000000000000000000020761262531616600200000ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef KOLABOBJECTTEST_H #define KOLABOBJECTTEST_H #include class KolabObjectTest: public QObject { Q_OBJECT private slots: void preserveLatin1(); void preserveUnicode(); void dontCrashWithEmptyOrganizer(); void dontCrashWithEmptyIncidence(); void parseRelationMembers(); }; #endif // KOLABOBJECTTEST_H libkolab-1.0.2/tests/legacyformattest.cpp000066400000000000000000000037201262531616600205260ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include "legacyformattest.h" #include "kolabformat/xmlobject.h" #include "kolabformat/errorhandler.h" #include "testutils.h" #include #include #include void V2Test::testReadDistlistUID() { std::ifstream t((TESTFILEDIR.toStdString()+"v2/contacts/distlistWithUID.xml").c_str()); std::stringstream buffer; buffer << t.rdbuf(); Kolab::XMLObject xo; const Kolab::DistList distlist = xo.readDistlist(buffer.str(), Kolab::KolabV2); foreach (const Kolab::ContactReference &contact, distlist.members()) { QVERIFY(!contact.uid().empty()); } QVERIFY(!Kolab::ErrorHandler::errorOccured()); } void V2Test::testWriteDistlistUID() { Kolab::DistList distlist; distlist.setUid("uid"); distlist.setName("name"); std::vector members; members.push_back(Kolab::ContactReference(Kolab::ContactReference::UidReference, "memberuid", "membername")); distlist.setMembers(members); Kolab::XMLObject xo; const std::string xml = xo.writeDistlist(distlist, Kolab::KolabV2); QVERIFY(QString::fromStdString(xml).contains("memberuid")); QVERIFY(!Kolab::ErrorHandler::errorOccured()); } QTEST_MAIN( V2Test ) #include "legacyformattest.moc"libkolab-1.0.2/tests/legacyformattest.h000066400000000000000000000016641262531616600202000ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef V2TEST_H #define V2TEST_H #include class V2Test: public QObject { Q_OBJECT private slots: void testReadDistlistUID(); void testWriteDistlistUID(); }; #endif // V2TEST_H libkolab-1.0.2/tests/mimeobjecttest.cpp000066400000000000000000000221201262531616600201620ustar00rootroot00000000000000/* * Copyright (C) 2012 Sofia Balicka * Copyright (C) 2014 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #include #include "mimeobjecttest.h" #include "testutils.h" #include "kolabformat/mimeobject.h" #include "conversion/commonconversion.h" #include #include #include static std::string readFile(const QString &path) { std::ifstream t(path.toStdString().c_str()); std::stringstream buffer; buffer << t.rdbuf(); return buffer.str(); } static QString normalizeMimemessage(const std::string &path) { QString qString = Kolab::Conversion::fromStdString(path); normalizeMimemessage(qString); return qString; } template void testFunction(const QString &filename, Kolab::Version version, Kolab::ObjectType type, T (Kolab::MIMEObject::* readFunction) (const std::string&), std::string (Kolab::MIMEObject::* writeFunction) (const T &, Kolab::Version, const std::string &)) { const std::string input = readFile(filename); Kolab::MIMEObject mimeobject; const T object = (mimeobject.*readFunction)(input); QCOMPARE(mimeobject.getType(), type); const std::string message = (mimeobject.*writeFunction)(object, version, std::string()); DIFFCOMPARE(normalizeMimemessage(message), normalizeMimemessage(input)); } template void testFunction(T (Kolab::MIMEObject::* readFunction) (const std::string&), std::string (Kolab::MIMEObject::* writeFunction) (const T &, Kolab::Version, const std::string &)) { testFunction(TESTVALUE(QString, mimeFileName), TESTVALUE(Kolab::Version, version), TESTVALUE(Kolab::ObjectType, type), readFunction, writeFunction); } void MIMEObjectTest::testEvent_data() { QTest::addColumn("version"); QTest::addColumn("type"); QTest::addColumn("mimeFileName"); QTest::newRow("v2eventSimple") << Kolab::KolabV2 << Kolab::EventObject << getPath("v2/event/simple.ics.mime"); QTest::newRow("v2eventComplex") << Kolab::KolabV2 << Kolab::EventObject << getPath("v2/event/complex.ics.mime"); QTest::newRow("v2eventAttachment") << Kolab::KolabV2 << Kolab::EventObject << getPath("v2/event/attachment.ics.mime"); QTest::newRow("v2eventAllday") << Kolab::KolabV2 << Kolab::EventObject << getPath("v2/event/allday.ics.mime"); QTest::newRow("v2eventUtf8Attachment") << Kolab::KolabV2 << Kolab::EventObject << getPath("v2/event/attachmentUtf8.ics.mime"); QTest::newRow("v3eventSimple") << Kolab::KolabV3 << Kolab::EventObject << getPath("v3/event/simple.ics.mime"); QTest::newRow("v3eventComplex") << Kolab::KolabV3 << Kolab::EventObject << getPath("v3/event/complex.ics.mime"); QTest::newRow("v3utf8quotedPrintable") << Kolab::KolabV3 << Kolab::EventObject << getPath("v3/event/utf8quotedPrintable.ics.mime"); //TODO move to read-only // QTest::newRow("v2eventHorde") << Kolab::KolabV2 << Kolab::EventObject << getPath("v2/event/horde.ics") << getPath("v2/event/horde.ics.mime"); //TODO read-only test, we never write base64 // QTest::newRow("v3utf8base64") << Kolab::KolabV3 << Kolab::EventObject << getPath("v3/event/utf8base64.ics.mime"); //TODO read-only test, we never write 8-bit // QTest::newRow("v3utf88bit") << Kolab::KolabV3 << Kolab::EventObject << getPath("v3/event/utf88bit.ics.mime"); } void MIMEObjectTest::testEvent() { testFunction(&Kolab::MIMEObject::readEvent, &Kolab::MIMEObject::writeEvent); } void MIMEObjectTest::testTodo_data() { QTest::addColumn("version"); QTest::addColumn("type"); QTest::addColumn("mimeFileName"); QTest::newRow("v2todoSimple") << Kolab::KolabV2 << Kolab::TodoObject << getPath("v2/task/simple.ics.mime"); QTest::newRow("v2todoComplex") << Kolab::KolabV2 << Kolab::TodoObject << getPath("v2/task/complex.ics.mime"); QTest::newRow("v2todoPrio1") << Kolab::KolabV2 << Kolab::TodoObject << getPath("v2/task/prioritytest1.ics.mime"); QTest::newRow("v2todoPrio2") << Kolab::KolabV2 << Kolab::TodoObject << getPath("v2/task/prioritytest2.ics.mime"); QTest::newRow("v3todoSimple") << Kolab::KolabV3 << Kolab::TodoObject << getPath("v3/task/simple.ics.mime"); QTest::newRow("v3todoComplex") << Kolab::KolabV3 << Kolab::TodoObject << getPath("v3/task/complex.ics.mime"); } void MIMEObjectTest::testTodo() { testFunction(&Kolab::MIMEObject::readTodo, &Kolab::MIMEObject::writeTodo); } void MIMEObjectTest::testJournal_data() { QTest::addColumn("version"); QTest::addColumn("type"); QTest::addColumn("mimeFileName"); QTest::newRow("v2journalSimple") << Kolab::KolabV2 << Kolab::JournalObject << getPath("v2/journal/simple.ics.mime"); QTest::newRow("v2journalComplex") << Kolab::KolabV2 << Kolab::JournalObject << getPath("v2/journal/complex.ics.mime"); QTest::newRow("v3journalSimple") << Kolab::KolabV3 << Kolab::JournalObject << getPath("v3/journal/simple.ics.mime"); QTest::newRow("v3journalComplex") << Kolab::KolabV3 << Kolab::JournalObject << getPath("v3/journal/complex.ics.mime"); } void MIMEObjectTest::testJournal() { testFunction(&Kolab::MIMEObject::readJournal, &Kolab::MIMEObject::writeJournal); } void MIMEObjectTest::testNote_data() { QTest::addColumn("version"); QTest::addColumn("type"); QTest::addColumn("mimeFileName"); QTest::newRow("v3noteSimple") << Kolab::KolabV3 << Kolab::NoteObject << getPath("v3/note/note.mime.mime"); } void MIMEObjectTest::testNote() { testFunction(&Kolab::MIMEObject::readNote, &Kolab::MIMEObject::writeNote); } void MIMEObjectTest::testContact_data() { QTest::addColumn("version"); QTest::addColumn("type"); QTest::addColumn("mimeFileName"); QTest::newRow("v2contactSimple") << Kolab::KolabV2 << Kolab::ContactObject << getPath("v2/contacts/simple.vcf.mime"); QTest::newRow("v2contactAddress") << Kolab::KolabV2 << Kolab::ContactObject << getPath("v2/contacts/address.vcf.mime"); //FIXME Figure out why this is broken // QTest::newRow("v2contactBug238996") << Kolab::KolabV2 << Kolab::ContactObject << getPath("v2/contacts/bug238996.vcf.mime"); QTest::newRow("v2contactDisplayname") << Kolab::KolabV2 << Kolab::ContactObject << getPath("v2/contacts/displayname.vcf.mime"); QTest::newRow("v2contactEmails") << Kolab::KolabV2 << Kolab::ContactObject << getPath("v2/contacts/emails.vcf.mime"); QTest::newRow("v2contactPhonenumbers") << Kolab::KolabV2 << Kolab::ContactObject << getPath("v2/contacts/phonenumbers.vcf.mime"); QTest::newRow("v3contactSimple") << Kolab::KolabV3 << Kolab::ContactObject << getPath("v3/contacts/simple.vcf.mime"); QTest::newRow("v3contactComplex") << Kolab::KolabV3 << Kolab::ContactObject << getPath("v3/contacts/complex.vcf.mime"); //FIXME Tested in read-only mode in formattest, perhaps move to read-only test that compares with ical? // QTest::newRow("v3contactPng") << Kolab::KolabV3 << Kolab::ContactObject << getPath("v3/readonly/png.vcf.mime"); //FIXME Reference files needs to be adjusted due to fix in how pictures are stored // QTest::newRow("v2contactComplex") << Kolab::KolabV2 << Kolab::ContactObject << getPath("v2/contacts/complex.vcf.mime"); // FIXME Reference files needs to be adjusted due to fix in how pictures are stored // QTest::newRow("v2contactPicture") << Kolab::KolabV2 << Kolab::ContactObject << getPath("v2/contacts/picture.vcf.mime"); //FIXME the following test fails because the vcard implementation always writes jpeg (which is lossy). //The reference vcf file is therefore probably also not really useful // QTest::newRow("v2pictureJPGHorde") << Kolab::KolabV2 << Kolab::ContactObject << getPath("v2/contacts/pictureJPGHorde.vcf.mime"); } void MIMEObjectTest::testContact() { testFunction(&Kolab::MIMEObject::readContact, &Kolab::MIMEObject::writeContact); } void MIMEObjectTest::testDistlist_data() { QTest::addColumn("version"); QTest::addColumn("type"); QTest::addColumn("mimeFileName"); QTest::newRow("v3distlistSimple") << Kolab::KolabV3 << Kolab::DistlistObject << getPath("v3/contacts/distlist.vcf.mime"); } void MIMEObjectTest::testDistlist() { testFunction(&Kolab::MIMEObject::readDistlist, &Kolab::MIMEObject::writeDistlist); } QTEST_MAIN(MIMEObjectTest) #include "mimeobjecttest.moc" libkolab-1.0.2/tests/mimeobjecttest.h000066400000000000000000000026041262531616600176340ustar00rootroot00000000000000/* * Copyright (C) 2012 Sofia Balicka * Copyright (C) 2014 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef MIMEOBJECTTEST_H #define MIMEOBJECTTEST_H #include /** * Read-Write roundtrip test. * * Ensures we can read a mime message, serialize it again, and contents are still the same. */ class MIMEObjectTest: public QObject { Q_OBJECT private slots: void testEvent_data(); void testEvent(); void testTodo_data(); void testTodo(); void testJournal_data(); void testJournal(); void testNote_data(); void testNote(); void testContact_data(); void testContact(); void testDistlist_data(); void testDistlist(); }; #endif // MIMEOBJECTTEST_H libkolab-1.0.2/tests/testfiles/000077500000000000000000000000001262531616600164455ustar00rootroot00000000000000libkolab-1.0.2/tests/testfiles/timezone/000077500000000000000000000000001262531616600202775ustar00rootroot00000000000000libkolab-1.0.2/tests/testfiles/timezone/windowsTimezone.ics000066400000000000000000000005611262531616600242060ustar00rootroot00000000000000BEGIN:VCALENDAR PRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN VERSION:2.0 BEGIN:VEVENT DTSTAMP:20090901T113644Z CREATED:20090901T113644Z UID:KOrganizer-1353608432.168 LAST-MODIFIED:20090901T113644Z SUMMARY:Windows Event LOCATION:Here DTSTART;TZID=Europe/Berlin:20090902T080000 DTEND;TZID=Europe/Berlin:20090902T090000 TRANSP:OPAQUE END:VEVENT END:VCALENDAR libkolab-1.0.2/tests/testfiles/timezone/windowsTimezoneV3.mime000066400000000000000000000045351262531616600245750ustar00rootroot00000000000000Date: Thu, 28 Feb 2013 18:22:55 +0000 X-Kolab-Type: application/x-vnd.kolab.event X-Kolab-Mime-Version: 3.0 User-Agent: Libkolab-0.5 Content-Type: multipart/mixed; boundary="nextPart3504925.NqhbgOChlS" Subject: KOrganizer-1353608432.168 MIME-Version: 1.0 --nextPart3504925.NqhbgOChlS Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart3504925.NqhbgOChlS Content-Type: application/calendar+xml; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" Libkolab-0.5 Libkolabxml-0.8 2.0 3.0dev1 KOrganizer-1353608432.168 2009-09-01T11:36:44Z 2009-09-01T11:36:44Z 0 PUBLIC /kolab.org/W. Europe Standard Time 2009-09-02T08:00:00 /kolab.org/W. Europe Standard Time 2009-09-02T09:00:00 Windows Event Here --nextPart3504925.NqhbgOChlS-- libkolab-1.0.2/tests/testfiles/v2/000077500000000000000000000000001262531616600167745ustar00rootroot00000000000000libkolab-1.0.2/tests/testfiles/v2/contacts/000077500000000000000000000000001262531616600206125ustar00rootroot00000000000000libkolab-1.0.2/tests/testfiles/v2/contacts/address.vcf000066400000000000000000000002641262531616600227410ustar00rootroot00000000000000BEGIN:VCARD CLASS:PUBLIC ADR;TYPE=home:PO Box;;Street;Locality;Region;Postal Code;Germany FN:Home Address N:Address;Home;;; NAME:Home Address UID:TX1vqbIUlB VERSION:3.0 END:VCARD libkolab-1.0.2/tests/testfiles/v2/contacts/address.vcf.mime000066400000000000000000000026321262531616600236700ustar00rootroot00000000000000Date: Tue, 01 Sep 2009 10:56:10 +0200 X-Kolab-Type: application/x-vnd.kolab.contact User-Agent: Libkolab-3.0.0 Content-Type: multipart/mixed; boundary="nextPart3449010.4rJ2gEvUCK" Subject: TX1vqbIUlB MIME-Version: 1.0 --nextPart3449010.4rJ2gEvUCK Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart3449010.4rJ2gEvUCK Content-Type: application/x-vnd.kolab.contact; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" KAddressBook 3.3, Kolab resource TX1vqbIUlB dummydate public Home Address Home Address
home 16 Street PO Box Locality Region Postal Code Germany
home
--nextPart3449010.4rJ2gEvUCK-- libkolab-1.0.2/tests/testfiles/v2/contacts/bug238996.vcf000066400000000000000000000021171262531616600225750ustar00rootroot00000000000000BEGIN:VCARD CLASS:PUBLIC ADR;TYPE=home:Home Post Office Box;;Home Street;Home Locality;Home Region;H ome Postal Code;Gabon ADR;TYPE=work:Work PO Box;;Work Street;Work Locality;Work Region;Work Posta l Code;Azerbaijan BDAY:2009-07-27T00:00:00 EMAIL;TYPE=PREF:first@email.org EMAIL:second@email.org FN:Firstname Lastname N:Lastname;Firstname;;; NAME:Firstname Lastname NICKNAME:Nickname NOTE:Notes ORG:Organization;Department TEL;TYPE=HOME:+4930-homephone TEL;TYPE=WORK:+4930-workphone TEL;TYPE=CELL:+4930-mobile TEL;TYPE=FAX;TYPE=WORK:+4930-fax TITLE:Title UID:Huu5X7hfYy URL:www.homepage.org VERSION:3.0 X-KADDRESSBOOK-BlogFeed:www.blog.test X-KADDRESSBOOK-X-Anniversary:2009-07-28 X-KADDRESSBOOK-X-AssistantsName:Assistant X-KADDRESSBOOK-X-IMAddress:messaging X-KADDRESSBOOK-X-ManagersName:Manager X-KADDRESSBOOK-X-Office:Office X-KADDRESSBOOK-X-Profession:Profession X-KADDRESSBOOK-X-SpousesName:Partner END:VCARD libkolab-1.0.2/tests/testfiles/v2/contacts/bug238996.vcf.mime000066400000000000000000000055251262531616600235310ustar00rootroot00000000000000Date: Mon, 31 Aug 2009 18:23:30 +0200 X-Kolab-Type: application/x-vnd.kolab.contact User-Agent: Libkolab-3.0.0 Content-Type: multipart/mixed; boundary="nextPart3762459.HDmZFN3AqE" Subject: Huu5X7hfYy From: Firstname Lastname MIME-Version: 1.0 --nextPart3762459.HDmZFN3AqE Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart3762459.HDmZFN3AqE Content-Type: application/x-vnd.kolab.contact; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" KAddressBook 3.3, Kolab resource Huu5X7hfYy Notes dummydate public Firstname Lastname Firstname Lastname Organization www.homepage.org messaging Department Office Profession Title Manager Assistant Nickname Partner 2009-07-27 2009-07-28 home2 +4930-homephone mobile +4930-mobile business2 +4930-workphone businessfax +4930-fax Firstname Lastname first@email.org Firstname Lastname second@email.org
home 16 Home Street Home Post Office Box Home Locality Home Region Home Postal Code Gabon
business 32 Work Street Work PO Box Work Locality Work Region Work Postal Code Azerbaijan
home
--nextPart3762459.HDmZFN3AqE-- libkolab-1.0.2/tests/testfiles/v2/contacts/complex.vcf000066400000000000000000000124731262531616600227700ustar00rootroot00000000000000BEGIN:VCARD CLASS:PUBLIC ADR;TYPE=home:Home Post Office Box;;Home Street;Home Locality;Home Region;H ome Postal Code;Gabon ADR;TYPE=work:Work PO Box;;Work Street;Work Locality;Work Region;Work Posta l Code;Azerbaijan BDAY:2009-07-27T00:00:00 EMAIL;TYPE=PREF:first@email.org EMAIL:second@email.org FN:Firstname Lastname LOGO;ENCODING=b;TYPE=image/png:iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVU AAAACXBIWXMAAA5NAAAOnAHe9pxXAAAEGUlEQVR4nO2dzWtjVRjG35ubNOkHY7+w07R22gxF0oK CRaY4uOkfoK4cKIIbKS50PQwMQpmFCOpW1AoiXbtwpQsXunBo68AoCDOCLZLaVKx0Jh+dpO3NdV +e99oMmD7F57d8Tk/eQ345cHpy7omZEEIIIYQQQgghhBBCPAaBmY04bU91ciD/Q3ZQmOr0KEQyE kKGhJAhIWRICBlpMxtHDXEcryX0k8jT00JhJpN5EeV6Y8mQEDIkhAwJIUNCyEgntLmyVlY+g3mx WIT5pUuT7YzpXwicOIRxuP2O+0phEMH8cGwZd4id2ha7NfL5Ufg+ptP4rdcMIUNCyJAQMiSEDAk hw11lRRHcgjEzs4WFBZjn83mYl8u7MI9jf3Xi4qymUg+/gfmFPjwmM7NUdgzmx5XvYN7IXoV5HO PVmplZFPltcExt/bX4z5EQMiSEDAkhQ0LIkBAy3GVvrVZzOzWbhzBfXV2F+VShAPPR0aSzeM5G3 tGfMB5ufAvzzMXX3QreqrtnD79WxWZhHsXdbo1a/ZHbhtAMIUNCyJAQMiSEDAkhw11lVSoVt1Oz 2YT5lfkXYD4xAE/e2/7vn7g1unN4lZXL4iFnJ1+BeRhvuTXC421ce/AJmGcOvoJ5tdHr1jgs98P 8zVfH4a6nZggZEkKGhJAhIWRICBkJX+EeuZ3W1m7DfGb2GZjntt+HeWFu0a2RCvDXvsHxPu7Q+t 7J624Nb7vMYvw5zfZOwDzqnXRLhGEO5m9f67+Bcs0QMiSEDAkhQ0LIkBAyAjObQw1bW5s/ep1az hm6kYujMP/lLl4BjR994A4sX7zsFP8L57G3Kkz6zOG2VupJmNejZ53X6XIrPNr5Aebvfbj62ulH JM4MCSFDQsiQEDIkhAwJIcNd9pZKpXWvU7Vab1MkfqajVb/n9hiL3oV5/1QVd/BOvQX+ITYLBvC 4AnyAr97Cm6eN0oZb4kH4EvwnYeb5Rd11ch6QEDIkhAwJIUNCyAjMbMppe7qTAznJnc8Hb6L8uZ eH8KOwLf/xCR/vKWC8KowD/FjF+pc/4x1EM5t/4+Etp+k3FGqGkCEhZEgIGRJChoSQkTYz77y+f 46/A0xPD1+HDdk93KHl7WUlVXEandcKUr/CvDAW/p1Q5OukEZxEM4QMCSFDQsiQEDIkhIyke3vP lDAX46vguvANbc0y3n/au+/cA2JmYVcafiCHpvGlupkRfE1GkImGvRrtohlChoSQISFkSAgZEkK GhJBBu+ytlv+AD3zslvp+Qvl+JfoU5XfLuS+8GgOpNDxFN7Njb6G8rz9YQnnYqLd3W3ICmiFkSA gZEkKGhJAhIWTQrrI+2jiAZ/+Xlw/839FoH+fZBoO/JPbx0hw+9Daw2eOX0L295xoJIUNCyJAQM iSEjH8AXiPOHbAJgiYAAAAASUVORK5CYII= N:Lastname;Firstname;;; NICKNAME:Nickname NOTE:Notes ORG:Organization;Department PHOTO;ENCODING=b;TYPE=image/png:iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pV UAAAACXBIWXMAAA5NAAAOnAHe9pxXAAAEBUlEQVR4nO2dwWsUZxjG3+zMusmaTbJZN6iNCS1CW6 Ko0V4qCVJCaw4eFHJQCko9t4dALy1oqXgTQfDiwZOgBy+CiNVAKDQH7amHQOmtOViztJCw2WR3M rOZ/gPPG9iwJE/0+R2fmfneIb988PLtNzNmQgghhBCi/XTs9A20jS+tH+Y5+9695qn94BxJd6pG xh1I7AgSQoaEkCEhZEgIGRJCxu5re7+yURSPfjo6g/JSsYRbVTObmZ/JwwM1G0HxyIcjL1FezBe LXo25hTlc47HVUawZQoaEkCEhZEgIGRJCRrjTN+Byzq6geOKziXsoHx8bz6J89rdZv0Zkl1E8dm rsDspPHjkJa7z+47Vfo0U0Q8iQEDIkhAwJIUNCyNieLivFa2adU52wYzIzmzw9+Q3Khw8PByivV CtwnCiI3Ns6+8XZuygvl8qwxmJ1EY5Ts5pbo1U0Q8iQEDIkhAwJIUNCyGhvl+VsJOv9uvcFys+M nznhDZXvz8NO5231LTw/thjm5eGyV8LiOMY11nCNpJ7AfC1cc2u0imYIGRJChoSQISFkSAgZEkL G1tre83izWrk0ANvb4x8dgxvJGpkGbDvNzGqreMEuDnF7m2RwS7pu614JSxJ8TRw7NSJ8fiNsuD VaRTOEDAkhQ0LIkBAyJIQMv8u6ZBe8Q0OFoUcoH+wbhBvJlqIl+BNuUsNdi5lZnMedznqKu6b1L M6TDr9G05o4T3GeNPFYmbB9/9eaIWRICBkSQoaEkCEhZPhdVhC460xLtWX4no43f7+B52/s28AD lfwbS4v4dSPmPV4J+7tN8s2OOaXN2XPX1cTPdW4FzRAyJIQMCSFDQsiQEDL8LutB87F3aOXq2gL KC58UnqM8aUQ9KK/n6n79vU5ecHKv+9qsAfK6Ke/pAuf8IHIb0pbRDCFDQsiQEDIkhAwJIUNCyN jaRrn7ye8oXple/hjlhYGeX1Hel+2E55uZLWeX8L11Ohc47XCuP+eVsChxVgu9dngVx0GzfY/Za IaQISFkSAgZEkKGhJDR3qdwb9t/KF5Jq0dR3vVz90NvqAO5D6ZQvpj+A1fy0hS3Rn3/uq/ttUpc wTviMht4tdD5JTrMqMt6Z5EQMiSEDAkhQ0LI2J43ynXg1aG61S56l0Q/NV6h/FBu6BbKK9VFr/v yvwDxl/0I84HMDRTvSUL49wrSoG1fmdAMIUNCyJAQMiSEDAkhY/d9g+p6+DmKDx488AvKe7t7va 119ueTebyN7nh4CsX7y/ufobyY6fNrvHBq6BtUuwMJIUNCyJAQMiSEDAkhY/e1vR43Db4xOejKX vMuaU7H3zmH8O/BXo2eTWp821oNzRAyJIQMCSFDQsiQECGEEEII8R7wP5vl0Mt4/hNcAAAAAElF TkSuQmCC SOUND;ENCODING=b:iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICA gIfAhkiAAAAAlwSFlzAAABuwAAAbsBOuzj4gAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlL m9yZ5vuPBoAAAFCSURBVDiNnZI9btwwEEbfDH9EuVlXPoqbrdP4CjlBOpc5kGsXRq7gJqUbX4Na BLDEn6WLQIQUOIiz0w048/CB86S1xiX1/XF+UAH7/PwzAof/2J2Ox9vr01v7qgI2xni4u/uCiFB rJedMzplaKwDee5ZlYZ5nSim8vLweAE5vjRWAiABgjEFVUVVqrTjnKKXQWsNai6oSY2QFiIDNOe /yiQjeewDO5zMigqr2t3X+NDcEsCEMtNZ6im2pKtZavPd9MYRhn2Ach+np6cenP3Ech2kLkEvPe HMfm4hgL9oGfi0AbQ/4pBPT8Xh7vTY7wOoEwLIspJRwzpFSYp5nUkrdg78B+jVCCHjvKaUAvx3x 3ncPPgT86YSqdrmMMTsP+sy2WZ3YljGGYRhwzqGq3YMPE4xj+KcT4ximbX+xB1ff4gPAOzDpl8j vlpTvAAAAAElFTkSuQmCC TEL;TYPE=HOME:+4930-homephone TEL;TYPE=WORK:+4930-workphone TEL;TYPE=CELL:+4930-mobile TEL;TYPE=FAX;TYPE=WORK:+4930-fax TITLE:Title UID:Huu5X7hfYy URL:www.homepage.org VERSION:3.0 X-KADDRESSBOOK-BlogFeed:www.blog.test X-KADDRESSBOOK-X-Anniversary:2009-07-28 X-KADDRESSBOOK-X-AssistantsName:Assistant X-KADDRESSBOOK-X-IMAddress:messaging X-KADDRESSBOOK-X-ManagersName:Manager X-KADDRESSBOOK-X-Office:Office X-KADDRESSBOOK-X-Profession:Profession X-KADDRESSBOOK-X-SpousesName:Partner X-KOLAB-PictureAttachmentName:kolab-picture.png X-KOLAB-LogoAttachmentName:kolab-logo.png X-KOLAB-SoundAttachmentName:sound END:VCARD libkolab-1.0.2/tests/testfiles/v2/contacts/complex.vcf.mime000066400000000000000000000157371262531616600237240ustar00rootroot00000000000000Date: Mon, 31 Aug 2009 18:23:30 +0200 X-Kolab-Type: application/x-vnd.kolab.contact User-Agent: Libkolab-3.0.0 Content-Type: multipart/mixed; boundary="nextPart3762459.HDmZFN3AqE" Subject: Huu5X7hfYy From: Firstname Lastname MIME-Version: 1.0 --nextPart3762459.HDmZFN3AqE Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart3762459.HDmZFN3AqE Content-Type: application/x-vnd.kolab.contact; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" KAddressBook 3.3, Kolab resource Huu5X7hfYy Notes dummydate public Firstname Lastname Firstname Lastname Organization www.homepage.org messaging Department Office Profession Title Manager Assistant Nickname Partner 2009-07-27 2009-07-28 kolab-picture.png kolab-logo.png sound home2 +4930-homephone mobile +4930-mobile business2 +4930-workphone businessfax +4930-fax Firstname Lastname first@email.org Firstname Lastname second@email.org
home 16 Home Street Home Post Office Box Home Locality Home Region Home Postal Code Gabon
business 32 Work Street Work PO Box Work Locality Work Region Work Postal Code Azerbaijan
home
--nextPart3762459.HDmZFN3AqE Content-Type: image/png; name="kolab-picture.png" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="kolab-picture.png" iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAACXBIWXMAAA5NAAAOnAHe9pxXAAAE BUlEQVR4nO2dwWsUZxjG3+zMusmaTbJZN6iNCS1CW6Ko0V4qCVJCaw4eFHJQCko9t4dALy1oqXgT QfDiwZOgBy+CiNVAKDQH7amHQOmtOViztJCw2WR3MrOZ/gPPG9iwJE/0+R2fmfneIb988PLtNzNm QgghhBCi/XTs9A20jS+tH+Y5+9695qn94BxJd6pGxh1I7AgSQoaEkCEhZEgIGRJCxu5re7+yURSP fjo6g/JSsYRbVTObmZ/JwwM1G0HxyIcjL1FezBeLXo25hTlc47HVUawZQoaEkCEhZEgIGRJCRrjT N+Byzq6geOKziXsoHx8bz6J89rdZv0Zkl1E8dmrsDspPHjkJa7z+47Vfo0U0Q8iQEDIkhAwJIUNC yNieLivFa2adU52wYzIzmzw9+Q3Khw8PByivVCtwnCiI3Ns6+8XZuygvl8qwxmJ1EY5Ts5pbo1U0 Q8iQEDIkhAwJIUNCyGhvl+VsJOv9uvcFys+MnznhDZXvz8NO5231LTw/thjm5eGyV8LiOMY11nCN pJ7AfC1cc2u0imYIGRJChoSQISFkSAgZEkLG1tre83izWrk0ANvb4x8dgxvJGpkGbDvNzGqreMEu DnF7m2RwS7pu614JSxJ8TRw7NSJ8fiNsuDVaRTOEDAkhQ0LIkBAyJIQMv8u6ZBe8Q0OFoUcoH+wb hBvJlqIl+BNuUsNdi5lZnMedznqKu6b1LM6TDr9G05o4T3GeNPFYmbB9/9eaIWRICBkSQoaEkCEh ZPhdVhC460xLtWX4no43f7+B52/s28ADlfwbS4v4dSPmPV4J+7tN8s2OOaXN2XPX1cTPdW4FzRAy JIQMCSFDQsiQEDL8LutB87F3aOXq2gLKC58UnqM8aUQ9KK/n6n79vU5ecHKv+9qsAfK6Ke/pAuf8 IHIb0pbRDCFDQsiQEDIkhAwJIUNCyNjaRrn7ye8oXple/hjlhYGeX1Hel+2E55uZLWeX8L11Ohc4 7XCuP+eVsChxVgu9dngVx0GzfY/ZaIaQISFkSAgZEkKGhJDR3qdwb9t/KF5Jq0dR3vVz90NvqAO5 D6ZQvpj+A1fy0hS3Rn3/uq/ttUpcwTviMht4tdD5JTrMqMt6Z5EQMiSEDAkhQ0LI2J43ynXg1aG6 1S56l0Q/NV6h/FBu6BbKK9VFr/vyvwDxl/0I84HMDRTvSUL49wrSoG1fmdAMIUNCyJAQMiSEDAkh Y/d9g+p6+DmKDx488AvKe7t7va119ueTebyN7nh4CsX7y/ufobyY6fNrvHBq6BtUuwMJIUNCyJAQ MiSEDAkhY/e1vR43Db4xOejKXvMuaU7H3zmH8O/BXo2eTWp821oNzRAyJIQMCSFDQsiQECGEEEII 8R7wP5vl0Mt4/hNcAAAAAElFTkSuQmCC --nextPart3762459.HDmZFN3AqE Content-Type: image/png; name="kolab-logo.png" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="kolab-logo.png" iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAACXBIWXMAAA5NAAAOnAHe9pxXAAAE GUlEQVR4nO2dzWtjVRjG35ubNOkHY7+w07R22gxF0oKCRaY4uOkfoK4cKIIbKS50PQwMQpmFCOpW 1AoiXbtwpQsXunBo68AoCDOCLZLaVKx0Jh+dpO3NdV+e99oMmD7F57d8Tk/eQ345cHpy7omZEEII IYQQQgghhBBCPAaBmY04bU91ciD/Q3ZQmOr0KEQyEkKGhJAhIWRICBlpMxtHDXEcryX0k8jT00Jh JpN5EeV6Y8mQEDIkhAwJIUNCyEgntLmyVlY+g3mxWIT5pUuT7YzpXwicOIRxuP2O+0phEMH8cGwZ d4id2ha7NfL5Ufg+ptP4rdcMIUNCyJAQMiSEDAkhw11lRRHcgjEzs4WFBZjn83mYl8u7MI9jf3Xi 4qymUg+/gfmFPjwmM7NUdgzmx5XvYN7IXoV5HOPVmplZFPltcExt/bX4z5EQMiSEDAkhQ0LIkBAy 3GVvrVZzOzWbhzBfXV2F+VShAPPR0aSzeM5G3tGfMB5ufAvzzMXX3QreqrtnD79WxWZhHsXdbo1a /ZHbhtAMIUNCyJAQMiSEDAkhw11lVSoVt1Oz2YT5lfkXYD4xAE/e2/7vn7g1unN4lZXL4iFnJ1+B eRhvuTXC421ce/AJmGcOvoJ5tdHr1jgs98P8zVfH4a6nZggZEkKGhJAhIWRICBkJX+EeuZ3W1m7D fGb2GZjntt+HeWFu0a2RCvDXvsHxPu7Q+t7J624Nb7vMYvw5zfZOwDzqnXRLhGEO5m9f67+Bcs0Q MiSEDAkhQ0LIkBAyAjObQw1bW5s/ep1azhm6kYujMP/lLl4BjR994A4sX7zsFP8L57G3Kkz6zOG2 VupJmNejZ53X6XIrPNr5Aebvfbj62ulHJM4MCSFDQsiQEDIkhAwJIcNd9pZKpXWvU7Vab1Mkfqaj Vb/n9hiL3oV5/1QVd/BOvQX+ITYLBvC4AnyAr97Cm6eN0oZb4kH4EvwnYeb5Rd11ch6QEDIkhAwJ IUNCyAjMbMppe7qTAznJnc8Hb6L8uZeH8KOwLf/xCR/vKWC8KowD/FjF+pc/4x1EM5t/4+Etp+k3 FGqGkCEhZEgIGRJChoSQkTYz77y+f46/A0xPD1+HDdk93KHl7WUlVXEandcKUr/CvDAW/p1Q5Ouk EZxEM4QMCSFDQsiQEDIkhIyke3vPlDAX46vguvANbc0y3n/au+/cA2JmYVcafiCHpvGlupkRfE1G kImGvRrtohlChoSQISFkSAgZEkKGhJBBu+ytlv+AD3zslvp+Qvl+JfoU5XfLuS+8GgOpNDxFN7Nj b6G8rz9YQnnYqLd3W3ICmiFkSAgZEkKGhJAhIWTQrrI+2jiAZ/+Xlw/839FoH+fZBoO/JPbx0hw+ 9Daw2eOX0L295xoJIUNCyJAQMiSEjH8AXiPOHbAJgiYAAAAASUVORK5CYII= --nextPart3762459.HDmZFN3AqE Content-Type: audio/unknown; name="sound" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="sound" iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz AAABuwAAAbsBOuzj4gAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAFCSURB VDiNnZI9btwwEEbfDH9EuVlXPoqbrdP4CjlBOpc5kGsXRq7gJqUbX4NaBLDEn6WLQIQUOIiz0w04 8/CB86S1xiX1/XF+UAH7/PwzAof/2J2Ox9vr01v7qgI2xni4u/uCiFBrJedMzplaKwDee5ZlYZ5n Sim8vLweAE5vjRWAiABgjEFVUVVqrTjnKKXQWsNai6oSY2QFiIDNOe/yiQjeewDO5zMigqr2t3X+ NDcEsCEMtNZ6im2pKtZavPd9MYRhn2Ach+np6cenP3Ech2kLkEvPeHMfm4hgL9oGfi0AbQ/4pBPT 8Xh7vTY7wOoEwLIspJRwzpFSYp5nUkrdg78B+jVCCHjvKaUAvx3x3ncPPgT86YSqdrmMMTsP+sy2 WZ3YljGGYRhwzqGq3YMPE4xj+KcT4ximbX+xB1ff4gPAOzDpl8jvlpTvAAAAAElFTkSuQmCC --nextPart3762459.HDmZFN3AqE-- libkolab-1.0.2/tests/testfiles/v2/contacts/displayname.vcf000066400000000000000000000001761262531616600236240ustar00rootroot00000000000000BEGIN:VCARD CLASS:PUBLIC FN:Displayname N:Lastname;Firstname;;; NAME:Firstname Lastname UID:sWDhiG62Ea VERSION:3.0 END:VCARD libkolab-1.0.2/tests/testfiles/v2/contacts/displayname.vcf.mime000066400000000000000000000022461262531616600245520ustar00rootroot00000000000000Date: Tue, 01 Sep 2009 09:15:59 +0200 X-Kolab-Type: application/x-vnd.kolab.contact User-Agent: Libkolab-3.0.0 Content-Type: multipart/mixed; boundary="nextPart1671573.1jqa7tTDaI" Subject: sWDhiG62Ea MIME-Version: 1.0 --nextPart1671573.1jqa7tTDaI Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart1671573.1jqa7tTDaI Content-Type: application/x-vnd.kolab.contact; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" KAddressBook 3.3, Kolab resource sWDhiG62Ea dummydate public Firstname Lastname Displayname home --nextPart1671573.1jqa7tTDaI-- libkolab-1.0.2/tests/testfiles/v2/contacts/distlistWithUID.xml000066400000000000000000000013751262531616600243770ustar00rootroot00000000000000 ebb1774429a2e03afafb31f233e23b42 2010-11-25T18:02:32Z 2011-07-23T09:06:38Z public Horde::Kolab Another lista Another User other@debian-vm.local a2cfdc52365ef429042413bf7717dc85 Sample A. User Jr. sample@debian-vm.local f538c7e9ad5a63e4452b7db3bc291231 libkolab-1.0.2/tests/testfiles/v2/contacts/emails.vcf000066400000000000000000000003121262531616600225600ustar00rootroot00000000000000BEGIN:VCARD CLASS:PUBLIC EMAIL;TYPE=PREF:first@email.org EMAIL:second@email.org EMAIL:third@email.org FN:Email Addresses N:Addresses;Email;;; NAME:Email Addresses UID:zj77MLHTiw VERSION:3.0 END:VCARD libkolab-1.0.2/tests/testfiles/v2/contacts/emails.vcf.mime000066400000000000000000000030431262531616600235120ustar00rootroot00000000000000Date: Tue, 01 Sep 2009 13:13:40 +0200 X-Kolab-Type: application/x-vnd.kolab.contact User-Agent: Libkolab-3.0.0 Content-Type: multipart/mixed; boundary="nextPart2497845.VQRhqsHbKY" Subject: zj77MLHTiw From: Email Addresses MIME-Version: 1.0 --nextPart2497845.VQRhqsHbKY Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart2497845.VQRhqsHbKY Content-Type: application/x-vnd.kolab.contact; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" KAddressBook 3.3, Kolab resource zj77MLHTiw dummydate public Email Addresses Email Addresses Email Addresses first@email.org Email Addresses second@email.org Email Addresses third@email.org home --nextPart2497845.VQRhqsHbKY-- libkolab-1.0.2/tests/testfiles/v2/contacts/iso8859-1.mime000066400000000000000000000042751262531616600227610ustar00rootroot00000000000000From: Johnny Test Organization: Kolab Systems Subject: UID Date: Wed, 1 Apr 2012 16:16:14 +0200 User-Agent: KMail/1.13.6 (Linux/2.6.35.12-88.fc14.x86_64; KDE/4.5.5; x86_64; ; ) MIME-Version: 1.0 X-Kolab-Type: application/x-vnd.kolab.contact Content-Type: Multipart/Mixed; boundary="Boundary-00=_uAbpNCARn9odR01" Status: RO X-Status: OT X-KMail-EncryptionState: X-KMail-SignatureState: X-KMail-MDN-Sent: X-UID: 0 --Boundary-00=_uAbpNCARn9odR01 Content-Type: Text/Plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable Content-Disposition: Dies ist ein Kolab Groupware-Objekt. Um dieses Objekt anzeigen zu k=F6nnen, brauchen Sie ein E-Mail Programm, da= s das Kolab Groupware-Format versteht. Eine Liste solcher E-Mail-Programme finden Sie hier: http://www.kolab.org/kolab2-clients.html =2D---------------------------------------------------- This is a Kolab Groupware object. To view this object you will need an email client that can understand the K= olab Groupware format. =46or a list of such email clients please visit http://www.kolab.org/kolab2-clients.html --Boundary-00=_uAbpNCARn9odR01 Content-Type: application/x-vnd.kolab.contact; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" KAddressBook 3.3, Kolab resource UID public John Doe John Doe org webpage.com f=C3=BCr test business1 00000000 businessfax +000000 John Doe doe@kolab.org
home 16 strasse locality 23424 country
home
--Boundary-00=_uAbpNCARn9odR01--libkolab-1.0.2/tests/testfiles/v2/contacts/phonenumbers.vcf000066400000000000000000000003121262531616600240130ustar00rootroot00000000000000BEGIN:VCARD CLASS:PUBLIC FN:Phone Caller N:Caller;Phone;;; NAME:Phone Caller TEL;TYPE=HOME:+4930-homephone TEL;TYPE=WORK:+4930-workphone TEL;TYPE=CELL:+4930-mobile UID:DskcKTX5C5 VERSION:3.0 END:VCARD libkolab-1.0.2/tests/testfiles/v2/contacts/phonenumbers.vcf.mime000066400000000000000000000026041262531616600247470ustar00rootroot00000000000000Date: Tue, 01 Sep 2009 10:20:52 +0200 X-Kolab-Type: application/x-vnd.kolab.contact User-Agent: Libkolab-3.0.0 Content-Type: multipart/mixed; boundary="nextPart5288440.YZXQeyvXcV" Subject: DskcKTX5C5 MIME-Version: 1.0 --nextPart5288440.YZXQeyvXcV Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart5288440.YZXQeyvXcV Content-Type: application/x-vnd.kolab.contact; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" KAddressBook 3.3, Kolab resource DskcKTX5C5 dummydate public Phone Caller Phone Caller home2 +4930-homephone mobile +4930-mobile business2 +4930-workphone home --nextPart5288440.YZXQeyvXcV-- libkolab-1.0.2/tests/testfiles/v2/contacts/picture.vcf000066400000000000000000000043721262531616600227730ustar00rootroot00000000000000BEGIN:VCARD CLASS:PUBLIC FN:Akonadi Logo N:Logo;Akonadi;;; NAME:Akonadi Logo PHOTO;ENCODING=b;TYPE=image/png:iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pV UAAAACXBIWXMAAA5NAAAOnAHe9pxXAAAFsklEQVR4nO2dy2tcdRTHz7znJvO4uZlpJ0mbpJVOao KhJG18LargAzdupCguRBBcuBFXuhBLEUVc69aVggSEQgUpVPBVU43tQkmtbWKb1ySZTCbpncedz NyH/8D3CAmtnsX5LL+/+7vnN/OdHxzO7zFEiqIoiqIoyr0n9F8EGT0zHUf6qYcHXuX6JIzki0h3 arujSLfLDfhZtpbtP7kYW6vVaaR3ys3PkD4//+Yu9657Rfh+B1D2hhoiDDVEGGqIMNQQYaghwth X2nv6k5UTSE947tdIHx1ws0gfLPakuBhBBP9WWjWcedqlOtQr81UuBC3PbUJ99ead6zCGXXoev+ eDBTbIHtEZIgw1RBhqiDDUEGGoIcKIcg2TZ3/r4toORstfIT13IDOA9OJUP3yPmYU1RyIiiodxA lh1XKgnjBjUYyE+kYx4AdTDbgcWMFcX7G+R7h1/Z5KLUbrx0RY7ABR7Lw8r9x81RBhqiDDUEGGo IcJgs6zxifzrXJvlO0eR7nXhTCfShbMpk6lXERElmCbPwEPumEmouzmDjdEpdEPd2Tbx8438ENI Dv/k+F6NE9AY7AIDOEGGoIcJQQ4ShhghDDREGm2XluqJwoxoRUT6Zgfr1FVy2cX1Y4qK6zw+sw+ htpg9XsYrGImwMrv7VnU5APW3iBc6mnXiFi/HAS998ivSFL5+bQ7rOEGGoIcJQQ4ShhghDDRGGG iKM6NHXfngcNbjbzZNcJ78bp4uDPXjVd2PdxsH7cfpMRMTVHd22B3WvhZd2gw5+noiIfGYJN4KT 6HgcD6o7beAqJRF5zeY1pJ986+dnYGzuRcr/gxoiDDVEGGqIMNQQYURjVuoR1FDdaLCFx1gMZyH Hxg9A/dYSLjpWcZJDRERpJpPzmSzLZY4pdOw2G6PdxCVMt4X7BD7zrn/ZjOfWa3D9ur1beBTpOk OEoYYIQw0RhhoiDDVEGFHDjC+ihmuX/2A7FSJ4ibNRx1nI2ATOvmavLLExhoctqCeYOlOHie1UH TZGbRMfFG3aO1BvtfDz9UaLjWHE8LjqlILfu84QYaghwlBDhKGGCEMNEUZo/OxlmAJF6t4q16kx +zusc/VkeuDz1gDe3p/NsedKyW7gmtXQIXhLBwUdvIOutlXjY1Rwja1eq0DdcRpQNwo5NkbTGoE f5K6dOIx0nSHCUEOEoYYIQw0RhhoiDDVEGOza4+R7P33BtbVvrr2MdH8FFwsfe3Ic6oeHe9mBVS o4xVy4hW+I2ynjzXjt5l02RiSBl3CTzB0sxkGcvqeKx9kYy0suvBdm5sOpM0jXGSIMNUQYaogw1 BBhqCHCYDfDRUKdt7m2UN56FunuTgWmTRfPf4/f4/MnZCMRZqOcj4uIvoeXURMpPka2D2dNxpE+ qPdMjEC9ctvBKR4RjQ3GP0b6d3NleIRBZ4gw1BBhqCHCUEOEoYYIg61lBUHAtj3x7qXTSC8vO+e R7m1twnXXTpnfKOfv4uMFPnOIM8zcaZLuxxvuiIgKU0WoZ04cg3pt0Yap3JGYe46L8fSUdRHpuY y5jHSdIcJQQ4ShhghDDRGGGiIMNpOaDgK2CJS8+hfcEXfhx8VTSL/yaxVmIU7Dh88TEYXbeMUwl cblty7mWo+kxd56QV4U18vIbd9G8uhA+HOkP1TMznIxek3rb6SbueQK0nWGCEMNEYYaIgw1RBhq iDDUEGHsq7h44WoJ/gfE9vYaPCixWi7Bm5RnZjee4mLcWai9gPR22zuE9GgUXziSNGIbXIy+oeQ lpD84kv0F6QXTgqlqttdc52JYqRQ8bFLs9uHBFZ0hwlBDhKGGCEMNEYYaIox9/cE9x/Q0U5A8NA P398+vN9hjuCs31mABs1J34GW/YQrgj8vKZNjLTgb7UjDTMfIm7NNnWPhdeWKvrZsbG4MXCp8Lh eCOP50hwlBDhKGGCEMNEYYaIox/ANiJdLNEDyLTAAAAAElFTkSuQmCC UID:DVd76P1FDJ X-KOLAB-PictureAttachmentName:kolab-picture.png VERSION:3.0 END:VCARD libkolab-1.0.2/tests/testfiles/v2/contacts/picture.vcf.mime000066400000000000000000000066231262531616600237220ustar00rootroot00000000000000Date: Tue, 01 Sep 2009 09:50:04 +0200 X-Kolab-Type: application/x-vnd.kolab.contact User-Agent: Libkolab-3.0.0 Content-Type: multipart/mixed; boundary="nextPart3467792.lKc2nMLyO8" Subject: DVd76P1FDJ MIME-Version: 1.0 --nextPart3467792.lKc2nMLyO8 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart3467792.lKc2nMLyO8 Content-Type: application/x-vnd.kolab.contact; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" KAddressBook 3.3, Kolab resource DVd76P1FDJ dummydate public Akonadi Logo Akonadi Logo kolab-picture.png home --nextPart3467792.lKc2nMLyO8 Content-Type: image/png; name="kolab-picture.png" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="kolab-picture.png" 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 --nextPart3467792.lKc2nMLyO8-- libkolab-1.0.2/tests/testfiles/v2/contacts/pictureJPGHorde.vcf000066400000000000000000000121541262531616600243130ustar00rootroot00000000000000BEGIN:VCARD ADR;TYPE=home:;;the streets;;;; CLASS:PUBLIC EMAIL:email@provider.org FN:Test2 Contact N:Contact;Test2;;; PHOTO;ENCODING=b;TYPE=image/jpeg:/9j/4AAQSkZJRgABAQEASwBLAAD/2wBDAAgGBgcGBQ gHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zN DL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy MjIyMjIyMjIyMjIyMjL/wAARCAB8AHwDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAE CAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0 KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc 3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW 19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQo L/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYn LRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g oOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk 5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDyUClxT8c0Yr6A4huKMU/FGOKQxuKMU/FGKAG baNtPxUkMElxIEiXcdwX2BPTJ7UmMg20ba9N0PwLZQ2+7UkS4mdiu7cQiL7Due+T61rXfwx0W4d Z4ZbiBDndFE4IPoQSDjvXM8XTTsV7OR46qF3VFBZ2OFUDJJ9hVmDStQuVVoLC7lVzhWSBiD+OMV 7dpXh3S/D/nfYLXdvI3OzZf6Ant7V0kKQz2qyGPYHHA67TWM8db4UWqXdnzPcWlxaSmO5glgkHG 2RCp9eh+oqIrX0zqOkW2p2M9reQJKjKynIBPTAIz0I9a+dtX08aZrF5Yq5dYJWRWbGSB0z74xW2 HxCq3VrMicOUzttJipdtJtrpMx+KXFOxS4qgGYpcU/FLigCPFGKkxRtpANj2CRTIpZAQWAOCR3A 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 TEL;TYPE=PREF;TYPE=WORK:9823749824982 UID:75ae7000a6337db6435ebfa405084990 VERSION:3.0 X-KOLAB-CreationDate:2012-04-25T23:07:06Z X-KOLAB-PictureAttachmentName:photo.attachment END:VCARD libkolab-1.0.2/tests/testfiles/v2/contacts/pictureJPGHorde.vcf.mime000066400000000000000000000152121262531616600252370ustar00rootroot00000000000000From: mollekopf@kolabsys.com To: mollekopf@kolabsys.com Date: Thu, 26 Apr 2012 01:51:52 +0200 X-Kolab-Type: application/x-vnd.kolab.contact Subject: 75ae7000a6337db6435ebfa405084990 User-Agent: Horde::Kolab::Storage v0.2 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=_9g56sz0u5wuy" Content-Transfer-Encoding: 7bit This message is in MIME format. --=_9g56sz0u5wuy Content-Type: text/plain; charset=UTF-8 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable This is a Kolab Groupware object. To view this object you will need an emai= l client that understands the Kolab Groupware format. For a list of such emai= l clients please visit http://www.kolab.org/kolab2-clients.html --=_9g56sz0u5wuy Content-Type: image/jpeg; name="photo.attachment" Content-Disposition: attachment; filename="photo.attachment" Content-Transfer-Encoding: base64 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 --=_9g56sz0u5wuy Content-Type: application/x-vnd.kolab.contact; name="kolab.xml" Content-Disposition: attachment; filename="kolab.xml" Content-Transfer-Encoding: quoted-printable 75ae7000a6337db6435ebfa405084990 2012-04-25T23:07:06Z 2012-04-25T23:51:52Z public Horde::Kolab Test2 Contact Test2 Contact photo.attachment
home the streets
Test2 Contact email@provider.org business1 9823749824982
--=_9g56sz0u5wuy-- libkolab-1.0.2/tests/testfiles/v2/contacts/simple.vcf000066400000000000000000000002141262531616600226000ustar00rootroot00000000000000BEGIN:VCARD CLASS:PUBLIC EMAIL:vkrause@kde.org FN:Volker Krause N:Krause;Volker;;; NAME:Volker Krause UID:4xuyC0cyjV VERSION:3.0 END:VCARD libkolab-1.0.2/tests/testfiles/v2/contacts/simple.vcf.mime000066400000000000000000000024671262531616600235420ustar00rootroot00000000000000Date: Mon, 31 Aug 2009 14:39:35 +0200 X-Kolab-Type: application/x-vnd.kolab.contact User-Agent: Libkolab-3.0.0 Content-Type: multipart/mixed; boundary="nextPart8293045.ykzvriC3IH" Subject: 4xuyC0cyjV From: Volker Krause MIME-Version: 1.0 --nextPart8293045.ykzvriC3IH Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart8293045.ykzvriC3IH Content-Type: application/x-vnd.kolab.contact; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" KAddressBook 3.3, Kolab resource 4xuyC0cyjV dummydate public Volker Krause Volker Krause Volker Krause vkrause@kde.org home --nextPart8293045.ykzvriC3IH-- libkolab-1.0.2/tests/testfiles/v2/event/000077500000000000000000000000001262531616600201155ustar00rootroot00000000000000libkolab-1.0.2/tests/testfiles/v2/event/allday.ics000066400000000000000000000005061262531616600220640ustar00rootroot00000000000000BEGIN:VCALENDAR PRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN VERSION:2.0 BEGIN:VEVENT DTSTAMP:20090901T131514Z CREATED:20090901T131514Z UID:KOrganizer-1256760206.500 LAST-MODIFIED:20090901T131514Z SUMMARY:All Day Event DTSTART;VALUE=DATE:20090902 DTEND;VALUE=DATE:20090903 TRANSP:OPAQUE END:VEVENT END:VCALENDAR libkolab-1.0.2/tests/testfiles/v2/event/allday.ics.mime000066400000000000000000000023501262531616600230110ustar00rootroot00000000000000Date: Tue, 01 Sep 2009 15:15:20 +0200 X-Kolab-Type: application/x-vnd.kolab.event User-Agent: Libkolab-3.0.0 Content-Type: multipart/mixed; boundary="nextPart2050770.69HWcxcYtE" Subject: KOrganizer-1256760206.500 MIME-Version: 1.0 --nextPart2050770.69HWcxcYtE Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart2050770.69HWcxcYtE Content-Type: application/x-vnd.kolab.event; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" Libkolab-0.1.0, Kolab resource KOrganizer-1256760206.500 2009-09-01T13:15:14Z 2009-09-01T13:15:14Z public 2009-09-02 All Day Event busy 2009-09-02 --nextPart2050770.69HWcxcYtE-- libkolab-1.0.2/tests/testfiles/v2/event/attachment.ics000066400000000000000000000032701262531616600227470ustar00rootroot00000000000000BEGIN:VCALENDAR PRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN VERSION:2.0 BEGIN:VEVENT DTSTAMP:20090901T125843Z CREATED:20090901T125843Z UID:KOrganizer-1181687251.384 LAST-MODIFIED:20090901T125843Z SUMMARY:Attachment Event ATTACH;VALUE=BINARY;FMTTYPE=image/png;ENCODING=BASE64;X-LABEL=AkonadiIcon: iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP 8A/wD/oL2nkwAAAAlwSFlzAAAbrwAAG68BXhqRHAAAAAd0SU1FB9gFEQkdFPibCIYAAAMrSURB VDjLpZNLaBx1AMZ/M/P/78zOzO7ObDbvNUnTxsUUm6YmaulNxN70UKEIRTyIBy8KHrypRUTw4E k8CqKnXuyhHgQRFTRNAvVFbOnDNO/EfWZmdmczszPrwcdBvPnBd/ng98F3+OB/Svl3cPbSx5mZ +ZkXjKx+setHs4cHbaW+7d2s79SvhK29j+6vvXH0nwVPfLh1WsTptdnxuDDxoGv3NZWuf4S3G1 C722BrrcrOnY1f/ebO05s337n3N6cBLLy1bI7njr4uD4nJhx4by5SGLQYcAzWnI6SGVFUkQKwM RqH/jGHNfXJYXwoBBMDc/MhLThpOJ6ZEMzM4moquQpIVxI5Br5QlHrEImw5xuzRJ0n4beBlABR gwxcXhUp5Ww6OXQvCXo/TPjUJq6FmJldPJOTZ2znj++HOfnwQQ0y9+e67X6iykpmTCNTnY9xBj eTQVelFC0u3RjxNI+6iaQiajYtmGlXa6NxZe/f4pobv24/X9thBSYebUEHc26zT6kLMkaZTQ84 +IvYioE9PrRvTTCBSF2PczUTxyVuiOsXHju58Y0XTaQcTJM0OsXt9kaqqIrinEQUTYCPGrAR2v RbcbELS7ZGWEj72hzL+5MqS0uzvBys/CzbsUxx0KJROvnTBZLtCPU/y6j1erE/g1wrBNdqREWK wktdB4QP3h8qO/K6Z2RR8bJmjtUx7KMDtd4MSozuatXX5Zus3tH29Rre7S18GtjFNanAMpr37w 2ti+ABAyeT0eLJ7vtWoDX1z9BiXV0DRJmqakSRfd1iiMOmSPjeKeqVC/H3oPT8r3ZNyzVID3L1 V2nDzPqsPlQ2PiGKoJCQFJ4qPIFH0gh3P6ONlHKlQ3ve6EEb57fl7GSh9DAVjaqmrNRsv97Kv1 xeurjcthkCyqURs7JzBdE6NokQgJSbQ+O65+euqEszo4UPytWMhvCwBUkSqq1jk356xNDUevLK /sPbl+L7jQ8ZLyUaepGE1xMDZhfDlbKSwPFt1tXcp9qWk1VWjhP2e6dneLvhdqLc/L7B3UzfX1 qttsdfKKguo4ZlguO36xWAgLth3mbSsyTatnyFz6B+BnWV0A/UiAAAAAAElFTkSuQmCC DTSTART;TZID=Europe/Berlin:20090902T120000 DTEND;TZID=Europe/Berlin:20090902T130000 TRANSP:OPAQUE END:VEVENT END:VCALENDAR libkolab-1.0.2/tests/testfiles/v2/event/attachment.ics.mime000066400000000000000000000053161262531616600237000ustar00rootroot00000000000000Date: Tue, 01 Sep 2009 14:58:47 +0200 X-Kolab-Type: application/x-vnd.kolab.event User-Agent: Libkolab-3.0.0 Content-Type: multipart/mixed; boundary="nextPart3083467.JSZapPgxdJ" Subject: KOrganizer-1181687251.384 MIME-Version: 1.0 --nextPart3083467.JSZapPgxdJ Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart3083467.JSZapPgxdJ Content-Type: application/x-vnd.kolab.event; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" Libkolab-0.1.0, Kolab resource KOrganizer-1181687251.384 2009-09-01T12:58:43Z 2009-09-01T12:58:43Z public 2009-09-02T10:00:00Z Attachment Event AkonadiIcon busy 2009-09-02T11:00:00Z --nextPart3083467.JSZapPgxdJ Content-Type: image/png; name="AkonadiIcon" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="AkonadiIcon" iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A /wD/oL2nkwAAAAlwSFlzAAAbrwAAG68BXhqRHAAAAAd0SU1FB9gFEQkdFPibCIYAAAMrSURBVDjL pZNLaBx1AMZ/M/P/78zOzO7ObDbvNUnTxsUUm6YmaulNxN70UKEIRTyIBy8KHrypRUTw4Ek8CqKn XuyhHgQRFTRNAvVFbOnDNO/EfWZmdmczszPrwcdBvPnBd/ng98F3+OB/Svl3cPbSx5mZ+ZkXjKx+ setHs4cHbaW+7d2s79SvhK29j+6vvXH0nwVPfLh1WsTptdnxuDDxoGv3NZWuf4S3G1C722BrrcrO nY1f/ebO05s337n3N6cBLLy1bI7njr4uD4nJhx4by5SGLQYcAzWnI6SGVFUkQKwMRqH/jGHNfXJY XwoBBMDc/MhLThpOJ6ZEMzM4moquQpIVxI5Br5QlHrEImw5xuzRJ0n4beBlABRgwxcXhUp5Ww6OX QvCXo/TPjUJq6FmJldPJOTZ2znj++HOfnwQQ0y9+e67X6iykpmTCNTnY9xBjeTQVelFC0u3RjxNI +6iaQiajYtmGlXa6NxZe/f4pobv24/X9thBSYebUEHc26zT6kLMkaZTQ84+IvYioE9PrRvTTCBSF 2PczUTxyVuiOsXHju58Y0XTaQcTJM0OsXt9kaqqIrinEQUTYCPGrAR2vRbcbELS7ZGWEj72hzL+5 MqS0uzvBys/CzbsUxx0KJROvnTBZLtCPU/y6j1erE/g1wrBNdqREWKwktdB4QP3h8qO/K6Z2RR8b JmjtUx7KMDtd4MSozuatXX5Zus3tH29Rre7S18GtjFNanAMpr37w2ti+ABAyeT0eLJ7vtWoDX1z9 BiXV0DRJmqakSRfd1iiMOmSPjeKeqVC/H3oPT8r3ZNyzVID3L1V2nDzPqsPlQ2PiGKoJCQFJ4qPI FH0gh3P6ONlHKlQ3ve6EEb57fl7GSh9DAVjaqmrNRsv97Kv1xeurjcthkCyqURs7JzBdE6NokQgJ SbQ+O65+euqEszo4UPytWMhvCwBUkSqq1jk356xNDUevLK/sPbl+L7jQ8ZLyUaepGE1xMDZhfDlb KSwPFt1tXcp9qWk1VWjhP2e6dneLvhdqLc/L7B3UzfX1qttsdfKKguo4ZlguO36xWAgLth3mbSsy TatnyFz6B+BnWV0A/UiAAAAAAElFTkSuQmCC --nextPart3083467.JSZapPgxdJ-- libkolab-1.0.2/tests/testfiles/v2/event/attachmentUtf8.ics000066400000000000000000000044701262531616600235210ustar00rootroot00000000000000BEGIN:VCALENDAR PRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN VERSION:2.0 BEGIN:VEVENT DTSTAMP:20090901T125258Z ATTENDEE;CN="Attendee1";RSVP=TRUE;PARTSTAT=NEEDS-ACTION; ROLE=REQ-PARTICIPANT:mailto:a1@example.com ATTENDEE;CN="Attendee2";RSVP=TRUE;PARTSTAT=ACCEPTED;ROLE=NON-PARTICIPANT: mailto:a2@example.com ATTENDEE;CN="Attendee3";RSVP=FALSE;PARTSTAT=DECLINED;ROLE=REQ-PARTICIPANT: mailto:a3@example.com CREATED:20090901T125258Z UID:KOrganizer-1687167952.818 LAST-MODIFIED:20090901T125258Z DESCRIPTION:äöü%@$£é¤¼²°€Š�ـأبـ SUMMARY:äöü%@$£é¤¼²°€Š�ـأبـ LOCATION:äöü%@$£é¤¼²°€Š�ـأبـ CLASS:PRIVATE CATEGORIES:Appointment\,Business RRULE:FREQ=WEEKLY;COUNT=10;BYDAY=WE,FR EXDATE;VALUE=DATE:20090904 ATTACH;VALUE=BINARY;FMTTYPE=image/png;ENCODING=BASE64;X-LABEL=äöü%@$£é¤¼²°€Š�ـأبـ: iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP 8A/wD/oL2nkwAAAAlwSFlzAAAbrwAAG68BXhqRHAAAAAd0SU1FB9gFEQkdFPibCIYAAAMrSURB VDjLpZNLaBx1AMZ/M/P/78zOzO7ObDbvNUnTxsUUm6YmaulNxN70UKEIRTyIBy8KHrypRUTw4E k8CqKnXuyhHgQRFTRNAvVFbOnDNO/EfWZmdmczszPrwcdBvPnBd/ng98F3+OB/Svl3cPbSx5mZ +ZkXjKx+setHs4cHbaW+7d2s79SvhK29j+6vvXH0nwVPfLh1WsTptdnxuDDxoGv3NZWuf4S3G1 C722BrrcrOnY1f/ebO05s337n3N6cBLLy1bI7njr4uD4nJhx4by5SGLQYcAzWnI6SGVFUkQKwM RqH/jGHNfXJYXwoBBMDc/MhLThpOJ6ZEMzM4moquQpIVxI5Br5QlHrEImw5xuzRJ0n4beBlABR gwxcXhUp5Ww6OXQvCXo/TPjUJq6FmJldPJOTZ2znj++HOfnwQQ0y9+e67X6iykpmTCNTnY9xBj eTQVelFC0u3RjxNI+6iaQiajYtmGlXa6NxZe/f4pobv24/X9thBSYebUEHc26zT6kLMkaZTQ84 +IvYioE9PrRvTTCBSF2PczUTxyVuiOsXHju58Y0XTaQcTJM0OsXt9kaqqIrinEQUTYCPGrAR2v RbcbELS7ZGWEj72hzL+5MqS0uzvBys/CzbsUxx0KJROvnTBZLtCPU/y6j1erE/g1wrBNdqREWK wktdB4QP3h8qO/K6Z2RR8bJmjtUx7KMDtd4MSozuatXX5Zus3tH29Rre7S18GtjFNanAMpr37w 2ti+ABAyeT0eLJ7vtWoDX1z9BiXV0DRJmqakSRfd1iiMOmSPjeKeqVC/H3oPT8r3ZNyzVID3L1 V2nDzPqsPlQ2PiGKoJCQFJ4qPIFH0gh3P6ONlHKlQ3ve6EEb57fl7GSh9DAVjaqmrNRsv97Kv1 xeurjcthkCyqURs7JzBdE6NokQgJSbQ+O65+euqEszo4UPytWMhvCwBUkSqq1jk356xNDUevLK /sPbl+L7jQ8ZLyUaepGE1xMDZhfDlbKSwPFt1tXcp9qWk1VWjhP2e6dneLvhdqLc/L7B3UzfX1 qttsdfKKguo4ZlguO36xWAgLth3mbSsyTatnyFz6B+BnWV0A/UiAAAAAAElFTkSuQmCC DTSTART;TZID=Europe/Berlin:20090902T100000 DTEND;TZID=Europe/Berlin:20090902T110000 TRANSP:TRANSPARENT BEGIN:VALARM DESCRIPTION: ACTION:DISPLAY TRIGGER;VALUE=DURATION:-PT15M END:VALARM END:VEVENT END:VCALENDAR libkolab-1.0.2/tests/testfiles/v2/event/attachmentUtf8.ics.mime000066400000000000000000000107041262531616600244440ustar00rootroot00000000000000Date: Fri, 17 Aug 2012 18:20:48 +0000 X-Kolab-Type: application/x-vnd.kolab.event User-Agent: Libkolab-0.3.1 Content-Type: multipart/mixed; boundary="nextPart5284273.1bMlkVXeYf" Subject: KOrganizer-1687167952.818 MIME-Version: 1.0 --nextPart5284273.1bMlkVXeYf Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart5284273.1bMlkVXeYf Content-Type: application/x-vnd.kolab.event; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" Libkolab-0.3.1, Kolab resource KOrganizer-1687167952.818 =C3=A4=C3=B6=C3=BC%@$=C2=A3=C3=A9=C2=A4=C2=BC=C2=B2=C2=B0=E2=82=AC= =C5=A0=EF=BF=BD=D9=80=D8=A3=D8=A8=D9=80 Appointment,Business 2009-09-01T12:52:58Z 2009-09-01T12:52:58Z private 2009-09-02T08:00:00Z =C3=A4=C3=B6=C3=BC%@$=C2=A3=C3=A9=C2=A4=C2=BC=C2=B2=C2=B0=E2=82= =AC=C5=A0=EF=BF=BD=D9=80=D8=A3=D8=A8=D9=80 =C3=A4=C3=B6=C3=BC%@$=C2=A3=C3=A9=C2=A4=C2=BC=C2=B2=C2=B0=E2= =82=AC=C5=A0=EF=BF=BD=D9=80=D8=A3=D8=A8=D9=80 1 wednesday friday 10 2009-09-04 Attendee1 a1@example.com none true false required Attendee2 a2@example.com accepted true false resource Attendee3 a3@example.com declined false false required =C3=A4=C3=B6=C3=BC%@$=C2=A3=C3=A9=C2=A4=C2=BC=C2=B2= =C2=B0=E2=82=AC=C5=A0=EF=BF=BD=D9=80=D8=A3=D8=A8=D9=80 15 1 -15 free 2009-09-02T09:00:00Z --nextPart5284273.1bMlkVXeYf Content-Type: image/png; name*=utf-8''%C3%A4%C3%B6%C3%BC%25%40$%C2%A3%C3%A9%C2%A4%C2%BC%C2%B2%C2%B0%E2%82%AC%C5%A0%EF%BF%BD%D9%80%D8%A3%D8%A8%D9%80 Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename*=''%C3%A4%C3%B6%C3%BC%25%40$%C2%A3%C3%A9%C2%A4%C2%BC%C2%B2%C2%B0%E2%82%AC%C5%A0%EF%BF%BD%D9%80%D8%A3%D8%A8%D9%80 iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A /wD/oL2nkwAAAAlwSFlzAAAbrwAAG68BXhqRHAAAAAd0SU1FB9gFEQkdFPibCIYAAAMrSURBVDjL pZNLaBx1AMZ/M/P/78zOzO7ObDbvNUnTxsUUm6YmaulNxN70UKEIRTyIBy8KHrypRUTw4Ek8CqKn XuyhHgQRFTRNAvVFbOnDNO/EfWZmdmczszPrwcdBvPnBd/ng98F3+OB/Svl3cPbSx5mZ+ZkXjKx+ setHs4cHbaW+7d2s79SvhK29j+6vvXH0nwVPfLh1WsTptdnxuDDxoGv3NZWuf4S3G1C722BrrcrO nY1f/ebO05s337n3N6cBLLy1bI7njr4uD4nJhx4by5SGLQYcAzWnI6SGVFUkQKwMRqH/jGHNfXJY XwoBBMDc/MhLThpOJ6ZEMzM4moquQpIVxI5Br5QlHrEImw5xuzRJ0n4beBlABRgwxcXhUp5Ww6OX QvCXo/TPjUJq6FmJldPJOTZ2znj++HOfnwQQ0y9+e67X6iykpmTCNTnY9xBjeTQVelFC0u3RjxNI +6iaQiajYtmGlXa6NxZe/f4pobv24/X9thBSYebUEHc26zT6kLMkaZTQ84+IvYioE9PrRvTTCBSF 2PczUTxyVuiOsXHju58Y0XTaQcTJM0OsXt9kaqqIrinEQUTYCPGrAR2vRbcbELS7ZGWEj72hzL+5 MqS0uzvBys/CzbsUxx0KJROvnTBZLtCPU/y6j1erE/g1wrBNdqREWKwktdB4QP3h8qO/K6Z2RR8b JmjtUx7KMDtd4MSozuatXX5Zus3tH29Rre7S18GtjFNanAMpr37w2ti+ABAyeT0eLJ7vtWoDX1z9 BiXV0DRJmqakSRfd1iiMOmSPjeKeqVC/H3oPT8r3ZNyzVID3L1V2nDzPqsPlQ2PiGKoJCQFJ4qPI FH0gh3P6ONlHKlQ3ve6EEb57fl7GSh9DAVjaqmrNRsv97Kv1xeurjcthkCyqURs7JzBdE6NokQgJ SbQ+O65+euqEszo4UPytWMhvCwBUkSqq1jk356xNDUevLK/sPbl+L7jQ8ZLyUaepGE1xMDZhfDlb KSwPFt1tXcp9qWk1VWjhP2e6dneLvhdqLc/L7B3UzfX1qttsdfKKguo4ZlguO36xWAgLth3mbSsy TatnyFz6B+BnWV0A/UiAAAAAAElFTkSuQmCC --nextPart5284273.1bMlkVXeYf-- libkolab-1.0.2/tests/testfiles/v2/event/complex.ics000066400000000000000000000043311262531616600222650ustar00rootroot00000000000000BEGIN:VCALENDAR PRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN VERSION:2.0 BEGIN:VEVENT DTSTAMP:20090901T125258Z ATTENDEE;CN="Attendee1";RSVP=TRUE;PARTSTAT=NEEDS-ACTION; ROLE=REQ-PARTICIPANT:mailto:a1@example.com ATTENDEE;CN="Attendee2";RSVP=TRUE;PARTSTAT=ACCEPTED;ROLE=NON-PARTICIPANT: mailto:a2@example.com ATTENDEE;CN="Attendee3";RSVP=FALSE;PARTSTAT=DECLINED;ROLE=REQ-PARTICIPANT: mailto:a3@example.com CREATED:20090901T125258Z UID:KOrganizer-1687167952.818 LAST-MODIFIED:20090901T125258Z DESCRIPTION:Some notes on this event. SUMMARY:Complex Event LOCATION:Here CLASS:PRIVATE CATEGORIES:Appointment\,Business RRULE:FREQ=WEEKLY;COUNT=10;BYDAY=WE,FR EXDATE;VALUE=DATE:20090904 ATTACH;VALUE=BINARY;FMTTYPE=image/png;ENCODING=BASE64;X-LABEL=akonadi.png: iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP 8A/wD/oL2nkwAAAAlwSFlzAAAbrwAAG68BXhqRHAAAAAd0SU1FB9gFEQkdFPibCIYAAAMrSURB VDjLpZNLaBx1AMZ/M/P/78zOzO7ObDbvNUnTxsUUm6YmaulNxN70UKEIRTyIBy8KHrypRUTw4E k8CqKnXuyhHgQRFTRNAvVFbOnDNO/EfWZmdmczszPrwcdBvPnBd/ng98F3+OB/Svl3cPbSx5mZ +ZkXjKx+setHs4cHbaW+7d2s79SvhK29j+6vvXH0nwVPfLh1WsTptdnxuDDxoGv3NZWuf4S3G1 C722BrrcrOnY1f/ebO05s337n3N6cBLLy1bI7njr4uD4nJhx4by5SGLQYcAzWnI6SGVFUkQKwM RqH/jGHNfXJYXwoBBMDc/MhLThpOJ6ZEMzM4moquQpIVxI5Br5QlHrEImw5xuzRJ0n4beBlABR gwxcXhUp5Ww6OXQvCXo/TPjUJq6FmJldPJOTZ2znj++HOfnwQQ0y9+e67X6iykpmTCNTnY9xBj eTQVelFC0u3RjxNI+6iaQiajYtmGlXa6NxZe/f4pobv24/X9thBSYebUEHc26zT6kLMkaZTQ84 +IvYioE9PrRvTTCBSF2PczUTxyVuiOsXHju58Y0XTaQcTJM0OsXt9kaqqIrinEQUTYCPGrAR2v RbcbELS7ZGWEj72hzL+5MqS0uzvBys/CzbsUxx0KJROvnTBZLtCPU/y6j1erE/g1wrBNdqREWK wktdB4QP3h8qO/K6Z2RR8bJmjtUx7KMDtd4MSozuatXX5Zus3tH29Rre7S18GtjFNanAMpr37w 2ti+ABAyeT0eLJ7vtWoDX1z9BiXV0DRJmqakSRfd1iiMOmSPjeKeqVC/H3oPT8r3ZNyzVID3L1 V2nDzPqsPlQ2PiGKoJCQFJ4qPIFH0gh3P6ONlHKlQ3ve6EEb57fl7GSh9DAVjaqmrNRsv97Kv1 xeurjcthkCyqURs7JzBdE6NokQgJSbQ+O65+euqEszo4UPytWMhvCwBUkSqq1jk356xNDUevLK /sPbl+L7jQ8ZLyUaepGE1xMDZhfDlbKSwPFt1tXcp9qWk1VWjhP2e6dneLvhdqLc/L7B3UzfX1 qttsdfKKguo4ZlguO36xWAgLth3mbSsyTatnyFz6B+BnWV0A/UiAAAAAAElFTkSuQmCC DTSTART;TZID=Europe/Berlin:20090902T100000 DTEND;TZID=Europe/Berlin:20090902T110000 TRANSP:TRANSPARENT BEGIN:VALARM DESCRIPTION: ACTION:DISPLAY TRIGGER;VALUE=DURATION:-PT15M END:VALARM END:VEVENT END:VCALENDAR libkolab-1.0.2/tests/testfiles/v2/event/complex.ics.mime000066400000000000000000000076021262531616600232170ustar00rootroot00000000000000Date: Tue, 01 Sep 2009 14:53:03 +0200 X-Kolab-Type: application/x-vnd.kolab.event User-Agent: Libkolab-3.0.0 Content-Type: multipart/mixed; boundary="nextPart1532650.N5Q3PfLWqK" Subject: KOrganizer-1687167952.818 MIME-Version: 1.0 --nextPart1532650.N5Q3PfLWqK Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart1532650.N5Q3PfLWqK Content-Type: application/x-vnd.kolab.event; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" Libkolab-0.1.0, Kolab resource KOrganizer-1687167952.818 Some notes on this event. Appointment,Business 2009-09-01T12:52:58Z 2009-09-01T12:52:58Z private 2009-09-02T08:00:00Z Complex Event Here 1 wednesday friday 10 2009-09-04 Attendee1 a1@example.com none true false required Attendee2 a2@example.com accepted true false resource Attendee3 a3@example.com declined false false required akonadi.png 15 1 -15 free 2009-09-02T09:00:00Z --nextPart1532650.N5Q3PfLWqK Content-Type: image/png; name="akonadi.png" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="akonadi.png" iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A /wD/oL2nkwAAAAlwSFlzAAAbrwAAG68BXhqRHAAAAAd0SU1FB9gFEQkdFPibCIYAAAMrSURBVDjL pZNLaBx1AMZ/M/P/78zOzO7ObDbvNUnTxsUUm6YmaulNxN70UKEIRTyIBy8KHrypRUTw4Ek8CqKn XuyhHgQRFTRNAvVFbOnDNO/EfWZmdmczszPrwcdBvPnBd/ng98F3+OB/Svl3cPbSx5mZ+ZkXjKx+ setHs4cHbaW+7d2s79SvhK29j+6vvXH0nwVPfLh1WsTptdnxuDDxoGv3NZWuf4S3G1C722BrrcrO nY1f/ebO05s337n3N6cBLLy1bI7njr4uD4nJhx4by5SGLQYcAzWnI6SGVFUkQKwMRqH/jGHNfXJY XwoBBMDc/MhLThpOJ6ZEMzM4moquQpIVxI5Br5QlHrEImw5xuzRJ0n4beBlABRgwxcXhUp5Ww6OX QvCXo/TPjUJq6FmJldPJOTZ2znj++HOfnwQQ0y9+e67X6iykpmTCNTnY9xBjeTQVelFC0u3RjxNI +6iaQiajYtmGlXa6NxZe/f4pobv24/X9thBSYebUEHc26zT6kLMkaZTQ84+IvYioE9PrRvTTCBSF 2PczUTxyVuiOsXHju58Y0XTaQcTJM0OsXt9kaqqIrinEQUTYCPGrAR2vRbcbELS7ZGWEj72hzL+5 MqS0uzvBys/CzbsUxx0KJROvnTBZLtCPU/y6j1erE/g1wrBNdqREWKwktdB4QP3h8qO/K6Z2RR8b JmjtUx7KMDtd4MSozuatXX5Zus3tH29Rre7S18GtjFNanAMpr37w2ti+ABAyeT0eLJ7vtWoDX1z9 BiXV0DRJmqakSRfd1iiMOmSPjeKeqVC/H3oPT8r3ZNyzVID3L1V2nDzPqsPlQ2PiGKoJCQFJ4qPI FH0gh3P6ONlHKlQ3ve6EEb57fl7GSh9DAVjaqmrNRsv97Kv1xeurjcthkCyqURs7JzBdE6NokQgJ SbQ+O65+euqEszo4UPytWMhvCwBUkSqq1jk356xNDUevLK/sPbl+L7jQ8ZLyUaepGE1xMDZhfDlb KSwPFt1tXcp9qWk1VWjhP2e6dneLvhdqLc/L7B3UzfX1qttsdfKKguo4ZlguO36xWAgLth3mbSsy TatnyFz6B+BnWV0A/UiAAAAAAElFTkSuQmCC --nextPart1532650.N5Q3PfLWqK-- libkolab-1.0.2/tests/testfiles/v2/event/horde.ics000066400000000000000000000005671262531616600217260ustar00rootroot00000000000000BEGIN:VCALENDAR PRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN VERSION:2.0 BEGIN:VEVENT DTSTAMP:20100623T150354Z ORGANIZER;CN="Till Adam":MAILTO:till@kdab.com CREATED:20100623T150354Z UID:c4f13514dafc8dccb61e107758d7c2ba LAST-MODIFIED:20100623T150354Z SUMMARY:jetzt erst recht DTSTART:20100623T040000Z DTEND:20100623T050000Z TRANSP:OPAQUE END:VEVENT END:VCALENDAR libkolab-1.0.2/tests/testfiles/v2/event/horde.ics.mime000066400000000000000000000027531262531616600226530ustar00rootroot00000000000000From: till@kdab.com To: till@kdab.com Date: Wed, 23 Jun 2010 17:03:54 +0200 X-Kolab-Type: application/x-vnd.kolab.event Subject: c4f13514dafc8dccb61e107758d7c2ba User-Agent: Horde::Kolab::Storage v0.2 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=_ncb7q5bbyhm" Content-Transfer-Encoding: 7bit --=_ncb7q5bbyhm Content-Type: text/plain; charset="UTF-8" Content-Disposition: inline Content-Transfer-Encoding: quoted-printable This is a Kolab Groupware object. To view this object you will need an email client that understands the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --=_ncb7q5bbyhm Content-Type: application/x-vnd.kolab.event; name="kolab.xml" Content-Disposition: attachment; filename="kolab.xml" Content-Transfer-Encoding: quoted-printable c4f13514dafc8dccb61e107758d7c2ba 2010-06-23T15:03:54Z 2010-06-23T15:03:54Z public Horde::Kolab jetzt erst recht Till Adam till@kdab.com 2010-06-23T04:00:00Z busy 2010-06-23T05:00:00Z --=_ncb7q5bbyhm-- libkolab-1.0.2/tests/testfiles/v2/event/iso8859-1.mime000066400000000000000000000031571262531616600222620ustar00rootroot00000000000000Date: Tue, 01 Sep 2009 13:36:50 +0200 X-Kolab-Type: application/x-vnd.kolab.event User-Agent: Libkolab-3.0.0 Content-Type: multipart/mixed; boundary="nextPart3915010.RBqxP67orN" Subject: KOrganizer-1353608432.168 MIME-Version: 1.0 --nextPart3915010.RBqxP67orN Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7Bit Dies ist ein Kolab Groupware-Objekt. Um dieses Objekt anzeigen zu k=F6nnen, brauchen Sie ein E-Mail Programm, da= s das Kolab Groupware-Format versteht. Eine Liste solcher E-Mail-Programme finden Sie hier: http://www.kolab.org/kolab2-clients.html =2D---------------------------------------------------- This is a Kolab Groupware object. To view this object you will need an email client that can understand the K= olab Groupware format. =46or a list of such email clients please visit http://www.kolab.org/kolab2-clients.html --nextPart3915010.RBqxP67orN Content-Type: application/x-vnd.kolab.event; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" Libkolab-0.1.0, Kolab resourcef=C3=BCr KOrganizer-1353608432.168 2009-09-01T11:36:44Z 2009-09-01T11:36:44Z public 2009-09-02T06:00:00Z Simplef=C3=BCr Event Heref=C3=BCr busy 2009-09-02T07:00:00Z --nextPart3915010.RBqxP67orN-- libkolab-1.0.2/tests/testfiles/v2/event/simple.ics000066400000000000000000000005601262531616600221070ustar00rootroot00000000000000BEGIN:VCALENDAR PRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN VERSION:2.0 BEGIN:VEVENT DTSTAMP:20090901T113644Z CREATED:20090901T113644Z UID:KOrganizer-1353608432.168 LAST-MODIFIED:20090901T113644Z SUMMARY:Simple Event LOCATION:Here DTSTART;TZID=Europe/Berlin:20090902T080000 DTEND;TZID=Europe/Berlin:20090902T090000 TRANSP:OPAQUE END:VEVENT END:VCALENDAR libkolab-1.0.2/tests/testfiles/v2/event/simple.ics.mime000066400000000000000000000024271262531616600230410ustar00rootroot00000000000000Date: Tue, 01 Sep 2009 13:36:50 +0200 X-Kolab-Type: application/x-vnd.kolab.event User-Agent: Libkolab-3.0.0 Content-Type: multipart/mixed; boundary="nextPart3915010.RBqxP67orN" Subject: KOrganizer-1353608432.168 MIME-Version: 1.0 --nextPart3915010.RBqxP67orN Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart3915010.RBqxP67orN Content-Type: application/x-vnd.kolab.event; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" Libkolab-0.1.0, Kolab resource KOrganizer-1353608432.168 2009-09-01T11:36:44Z 2009-09-01T11:36:44Z public 2009-09-02T06:00:00Z Simple Event Here busy 2009-09-02T07:00:00Z --nextPart3915010.RBqxP67orN-- libkolab-1.0.2/tests/testfiles/v2/event/simple_missingTypeHeader.ics.mime000066400000000000000000000023531262531616600265430ustar00rootroot00000000000000Date: Tue, 01 Sep 2009 13:36:50 +0200 User-Agent: Libkolab-3.0.0 Content-Type: multipart/mixed; boundary="nextPart3915010.RBqxP67orN" Subject: KOrganizer-1353608432.168 MIME-Version: 1.0 --nextPart3915010.RBqxP67orN Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart3915010.RBqxP67orN Content-Type: application/x-vnd.kolab.event; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" Libkolab-0.1.0, Kolab resource KOrganizer-1353608432.168 2009-09-01T11:36:44Z 2009-09-01T11:36:44Z public 2009-09-02T06:00:00Z Simple Event Here busy 2009-09-02T07:00:00Z --nextPart3915010.RBqxP67orN-- libkolab-1.0.2/tests/testfiles/v2/journal/000077500000000000000000000000001262531616600204465ustar00rootroot00000000000000libkolab-1.0.2/tests/testfiles/v2/journal/complex.ics000066400000000000000000000006071262531616600226200ustar00rootroot00000000000000BEGIN:VCALENDAR PRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN VERSION:2.0 BEGIN:VJOURNAL DTSTAMP:20090901T150009Z CREATED:20090901T150009Z UID:KOrganizer-2037616327.585 LAST-MODIFIED:20090901T150009Z DESCRIPTION:Some notes on this journal. SUMMARY:Complex Journal CATEGORIES:Business\,Meeting\,Miscellaneous DTSTART;TZID=Europe/Berlin:20090901T165900 END:VJOURNAL END:VCALENDAR libkolab-1.0.2/tests/testfiles/v2/journal/complex.ics.mime000066400000000000000000000024221262531616600235430ustar00rootroot00000000000000Date: Tue, 01 Sep 2009 17:00:13 +0200 X-Kolab-Type: application/x-vnd.kolab.journal User-Agent: Libkolab-3.0.0 Content-Type: multipart/mixed; boundary="nextPart1324738.3KhudssxDn" Subject: KOrganizer-2037616327.585 MIME-Version: 1.0 --nextPart1324738.3KhudssxDn Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart1324738.3KhudssxDn Content-Type: application/x-vnd.kolab.journal; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" Libkolab-0.1.0, Kolab resource KOrganizer-2037616327.585 Some notes on this journal. Business,Meeting,Miscellaneous 2009-09-01T15:00:09Z 2009-09-01T15:00:09+00:00 public Complex Journal 2009-09-01T14:59:00Z --nextPart1324738.3KhudssxDn-- libkolab-1.0.2/tests/testfiles/v2/journal/simple.ics000066400000000000000000000004701262531616600224400ustar00rootroot00000000000000BEGIN:VCALENDAR PRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN VERSION:2.0 BEGIN:VJOURNAL DTSTAMP:20090901T145756Z CREATED:20090901T145756Z UID:KOrganizer-1941104064.609 LAST-MODIFIED:20090901T145756Z SUMMARY:Simple Journal Entry DTSTART;TZID=Europe/Berlin:20090901T165700 END:VJOURNAL END:VCALENDAR libkolab-1.0.2/tests/testfiles/v2/journal/simple.ics.mime000066400000000000000000000022651262531616600233720ustar00rootroot00000000000000Date: Tue, 01 Sep 2009 16:58:01 +0200 X-Kolab-Type: application/x-vnd.kolab.journal User-Agent: Libkolab-3.0.0 Content-Type: multipart/mixed; boundary="nextPart5948088.KInc4Inoe4" Subject: KOrganizer-1941104064.609 MIME-Version: 1.0 --nextPart5948088.KInc4Inoe4 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart5948088.KInc4Inoe4 Content-Type: application/x-vnd.kolab.journal; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" Libkolab-0.1.0, Kolab resource KOrganizer-1941104064.609 2009-09-01T14:57:56Z 2009-09-01T14:57:56+00:00 public Simple Journal Entry 2009-09-01T14:57:00Z --nextPart5948088.KInc4Inoe4-- libkolab-1.0.2/tests/testfiles/v2/task/000077500000000000000000000000001262531616600177365ustar00rootroot00000000000000libkolab-1.0.2/tests/testfiles/v2/task/complex.ics000066400000000000000000000042471262531616600221140ustar00rootroot00000000000000BEGIN:VCALENDAR PRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN VERSION:2.0 BEGIN:VTODO DTSTAMP:20090901T133915Z ATTENDEE;CN="Attendee1";RSVP=TRUE;PARTSTAT=NEEDS-ACTION; ROLE=REQ-PARTICIPANT:mailto:a1@example.com ATTENDEE;CN="Attendee2";RSVP=TRUE;PARTSTAT=TENTATIVE;ROLE=REQ-PARTICIPANT:mailto: a2@example.com ATTENDEE;CN="Attendee3";RSVP=FALSE;PARTSTAT=ACCEPTED; ROLE=OPT-PARTICIPANT:mailto:a3@example.com CREATED:20090901T133915Z UID:KOrganizer-396756838.184 LAST-MODIFIED:20090901T133915Z DESCRIPTION:Some notes on this task. SUMMARY:Complex Task LOCATION:Here CLASS:PRIVATE PRIORITY:1 CATEGORIES:Business\,Education ATTACH;VALUE=BINARY;FMTTYPE=image/png;ENCODING=BASE64;X-LABEL=akonadi.png: iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP 8A/wD/oL2nkwAAAAlwSFlzAAAbrwAAG68BXhqRHAAAAAd0SU1FB9gFEQkdFPibCIYAAAMrSURB VDjLpZNLaBx1AMZ/M/P/78zOzO7ObDbvNUnTxsUUm6YmaulNxN70UKEIRTyIBy8KHrypRUTw4E k8CqKnXuyhHgQRFTRNAvVFbOnDNO/EfWZmdmczszPrwcdBvPnBd/ng98F3+OB/Svl3cPbSx5mZ +ZkXjKx+setHs4cHbaW+7d2s79SvhK29j+6vvXH0nwVPfLh1WsTptdnxuDDxoGv3NZWuf4S3G1 C722BrrcrOnY1f/ebO05s337n3N6cBLLy1bI7njr4uD4nJhx4by5SGLQYcAzWnI6SGVFUkQKwM RqH/jGHNfXJYXwoBBMDc/MhLThpOJ6ZEMzM4moquQpIVxI5Br5QlHrEImw5xuzRJ0n4beBlABR gwxcXhUp5Ww6OXQvCXo/TPjUJq6FmJldPJOTZ2znj++HOfnwQQ0y9+e67X6iykpmTCNTnY9xBj eTQVelFC0u3RjxNI+6iaQiajYtmGlXa6NxZe/f4pobv24/X9thBSYebUEHc26zT6kLMkaZTQ84 +IvYioE9PrRvTTCBSF2PczUTxyVuiOsXHju58Y0XTaQcTJM0OsXt9kaqqIrinEQUTYCPGrAR2v RbcbELS7ZGWEj72hzL+5MqS0uzvBys/CzbsUxx0KJROvnTBZLtCPU/y6j1erE/g1wrBNdqREWK wktdB4QP3h8qO/K6Z2RR8bJmjtUx7KMDtd4MSozuatXX5Zus3tH29Rre7S18GtjFNanAMpr37w 2ti+ABAyeT0eLJ7vtWoDX1z9BiXV0DRJmqakSRfd1iiMOmSPjeKeqVC/H3oPT8r3ZNyzVID3L1 V2nDzPqsPlQ2PiGKoJCQFJ4qPIFH0gh3P6ONlHKlQ3ve6EEb57fl7GSh9DAVjaqmrNRsv97Kv1 xeurjcthkCyqURs7JzBdE6NokQgJSbQ+O65+euqEszo4UPytWMhvCwBUkSqq1jk356xNDUevLK /sPbl+L7jQ8ZLyUaepGE1xMDZhfDlbKSwPFt1tXcp9qWk1VWjhP2e6dneLvhdqLc/L7B3UzfX1 qttsdfKKguo4ZlguO36xWAgLth3mbSsyTatnyFz6B+BnWV0A/UiAAAAAAElFTkSuQmCC DUE;TZID=Europe/Berlin:20090908T160000 DTSTART;TZID=Europe/Berlin:20090901T160000 PERCENT-COMPLETE:50 BEGIN:VALARM DESCRIPTION: ACTION:DISPLAY TRIGGER;VALUE=DURATION;RELATED=END:-PT15M END:VALARM END:VTODO END:VCALENDAR libkolab-1.0.2/tests/testfiles/v2/task/complex.ics.mime000066400000000000000000000073311262531616600230370ustar00rootroot00000000000000Date: Tue, 01 Sep 2009 15:39:19 +0200 X-Kolab-Type: application/x-vnd.kolab.task User-Agent: Libkolab-3.0.0 Content-Type: multipart/mixed; boundary="nextPart1580071.CkrsaYjaUZ" Subject: KOrganizer-396756838.184 MIME-Version: 1.0 --nextPart1580071.CkrsaYjaUZ Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart1580071.CkrsaYjaUZ Content-Type: application/x-vnd.kolab.task; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" Libkolab-0.1.0, Kolab resource KOrganizer-396756838.184 Some notes on this task. Business,Education 2009-09-01T13:39:15Z 2009-09-01T13:39:15+00:00 private 1 2009-09-01T14:00:00Z Complex Task Here Attendee1 a1@example.com none true false required Attendee2 a2@example.com tentative true false required Attendee3 a3@example.com accepted false false optional akonadi.png 1 -15 50 not-started 2009-09-08T14:00:00Z --nextPart1580071.CkrsaYjaUZ Content-Type: image/png; name="akonadi.png" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="akonadi.png" iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A /wD/oL2nkwAAAAlwSFlzAAAbrwAAG68BXhqRHAAAAAd0SU1FB9gFEQkdFPibCIYAAAMrSURBVDjL pZNLaBx1AMZ/M/P/78zOzO7ObDbvNUnTxsUUm6YmaulNxN70UKEIRTyIBy8KHrypRUTw4Ek8CqKn XuyhHgQRFTRNAvVFbOnDNO/EfWZmdmczszPrwcdBvPnBd/ng98F3+OB/Svl3cPbSx5mZ+ZkXjKx+ setHs4cHbaW+7d2s79SvhK29j+6vvXH0nwVPfLh1WsTptdnxuDDxoGv3NZWuf4S3G1C722BrrcrO nY1f/ebO05s337n3N6cBLLy1bI7njr4uD4nJhx4by5SGLQYcAzWnI6SGVFUkQKwMRqH/jGHNfXJY XwoBBMDc/MhLThpOJ6ZEMzM4moquQpIVxI5Br5QlHrEImw5xuzRJ0n4beBlABRgwxcXhUp5Ww6OX QvCXo/TPjUJq6FmJldPJOTZ2znj++HOfnwQQ0y9+e67X6iykpmTCNTnY9xBjeTQVelFC0u3RjxNI +6iaQiajYtmGlXa6NxZe/f4pobv24/X9thBSYebUEHc26zT6kLMkaZTQ84+IvYioE9PrRvTTCBSF 2PczUTxyVuiOsXHju58Y0XTaQcTJM0OsXt9kaqqIrinEQUTYCPGrAR2vRbcbELS7ZGWEj72hzL+5 MqS0uzvBys/CzbsUxx0KJROvnTBZLtCPU/y6j1erE/g1wrBNdqREWKwktdB4QP3h8qO/K6Z2RR8b JmjtUx7KMDtd4MSozuatXX5Zus3tH29Rre7S18GtjFNanAMpr37w2ti+ABAyeT0eLJ7vtWoDX1z9 BiXV0DRJmqakSRfd1iiMOmSPjeKeqVC/H3oPT8r3ZNyzVID3L1V2nDzPqsPlQ2PiGKoJCQFJ4qPI FH0gh3P6ONlHKlQ3ve6EEb57fl7GSh9DAVjaqmrNRsv97Kv1xeurjcthkCyqURs7JzBdE6NokQgJ SbQ+O65+euqEszo4UPytWMhvCwBUkSqq1jk356xNDUevLK/sPbl+L7jQ8ZLyUaepGE1xMDZhfDlb KSwPFt1tXcp9qWk1VWjhP2e6dneLvhdqLc/L7B3UzfX1qttsdfKKguo4ZlguO36xWAgLth3mbSsy TatnyFz6B+BnWV0A/UiAAAAAAElFTkSuQmCC --nextPart1580071.CkrsaYjaUZ-- libkolab-1.0.2/tests/testfiles/v2/task/prioritytest1.ics000066400000000000000000000004341262531616600233010ustar00rootroot00000000000000BEGIN:VCALENDAR PRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN VERSION:2.0 BEGIN:VTODO DTSTAMP:20090901T131703Z CREATED:20090901T131703Z UID:KOrganizer-2105012348.490 LAST-MODIFIED:20090901T131703Z SUMMARY:Simple Task PERCENT-COMPLETE:0 PRIORITY:8 END:VTODO END:VCALENDAR libkolab-1.0.2/tests/testfiles/v2/task/prioritytest1.ics.mime000066400000000000000000000023161262531616600242300ustar00rootroot00000000000000Date: Tue, 01 Sep 2009 15:17:09 +0200 X-Kolab-Type: application/x-vnd.kolab.task User-Agent: Libkolab-3.0.0 Content-Type: multipart/mixed; boundary="nextPart1959111.QQxQ0WGgtU" Subject: KOrganizer-2105012348.490 MIME-Version: 1.0 --nextPart1959111.QQxQ0WGgtU Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart1959111.QQxQ0WGgtU Content-Type: application/x-vnd.kolab.task; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" Libkolab-0.1.0, Kolab resource KOrganizer-2105012348.490 2009-09-01T13:17:03Z 2009-09-01T13:17:03+00:00 public 8 Simple Task 0 not-started --nextPart1959111.QQxQ0WGgtU-- libkolab-1.0.2/tests/testfiles/v2/task/prioritytest2.ics000066400000000000000000000004341262531616600233020ustar00rootroot00000000000000BEGIN:VCALENDAR PRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN VERSION:2.0 BEGIN:VTODO DTSTAMP:20090901T131703Z CREATED:20090901T131703Z UID:KOrganizer-2105012348.490 LAST-MODIFIED:20090901T131703Z SUMMARY:Simple Task PERCENT-COMPLETE:0 PRIORITY:1 END:VTODO END:VCALENDAR libkolab-1.0.2/tests/testfiles/v2/task/prioritytest2.ics.mime000066400000000000000000000023161262531616600242310ustar00rootroot00000000000000Date: Tue, 01 Sep 2009 15:17:09 +0200 X-Kolab-Type: application/x-vnd.kolab.task User-Agent: Libkolab-3.0.0 Content-Type: multipart/mixed; boundary="nextPart1959111.QQxQ0WGgtU" Subject: KOrganizer-2105012348.490 MIME-Version: 1.0 --nextPart1959111.QQxQ0WGgtU Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart1959111.QQxQ0WGgtU Content-Type: application/x-vnd.kolab.task; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" Libkolab-0.1.0, Kolab resource KOrganizer-2105012348.490 2009-09-01T13:17:03Z 2009-09-01T13:17:03+00:00 public 1 Simple Task 0 not-started --nextPart1959111.QQxQ0WGgtU-- libkolab-1.0.2/tests/testfiles/v2/task/simple.ics000066400000000000000000000004341262531616600217300ustar00rootroot00000000000000BEGIN:VCALENDAR PRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN VERSION:2.0 BEGIN:VTODO DTSTAMP:20090901T131703Z CREATED:20090901T131703Z UID:KOrganizer-2105012348.490 LAST-MODIFIED:20090901T131703Z SUMMARY:Simple Task PERCENT-COMPLETE:0 PRIORITY:7 END:VTODO END:VCALENDAR libkolab-1.0.2/tests/testfiles/v2/task/simple.ics.mime000066400000000000000000000023161262531616600226570ustar00rootroot00000000000000Date: Tue, 01 Sep 2009 15:17:09 +0200 X-Kolab-Type: application/x-vnd.kolab.task User-Agent: Libkolab-3.0.0 Content-Type: multipart/mixed; boundary="nextPart1959111.QQxQ0WGgtU" Subject: KOrganizer-2105012348.490 MIME-Version: 1.0 --nextPart1959111.QQxQ0WGgtU Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart1959111.QQxQ0WGgtU Content-Type: application/x-vnd.kolab.task; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" Libkolab-0.1.0, Kolab resource KOrganizer-2105012348.490 2009-09-01T13:17:03Z 2009-09-01T13:17:03+00:00 public 7 Simple Task 0 not-started --nextPart1959111.QQxQ0WGgtU-- libkolab-1.0.2/tests/testfiles/v3/000077500000000000000000000000001262531616600167755ustar00rootroot00000000000000libkolab-1.0.2/tests/testfiles/v3/contacts/000077500000000000000000000000001262531616600206135ustar00rootroot00000000000000libkolab-1.0.2/tests/testfiles/v3/contacts/complex.vcf000066400000000000000000000113741262531616600227700ustar00rootroot00000000000000BEGIN:VCARD CLASS:PUBLIC ADR;TYPE=home:;;Home Street;Home Locality;Home Region;H ome Postal Code;Gabon ADR;TYPE=work:;;Work Street;Work Locality;Work Region;Work Posta l Code;Azerbaijan BDAY:2009-07-27T00:00:00 EMAIL;TYPE=PREF:first@email.org EMAIL:second@email.org FN:Displayname LOGO;ENCODING=b;TYPE=png:iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAABH NCSVQICAgIfAhkiAAAAAlwSFlzAAAOTQAADpwB3vacVwAABBlJREFUeJztnc1rY1UYxt+bmzTpB 2O/sNO0dtoMRdKCgkWmOLjpH6CuHCiCGykudD0MDEKZhQjqVtQKIl27cKULF7pwaOvAKAgzgi2S 2lSsdCYfnaTtzXVfnvfaDJg+xee3fE5P3kN+OXB6cu6JmRBCCCGEEEIIIYQQQjwGgZmNOG1PdXI g/0N2UJjq9ChEMhJChoSQISFkSAgZaTMbRw1xHK8l9JPI09NCYSaTeRHlemPJkBAyJIQMCSFDQs hIJ7S5slZWPoN5sViE+aVLk+2M6V8InDiEcbj9jvtKYRDB/HBsGXeIndoWuzXy+VH4PqbT+K3XD CFDQsiQEDIkhAwJIcNdZUUR3IIxM7OFhQWY5/N5mJfLuzCPY3914uKsplIPv4H5hT48JjOzVHYM 5seV72DeyF6FeRzj1ZqZWRT5bXBMbf21+M+REDIkhAwJIUNCyJAQMtxlb61Wczs1m4cwX11dhfl UoQDz0dGks3jORt7RnzAebnwL88zF190K3qq7Zw+/VsVmYR7F3W6NWv2R24bQDCFDQsiQEDIkhA wJIcNdZVUqFbdTs9mE+ZX5F2A+MQBP3tv+75+4NbpzeJWVy+IhZydfgXkYb7k1wuNtXHvwCZhnD r6CebXR69Y4LPfD/M1Xx+Gup2YIGRJChoSQISFkSAgZCV/hHrmd1tZuw3xm9hmY57bfh3lhbtGt kQrw177B8T7u0PreyetuDW+7zGL8Oc32TsA86p10S4RhDuZvX+u/gXLNEDIkhAwJIUNCyJAQMgI zm0MNW1ubP3qdWs4ZupGLozD/5S5eAY0ffeAOLF+87BT/C+extypM+szhtlbqSZjXo2ed1+lyKz za+QHm7324+trpRyTODAkhQ0LIkBAyJIQMCSHDXfaWSqV1r1O1Wm9TJH6mo1W/5/YYi96Fef9UF XfwTr0F/iE2CwbwuAJ8gK/ewpunjdKGW+JB+BL8J2Hm+UXddXIekBAyJIQMCSFDQsgIzGzKaXu6 kwM5yZ3PB2+i/LmXh/CjsC3/8Qkf7ylgvCqMA/xYxfqXP+MdRDObf+PhLafpNxRqhpAhIWRICBk SQoaEkJE2M++8vn+OvwNMTw9fhw3ZPdyh5e1lJVVxGp3XClK/wrwwFv6dUOTrpBGcRDOEDAkhQ0 LIkBAyJISMpHt7z5QwF+Or4LrwDW3NMt5/2rvv3ANiZmFXGn4gh6bxpbqZEXxNRpCJhr0a7aIZQ oaEkCEhZEgIGRJChoSQQbvsrZb/gA987Jb6fkL5fiX6FOV3y7kvvBoDqTQ8RTezY2+hvK8/WEJ5 2Ki3d1tyApohZEgIGRJChoSQISFk0K6yPto4gGf/l5cP/N/RaB/n2QaDvyT28dIcPvQ2sNnjl9C 9vecaCSFDQsiQEDIkhIx/AF4jzh2wCYImAAAAAElFTkSuQmCC N:Lastname;Firstname;;; NAME:Firstname Lastname NICKNAME:Nickname NOTE:Notes ORG:Organization;Department PHOTO;ENCODING=b;TYPE=png:iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAB HNCSVQICAgIfAhkiAAAAAlwSFlzAAAOTQAADpwB3vacVwAABAVJREFUeJztncFrFGcYxt/szLrJ mk2yWTeojQktQluiqNFeKglSQmsOHhRyUApKPbeHQC8taKl4E0Hw4sGToAcvgojVQCg0B+2ph0D prTlYs7SQsNlkdzKzmf4DzxvYsCRP9Pkdn5n53iG/fPDy7TczZkIIIYQQov107PQNtI0vrR/mOf veveap/eAcSXeqRsYdSOwIEkKGhJAhIWRICBkSQsbua3u/slEUj346OoPyUrGEW1Uzm5mfycMDN RtB8ciHIy9RXswXi16NuYU5XOOx1VGsGUKGhJAhIWRICBkSQka40zfgcs6uoHjis4l7KB8fG8+i fPa3Wb9GZJdRPHZq7A7KTx45CWu8/uO1X6NFNEPIkBAyJIQMCSFDQsjYni4rxWtmnVOdsGMyM5s 8PfkNyocPDwcor1QrcJwoiNzbOvvF2bsoL5fKsMZidRGOU7OaW6NVNEPIkBAyJIQMCSFDQshob5 flbCTr/br3BcrPjJ854Q2V78/DTudt9S08P7YY5uXhslfC4jjGNdZwjaSewHwtXHNrtIpmCBkSQ oaEkCEhZEgIGRJCxtba3vN4s1q5NADb2+MfHYMbyRqZBmw7zcxqq3jBLg5xe5tkcEu6buteCUsS fE0cOzUifH4jbLg1WkUzhAwJIUNCyJAQMiSEDL/LumQXvENDhaFHKB/sG4QbyZaiJfgTblLDXYu ZWZzHnc56irum9SzOkw6/RtOaOE9xnjTxWJmwff/XmiFkSAgZEkKGhJAhIWT4XVYQuOtMS7Vl+J 6ON3+/gedv7NvAA5X8G0uL+HUj5j1eCfu7TfLNjjmlzdlz19XEz3VuBc0QMiSEDAkhQ0LIkBAy/ C7rQfOxd2jl6toCygufFJ6jPGlEPSiv5+p+/b1OXnByr/varAHyuinv6QLn/CByG9KW0QwhQ0LI kBAyJIQMCSFDQsjY2ka5+8nvKF6ZXv4Y5YWBnl9R3pfthOebmS1nl/C9dToXOO1wrj/nlbAocVY LvXZ4FcdBs32P2WiGkCEhZEgIGRJChoSQ0d6ncG/bfyheSatHUd71c/dDb6gDuQ+mUL6Y/gNX8t IUt0Z9/7qv7bVKXME74jIbeLXQ+SU6zKjLemeREDIkhAwJIUNCyNieN8p14NWhutUuepdEPzVeo fxQbugWyivVRa/78r8A8Zf9CPOBzA0U70lC+PcK0qBtX5nQDCFDQsiQEDIkhAwJIWP3fYPqevg5 ig8ePPALynu7e72tdfbnk3m8je54eArF+8v7n6G8mOnza7xwaugbVLsDCSFDQsiQEDIkhAwJIWP 3tb0eNw2+MTnoyl7zLmlOx985h/DvwV6Nnk1qfNtaDc0QMiSEDAkhQ0LIkBAhhBBCCPEe8D+b5d DLeP4TXAAAAABJRU5ErkJggg== SOUND;ENCODING=b:iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICA gIfAhkiAAAAAlwSFlzAAABuwAAAbsBOuzj4gAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlL m9yZ5vuPBoAAAFCSURBVDiNnZI9btwwEEbfDH9EuVlXPoqbrdP4CjlBOpc5kGsXRq7gJqUbX4Na BLDEn6WLQIQUOIiz0w048/CB86S1xiX1/XF+UAH7/PwzAof/2J2Ox9vr01v7qgI2xni4u/uCiFB rJedMzplaKwDee5ZlYZ5nSim8vLweAE5vjRWAiABgjEFVUVVqrTjnKKXQWsNai6oSY2QFiIDNOe /yiQjeewDO5zMigqr2t3X+NDcEsCEMtNZ6im2pKtZavPd9MYRhn2Ach+np6cenP3Ech2kLkEvPe HMfm4hgL9oGfi0AbQ/4pBPT8Xh7vTY7wOoEwLIspJRwzpFSYp5nUkrdg78B+jVCCHjvKaUAvx3x 3ncPPgT86YSqdrmMMTsP+sy2WZ3YljGGYRhwzqGq3YMPE4xj+KcT4ximbX+xB1ff4gPAOzDpl8j vlpTvAAAAAElFTkSuQmCC TEL;TYPE=HOME:+4930-homephone TEL;TYPE=WORK:+4930-workphone TEL;TYPE=CELL:+4930-mobile TEL;TYPE=FAX;TYPE=WORK:+4930-fax TITLE:Title UID:Huu5X7hfYy URL:www.homepage.org VERSION:3.0 X-KADDRESSBOOK-BlogFeed:www.blog.test X-KADDRESSBOOK-X-Anniversary:2009-07-28 X-KADDRESSBOOK-X-AssistantsName:Assistant X-KADDRESSBOOK-X-IMAddress:messaging X-KADDRESSBOOK-X-ManagersName:Manager X-KADDRESSBOOK-X-Office:Office X-KADDRESSBOOK-X-Profession:Profession X-KADDRESSBOOK-X-SpousesName:Partner END:VCARD libkolab-1.0.2/tests/testfiles/v3/contacts/complex.vcf.mime000066400000000000000000000174331262531616600237200ustar00rootroot00000000000000Date: Fri, 27 Apr 2012 02:25:38 +0200 X-Kolab-Type: application/x-vnd.kolab.contact X-Kolab-Mime-Version: 3.0 User-Agent: Libkolab-0.2.0 Content-Type: multipart/mixed; boundary="nextPart38186565.1WqI9LYOEs" Subject: Huu5X7hfYy From: Displayname MIME-Version: 1.0 --nextPart38186565.1WqI9LYOEs Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart38186565.1WqI9LYOEs Content-Type: application/vcard+xml; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" urn:uuid:Huu5X7hfYy 3.0dev1 Libkolab-0.2.0 Libkolabxml-0.4.0 20120505T050505Z individual Displayname Lastname Firstname Notes <text>Title</text> Organization Department data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYA= AABw4pVUAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAOTQAADpwB3vacVwAABBlJREFUeJz= tnc1rY1UYxt+bmzTpB2O/sNO0dtoMRdKCgkWmOLjpH6CuHCiCGykudD0MDEKZhQjqVtQKIl= 27cKULF7pwaOvAKAgzgi2S2lSsdCYfnaTtzXVfnvfaDJg+xee3fE5P3kN+OXB6cu6JmRBCC= CGEEEIIIYQQQjwGgZmNOG1PdXIg/0N2UJjq9ChEMhJChoSQISFkSAgZaTMbRw1xHK8l9JPI= 09NCYSaTeRHlemPJkBAyJIQMCSFDQshIJ7S5slZWPoN5sViE+aVLk+2M6V8InDiEcbj9jvt= KYRDB/HBsGXeIndoWuzXy+VH4PqbT+K3XDCFDQsiQEDIkhAwJIcNdZUUR3IIxM7OFhQWY5/= N5mJfLuzCPY3914uKsplIPv4H5hT48JjOzVHYM5seV72DeyF6FeRzj1ZqZWRT5bXBMbf21+= M+REDIkhAwJIUNCyJAQMtxlb61Wczs1m4cwX11dhflUoQDz0dGks3jORt7RnzAebnwL88zF= 190K3qq7Zw+/VsVmYR7F3W6NWv2R24bQDCFDQsiQEDIkhAwJIcNdZVUqFbdTs9mE+ZX5F2A= +MQBP3tv+75+4NbpzeJWVy+IhZydfgXkYb7k1wuNtXHvwCZhnDr6CebXR69Y4LPfD/M1Xx+= Gup2YIGRJChoSQISFkSAgZCV/hHrmd1tZuw3xm9hmY57bfh3lhbtGtkQrw177B8T7u0Prey= etuDW+7zGL8Oc32TsA86p10S4RhDuZvX+u/gXLNEDIkhAwJIUNCyJAQMgIzm0MNW1ubP3qd= Ws4ZupGLozD/5S5eAY0ffeAOLF+87BT/C+extypM+szhtlbqSZjXo2ed1+lyKzza+QHm732= 4+trpRyTODAkhQ0LIkBAyJIQMCSHDXfaWSqV1r1O1Wm9TJH6mo1W/5/YYi96Fef9UFXfwTr= 0F/iE2CwbwuAJ8gK/ewpunjdKGW+JB+BL8J2Hm+UXddXIekBAyJIQMCSFDQsgIzGzKaXu6k= wM5yZ3PB2+i/LmXh/CjsC3/8Qkf7ylgvCqMA/xYxfqXP+MdRDObf+PhLafpNxRqhpAhIWRI= CBkSQoaEkJE2M++8vn+OvwNMTw9fhw3ZPdyh5e1lJVVxGp3XClK/wrwwFv6dUOTrpBGcRDO= EDAkhQ0LIkBAyJISMpHt7z5QwF+Or4LrwDW3NMt5/2rvv3ANiZmFXGn4gh6bxpbqZEXxNRp= CJhr0a7aIZQoaEkCEhZEgIGRJChoSQQbvsrZb/gA987Jb6fkL5fiX6FOV3y7kvvBoDqTQ8R= TezY2+hvK8/WEJ52Ki3d1tyApohZEgIGRJChoSQISFk0K6yPto4gGf/l5cP/N/RaB/n2QaD= vyT28dIcPvQ2sNnjl9C9vecaCSFDQsiQEDIkhIx/AF4jzh2wCYImAAAAAElFTkSuQmCC x-manager Manager x-assistant Assistant work www.homepage.org x-blog www.blog.test home Home Street Home Locality Home Region Home Postal Code Gabon work Work Street Work Locality Work Region Work Postal Code Azerbaijan Nickname spouse Partner 20090727T000000 20090728 data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAA= Bw4pVUAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAOTQAADpwB3vacVwAABAVJREFUeJztn= cFrFGcYxt/szLrJmk2yWTeojQktQluiqNFeKglSQmsOHhRyUApKPbeHQC8taKl4E0Hw4sGT= oAcvgojVQCg0B+2ph0DprTlYs7SQsNlkdzKzmf4DzxvYsCRP9Pkdn5n53iG/fPDy7TczZkI= IIYQQov107PQNtI0vrR/mOfveveap/eAcSXeqRsYdSOwIEkKGhJAhIWRICBkSQsbua3u/sl= EUj346OoPyUrGEW1Uzm5mfycMDNRtB8ciHIy9RXswXi16NuYU5XOOx1VGsGUKGhJAhIWRIC= BkSQka40zfgcs6uoHjis4l7KB8fG8+ifPa3Wb9GZJdRPHZq7A7KTx45CWu8/uO1X6NFNEPI= kBAyJIQMCSFDQsjYni4rxWtmnVOdsGMyM5s8PfkNyocPDwcor1QrcJwoiNzbOvvF2bsoL5f= KsMZidRGOU7OaW6NVNEPIkBAyJIQMCSFDQshob5flbCTr/br3BcrPjJ854Q2V78/DTudt9S= 08P7YY5uXhslfC4jjGNdZwjaSewHwtXHNrtIpmCBkSQoaEkCEhZEgIGRJCxtba3vN4s1q5N= ADb2+MfHYMbyRqZBmw7zcxqq3jBLg5xe5tkcEu6buteCUsSfE0cOzUifH4jbLg1WkUzhAwJ= IUNCyJAQMiSEDL/LumQXvENDhaFHKB/sG4QbyZaiJfgTblLDXYuZWZzHnc56irum9SzOkw6= /RtOaOE9xnjTxWJmwff/XmiFkSAgZEkKGhJAhIWT4XVYQuOtMS7Vl+J6ON3+/gedv7NvAA5= X8G0uL+HUj5j1eCfu7TfLNjjmlzdlz19XEz3VuBc0QMiSEDAkhQ0LIkBAy/C7rQfOxd2jl6= toCygufFJ6jPGlEPSiv5+p+/b1OXnByr/varAHyuinv6QLn/CByG9KW0QwhQ0LIkBAyJIQM= CSFDQsjY2ka5+8nvKF6ZXv4Y5YWBnl9R3pfthOebmS1nl/C9dToXOO1wrj/nlbAocVYLvXZ= 4FcdBs32P2WiGkCEhZEgIGRJChoSQ0d6ncG/bfyheSatHUd71c/dDb6gDuQ+mUL6Y/gNX8t= IUt0Z9/7qv7bVKXME74jIbeLXQ+SU6zKjLemeREDIkhAwJIUNCyNieN8p14NWhutUuepdEP= zVeofxQbugWyivVRa/78r8A8Zf9CPOBzA0U70lC+PcK0qBtX5nQDCFDQsiQEDIkhAwJIWP3= fYPqevg5ig8ePPALynu7e72tdfbnk3m8je54eArF+8v7n6G8mOnza7xwaugbVLsDCSFDQsi= QEDIkhAwJIWP3tb0eNw2+MTnoyl7zLmlOx985h/DvwV6Nnk1qfNtaDc0QMiSEDAkhQ0LIkB= AhhBBCCPEe8D+b5dDLeP4TXAAAAABJRU5ErkJggg=3D=3D home +4930-homephone cell +4930-mobile work +4930-workphone fax work +4930-fax 1 messaging 1 first@email.org second@email.org X-Profession Profession --nextPart38186565.1WqI9LYOEs-- libkolab-1.0.2/tests/testfiles/v3/contacts/distlist.vcf000066400000000000000000000003431262531616600231520ustar00rootroot00000000000000 libkolab-1.0.2/tests/testfiles/v3/contacts/distlist.vcf.mime000066400000000000000000000027121262531616600241020ustar00rootroot00000000000000Date: Mon, 23 Apr 2012 12:46:37 +0200 X-Kolab-Type: application/x-vnd.kolab.distribution-list X-Kolab-Mime-Version: 3.0 User-Agent: Libkolab-0.1.0 Content-Type: multipart/mixed; boundary="nextPart1365947.WmFcbPlLFA" Subject: 4xuyC0cyjV MIME-Version: 1.0 --nextPart1365947.WmFcbPlLFA Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart1365947.WmFcbPlLFA Content-Type: application/vcard+xml; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" urn:uuid:4xuyC0cyjV 3.0dev1 Libkolab-0.1.0 Libkolabxml-0.3.0 20120505T050505Z group My Distlist mailto:John%20Doe%3Cjdoe%40example.com%3E mailto:John%20Doe2%3Cjdoe2%40example.com%3E --nextPart1365947.WmFcbPlLFA-- libkolab-1.0.2/tests/testfiles/v3/contacts/simple.vcf000066400000000000000000000002141262531616600226010ustar00rootroot00000000000000BEGIN:VCARD CLASS:PUBLIC EMAIL:vkrause@kde.org FN:Volker Krause N:Krause;Volker;;; NAME:Volker Krause UID:4xuyC0cyjV VERSION:3.0 END:VCARD libkolab-1.0.2/tests/testfiles/v3/contacts/simple.vcf.mime000066400000000000000000000031401262531616600235300ustar00rootroot00000000000000Date: Mon, 23 Apr 2012 12:46:37 +0200 X-Kolab-Type: application/x-vnd.kolab.contact X-Kolab-Mime-Version: 3.0 User-Agent: Libkolab-0.1.0 Content-Type: multipart/mixed; boundary="nextPart1365947.WmFcbPlLFA" Subject: 4xuyC0cyjV From: Volker Krause MIME-Version: 1.0 --nextPart1365947.WmFcbPlLFA Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart1365947.WmFcbPlLFA Content-Type: application/vcard+xml; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" urn:uuid:4xuyC0cyjV 3.0dev1 Libkolab-0.1.0 Libkolabxml-0.3.0 20120505T050505Z individual Volker Krause Krause Volker 1 vkrause@kde.org --nextPart1365947.WmFcbPlLFA--libkolab-1.0.2/tests/testfiles/v3/event/000077500000000000000000000000001262531616600201165ustar00rootroot00000000000000libkolab-1.0.2/tests/testfiles/v3/event/complex.ics000066400000000000000000000043311262531616600222660ustar00rootroot00000000000000BEGIN:VCALENDAR PRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN VERSION:2.0 BEGIN:VEVENT DTSTAMP:20090901T125258Z ATTENDEE;CN="Attendee1";RSVP=TRUE;PARTSTAT=NEEDS-ACTION; ROLE=REQ-PARTICIPANT:mailto:a1@example.com ATTENDEE;CN="Attendee2";RSVP=TRUE;PARTSTAT=ACCEPTED;ROLE=NON-PARTICIPANT: mailto:a2@example.com ATTENDEE;CN="Attendee3";RSVP=FALSE;PARTSTAT=DECLINED;ROLE=REQ-PARTICIPANT: mailto:a3@example.com CREATED:20090901T125258Z UID:KOrganizer-1687167952.818 LAST-MODIFIED:20120505T050505Z DESCRIPTION:Some notes on this event. SUMMARY:Complex Event LOCATION:Here CLASS:PRIVATE CATEGORIES:Appointment\,Business RRULE:FREQ=WEEKLY;COUNT=10;BYDAY=WE,FR EXDATE;VALUE=DATE:20090904 ATTACH;VALUE=BINARY;FMTTYPE=image/png;ENCODING=BASE64;X-LABEL=akonadi.png: iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP 8A/wD/oL2nkwAAAAlwSFlzAAAbrwAAG68BXhqRHAAAAAd0SU1FB9gFEQkdFPibCIYAAAMrSURB VDjLpZNLaBx1AMZ/M/P/78zOzO7ObDbvNUnTxsUUm6YmaulNxN70UKEIRTyIBy8KHrypRUTw4E k8CqKnXuyhHgQRFTRNAvVFbOnDNO/EfWZmdmczszPrwcdBvPnBd/ng98F3+OB/Svl3cPbSx5mZ +ZkXjKx+setHs4cHbaW+7d2s79SvhK29j+6vvXH0nwVPfLh1WsTptdnxuDDxoGv3NZWuf4S3G1 C722BrrcrOnY1f/ebO05s337n3N6cBLLy1bI7njr4uD4nJhx4by5SGLQYcAzWnI6SGVFUkQKwM RqH/jGHNfXJYXwoBBMDc/MhLThpOJ6ZEMzM4moquQpIVxI5Br5QlHrEImw5xuzRJ0n4beBlABR gwxcXhUp5Ww6OXQvCXo/TPjUJq6FmJldPJOTZ2znj++HOfnwQQ0y9+e67X6iykpmTCNTnY9xBj eTQVelFC0u3RjxNI+6iaQiajYtmGlXa6NxZe/f4pobv24/X9thBSYebUEHc26zT6kLMkaZTQ84 +IvYioE9PrRvTTCBSF2PczUTxyVuiOsXHju58Y0XTaQcTJM0OsXt9kaqqIrinEQUTYCPGrAR2v RbcbELS7ZGWEj72hzL+5MqS0uzvBys/CzbsUxx0KJROvnTBZLtCPU/y6j1erE/g1wrBNdqREWK wktdB4QP3h8qO/K6Z2RR8bJmjtUx7KMDtd4MSozuatXX5Zus3tH29Rre7S18GtjFNanAMpr37w 2ti+ABAyeT0eLJ7vtWoDX1z9BiXV0DRJmqakSRfd1iiMOmSPjeKeqVC/H3oPT8r3ZNyzVID3L1 V2nDzPqsPlQ2PiGKoJCQFJ4qPIFH0gh3P6ONlHKlQ3ve6EEb57fl7GSh9DAVjaqmrNRsv97Kv1 xeurjcthkCyqURs7JzBdE6NokQgJSbQ+O65+euqEszo4UPytWMhvCwBUkSqq1jk356xNDUevLK /sPbl+L7jQ8ZLyUaepGE1xMDZhfDlbKSwPFt1tXcp9qWk1VWjhP2e6dneLvhdqLc/L7B3UzfX1 qttsdfKKguo4ZlguO36xWAgLth3mbSsyTatnyFz6B+BnWV0A/UiAAAAAAElFTkSuQmCC DTSTART;TZID=Europe/Berlin:20090902T100000 DTEND;TZID=Europe/Berlin:20090902T110000 TRANSP:TRANSPARENT BEGIN:VALARM DESCRIPTION: ACTION:DISPLAY TRIGGER;VALUE=DURATION:-PT15M END:VALARM END:VEVENT END:VCALENDAR libkolab-1.0.2/tests/testfiles/v3/event/complex.ics.mime000066400000000000000000000154271262531616600232240ustar00rootroot00000000000000Date: Mon, 23 Apr 2012 12:37:59 +0200 X-Kolab-Type: application/x-vnd.kolab.event X-Kolab-Mime-Version: 3.0 User-Agent: Libkolab-0.1.0 Content-Type: multipart/mixed; boundary="nextPart1929983.SbWkbbbi0G" Subject: KOrganizer-1687167952.818 MIME-Version: 1.0 --nextPart1929983.SbWkbbbi0G Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart1929983.SbWkbbbi0G Content-Type: application/calendar+xml; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" Libkolab-0.1.0 Libkolabxml-0.3.0 2.0 3.0dev1 KOrganizer-1687167952.818 2009-09-01T12:52:58Z 2012-05-05T05:05:05Z 0 PRIVATE Appointment Business /kolab.org/Europe/Berlin 2009-09-02T10:00:00 /kolab.org/Europe/Berlin 2009-09-02T11:00:00 TRANSPARENT WEEKLY 10 WE FR 2009-09-04 Complex Event Some notes on this event. Here Attendee1 NEEDS-ACTION REQ-PARTICIPANT true mailto:%3Ca1%40example.com%3E Attendee2 ACCEPTED NON-PARTICIPANT true mailto:%3Ca2%40example.com%3E Attendee3 DECLINED REQ-PARTICIPANT mailto:%3Ca3%40example.com%3E image/png akonadi.png cid:7313173.zaagFSsPPv@kolab.resource.akonadi DISPLAY START -PT900S PT5S 0 --nextPart1929983.SbWkbbbi0G Content-ID: <7313173.zaagFSsPPv@kolab.resource.akonadi> Content-Type: image/png; name="akonadi.png" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="akonadi.png" iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A /wD/oL2nkwAAAAlwSFlzAAAbrwAAG68BXhqRHAAAAAd0SU1FB9gFEQkdFPibCIYAAAMrSURBVDjL pZNLaBx1AMZ/M/P/78zOzO7ObDbvNUnTxsUUm6YmaulNxN70UKEIRTyIBy8KHrypRUTw4Ek8CqKn XuyhHgQRFTRNAvVFbOnDNO/EfWZmdmczszPrwcdBvPnBd/ng98F3+OB/Svl3cPbSx5mZ+ZkXjKx+ setHs4cHbaW+7d2s79SvhK29j+6vvXH0nwVPfLh1WsTptdnxuDDxoGv3NZWuf4S3G1C722BrrcrO nY1f/ebO05s337n3N6cBLLy1bI7njr4uD4nJhx4by5SGLQYcAzWnI6SGVFUkQKwMRqH/jGHNfXJY XwoBBMDc/MhLThpOJ6ZEMzM4moquQpIVxI5Br5QlHrEImw5xuzRJ0n4beBlABRgwxcXhUp5Ww6OX QvCXo/TPjUJq6FmJldPJOTZ2znj++HOfnwQQ0y9+e67X6iykpmTCNTnY9xBjeTQVelFC0u3RjxNI +6iaQiajYtmGlXa6NxZe/f4pobv24/X9thBSYebUEHc26zT6kLMkaZTQ84+IvYioE9PrRvTTCBSF 2PczUTxyVuiOsXHju58Y0XTaQcTJM0OsXt9kaqqIrinEQUTYCPGrAR2vRbcbELS7ZGWEj72hzL+5 MqS0uzvBys/CzbsUxx0KJROvnTBZLtCPU/y6j1erE/g1wrBNdqREWKwktdB4QP3h8qO/K6Z2RR8b JmjtUx7KMDtd4MSozuatXX5Zus3tH29Rre7S18GtjFNanAMpr37w2ti+ABAyeT0eLJ7vtWoDX1z9 BiXV0DRJmqakSRfd1iiMOmSPjeKeqVC/H3oPT8r3ZNyzVID3L1V2nDzPqsPlQ2PiGKoJCQFJ4qPI FH0gh3P6ONlHKlQ3ve6EEb57fl7GSh9DAVjaqmrNRsv97Kv1xeurjcthkCyqURs7JzBdE6NokQgJ SbQ+O65+euqEszo4UPytWMhvCwBUkSqq1jk356xNDUevLK/sPbl+L7jQ8ZLyUaepGE1xMDZhfDlb KSwPFt1tXcp9qWk1VWjhP2e6dneLvhdqLc/L7B3UzfX1qttsdfKKguo4ZlguO36xWAgLth3mbSsy TatnyFz6B+BnWV0A/UiAAAAAAElFTkSuQmCC --nextPart1929983.SbWkbbbi0G--libkolab-1.0.2/tests/testfiles/v3/event/simple.ics000066400000000000000000000005601262531616600221100ustar00rootroot00000000000000BEGIN:VCALENDAR PRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN VERSION:2.0 BEGIN:VEVENT DTSTAMP:20090901T113644Z CREATED:20090901T113644Z UID:KOrganizer-1353608432.168 LAST-MODIFIED:20090901T113644Z SUMMARY:Simple Event LOCATION:Here DTSTART;TZID=Europe/Berlin:20090902T080000 DTEND;TZID=Europe/Berlin:20090902T090000 TRANSP:OPAQUE END:VEVENT END:VCALENDAR libkolab-1.0.2/tests/testfiles/v3/event/simple.ics.mime000066400000000000000000000045151262531616600230420ustar00rootroot00000000000000Date: Mon, 23 Apr 2012 12:33:34 +0200 X-Kolab-Type: application/x-vnd.kolab.event X-Kolab-Mime-Version: 3.0 User-Agent: Libkolab-0.1.0 Content-Type: multipart/mixed; boundary="nextPart1440420.ZGVZUGuhry" Subject: KOrganizer-1353608432.168 MIME-Version: 1.0 --nextPart1440420.ZGVZUGuhry Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart1440420.ZGVZUGuhry Content-Type: application/calendar+xml; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" Libkolab-0.1.0 Libkolabxml-0.3.0 2.0 3.0dev1 KOrganizer-1353608432.168 2009-09-01T11:36:44Z 2012-05-05T05:05:05Z 0 PUBLIC /kolab.org/Europe/Berlin 2009-09-02T08:00:00 /kolab.org/Europe/Berlin 2009-09-02T09:00:00 Simple Event Here --nextPart1440420.ZGVZUGuhry--libkolab-1.0.2/tests/testfiles/v3/event/utf8.ics000066400000000000000000000006521262531616600215070ustar00rootroot00000000000000BEGIN:VCALENDAR PRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN VERSION:2.0 BEGIN:VEVENT DTSTAMP:20090901T113644Z CREATED:20090901T113644Z UID:KOrganizer-1353608432.168 LAST-MODIFIED:20090901T113644Z SUMMARY:äöü%@$£é¤¼²°€Š�ـأبـ LOCATION:äöü%@$£é¤¼²°€Š�ـأبـ DTSTART;TZID=Europe/Berlin:20090902T080000 DTEND;TZID=Europe/Berlin:20090902T090000 TRANSP:OPAQUE END:VEVENT END:VCALENDAR libkolab-1.0.2/tests/testfiles/v3/event/utf88bit.ics.mime000066400000000000000000000046011262531616600232220ustar00rootroot00000000000000Date: Fri, 17 Aug 2012 17:47:13 +0000 X-Kolab-Type: application/x-vnd.kolab.event X-Kolab-Mime-Version: 3.0 User-Agent: Libkolab-0.3.1 Content-Type: multipart/mixed; boundary="nextPart1387272.PG4QbOfaIz" Subject: KOrganizer-1353608432.168 MIME-Version: 1.0 --nextPart1387272.PG4QbOfaIz Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart1387272.PG4QbOfaIz Content-Type: application/calendar+xml; charset=UTF-8; name="kolab.xml" Content-Transfer-Encoding: 8bit Content-Disposition: attachment; filename="kolab.xml" Libkolab-0.3.1 Libkolabxml-0.5 2.0 3.0dev1 KOrganizer-1353608432.168 2009-09-01T11:36:44Z 2009-09-01T11:36:44Z 0 PUBLIC /kolab.org/Europe/Berlin 2009-09-02T08:00:00 /kolab.org/Europe/Berlin 2009-09-02T09:00:00 äöü%@$£é¤¼²°€Š�ـأبـ äöü%@$£é¤¼²°€Š�ـأبـ --nextPart1387272.PG4QbOfaIz-- libkolab-1.0.2/tests/testfiles/v3/event/utf8base64.ics.mime000066400000000000000000000056641262531616600234520ustar00rootroot00000000000000Date: Fri, 17 Aug 2012 18:00:15 +0000 X-Kolab-Type: application/x-vnd.kolab.event X-Kolab-Mime-Version: 3.0 User-Agent: Libkolab-0.3.1 Content-Type: multipart/mixed; boundary="nextPart1896568.xMY9UUPWVa" Subject: KOrganizer-1353608432.168 MIME-Version: 1.0 --nextPart1896568.xMY9UUPWVa Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart1896568.xMY9UUPWVa Content-Type: application/calendar+xml; name="kolab.xml" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="kolab.xml" PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIiA/Pgo8 aWNhbGVuZGFyIHhtbG5zPSJ1cm46aWV0ZjpwYXJhbXM6eG1sOm5zOmljYWxlbmRhci0yLjAiPgoK ICA8dmNhbGVuZGFyPgogICAgPHByb3BlcnRpZXM+CiAgICAgIDxwcm9kaWQ+CiAgICAgICAgPHRl eHQ+TGlia29sYWItMC4zLjEgTGlia29sYWJ4bWwtMC41PC90ZXh0PgogICAgICA8L3Byb2RpZD4K ICAgICAgPHZlcnNpb24+CiAgICAgICAgPHRleHQ+Mi4wPC90ZXh0PgogICAgICA8L3ZlcnNpb24+ CiAgICAgIDx4LWtvbGFiLXZlcnNpb24+CiAgICAgICAgPHRleHQ+My4wZGV2MTwvdGV4dD4KICAg ICAgPC94LWtvbGFiLXZlcnNpb24+CiAgICA8L3Byb3BlcnRpZXM+CiAgICA8Y29tcG9uZW50cz4K ICAgICAgPHZldmVudD4KICAgICAgICA8cHJvcGVydGllcz4KICAgICAgICAgIDx1aWQ+CiAgICAg ICAgICAgIDx0ZXh0PktPcmdhbml6ZXItMTM1MzYwODQzMi4xNjg8L3RleHQ+CiAgICAgICAgICA8 L3VpZD4KICAgICAgICAgIDxjcmVhdGVkPgogICAgICAgICAgICA8ZGF0ZS10aW1lPjIwMDktMDkt MDFUMTE6MzY6NDRaPC9kYXRlLXRpbWU+CiAgICAgICAgICA8L2NyZWF0ZWQ+CiAgICAgICAgICA8 ZHRzdGFtcD4KICAgICAgICAgICAgPGRhdGUtdGltZT4yMDA5LTA5LTAxVDExOjM2OjQ0WjwvZGF0 ZS10aW1lPgogICAgICAgICAgPC9kdHN0YW1wPgogICAgICAgICAgPHNlcXVlbmNlPgogICAgICAg ICAgICA8aW50ZWdlcj4wPC9pbnRlZ2VyPgogICAgICAgICAgPC9zZXF1ZW5jZT4KICAgICAgICAg IDxjbGFzcz4KICAgICAgICAgICAgPHRleHQ+UFVCTElDPC90ZXh0PgogICAgICAgICAgPC9jbGFz cz4KICAgICAgICAgIDxkdHN0YXJ0PgogICAgICAgICAgICA8cGFyYW1ldGVycz4KICAgICAgICAg ICAgICA8dHppZD4KICAgICAgICAgICAgICAgIDx0ZXh0Pi9rb2xhYi5vcmcvRXVyb3BlL0Jlcmxp bjwvdGV4dD4KICAgICAgICAgICAgICA8L3R6aWQ+CiAgICAgICAgICAgIDwvcGFyYW1ldGVycz4K ICAgICAgICAgICAgPGRhdGUtdGltZT4yMDA5LTA5LTAyVDA4OjAwOjAwPC9kYXRlLXRpbWU+CiAg ICAgICAgICA8L2R0c3RhcnQ+CiAgICAgICAgICA8ZHRlbmQ+CiAgICAgICAgICAgIDxwYXJhbWV0 ZXJzPgogICAgICAgICAgICAgIDx0emlkPgogICAgICAgICAgICAgICAgPHRleHQ+L2tvbGFiLm9y Zy9FdXJvcGUvQmVybGluPC90ZXh0PgogICAgICAgICAgICAgIDwvdHppZD4KICAgICAgICAgICAg PC9wYXJhbWV0ZXJzPgogICAgICAgICAgICA8ZGF0ZS10aW1lPjIwMDktMDktMDJUMDk6MDA6MDA8 L2RhdGUtdGltZT4KICAgICAgICAgIDwvZHRlbmQ+CiAgICAgICAgICA8c3VtbWFyeT4KICAgICAg ICAgICAgPHRleHQ+w6TDtsO8JUAkwqPDqcKkwrzCssKw4oKsxaDvv73ZgNij2KjZgDwvdGV4dD4K ICAgICAgICAgIDwvc3VtbWFyeT4KICAgICAgICAgIDxsb2NhdGlvbj4KICAgICAgICAgICAgPHRl eHQ+w6TDtsO8JUAkwqPDqcKkwrzCssKw4oKsxaDvv73ZgNij2KjZgDwvdGV4dD4KICAgICAgICAg IDwvbG9jYXRpb24+CiAgICAgICAgPC9wcm9wZXJ0aWVzPgogICAgICA8L3ZldmVudD4KICAgIDwv Y29tcG9uZW50cz4KICA8L3ZjYWxlbmRhcj4KCjwvaWNhbGVuZGFyPgo= --nextPart1896568.xMY9UUPWVa-- libkolab-1.0.2/tests/testfiles/v3/event/utf8quotedPrintable.ics.mime000066400000000000000000000050221262531616600255140ustar00rootroot00000000000000Date: Fri, 17 Aug 2012 17:47:13 +0000 X-Kolab-Type: application/x-vnd.kolab.event X-Kolab-Mime-Version: 3.0 User-Agent: Libkolab-0.3.1 Content-Type: multipart/mixed; boundary="nextPart1387272.PG4QbOfaIz" Subject: KOrganizer-1353608432.168 MIME-Version: 1.0 --nextPart1387272.PG4QbOfaIz Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart1387272.PG4QbOfaIz Content-Type: application/calendar+xml; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" Libkolab-0.3.1 Libkolabxml-0.5 2.0 3.0dev1 KOrganizer-1353608432.168 2009-09-01T11:36:44Z 2009-09-01T11:36:44Z 0 PUBLIC /kolab.org/Europe/Berlin 2009-09-02T08:00:00 /kolab.org/Europe/Berlin 2009-09-02T09:00:00 =C3=A4=C3=B6=C3=BC%@$=C2=A3=C3=A9=C2=A4=C2=BC=C2=B2=C2= =B0=E2=82=AC=C5=A0=EF=BF=BD=D9=80=D8=A3=D8=A8=D9=80 =C3=A4=C3=B6=C3=BC%@$=C2=A3=C3=A9=C2=A4=C2=BC=C2=B2=C2= =B0=E2=82=AC=C5=A0=EF=BF=BD=D9=80=D8=A3=D8=A8=D9=80 --nextPart1387272.PG4QbOfaIz-- libkolab-1.0.2/tests/testfiles/v3/journal/000077500000000000000000000000001262531616600204475ustar00rootroot00000000000000libkolab-1.0.2/tests/testfiles/v3/journal/complex.ics000066400000000000000000000006071262531616600226210ustar00rootroot00000000000000BEGIN:VCALENDAR PRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN VERSION:2.0 BEGIN:VJOURNAL DTSTAMP:20090901T150009Z CREATED:20090901T150009Z UID:KOrganizer-2037616327.585 LAST-MODIFIED:20090901T150009Z DESCRIPTION:Some notes on this journal. SUMMARY:Complex Journal CATEGORIES:Business\,Meeting\,Miscellaneous DTSTART;TZID=Europe/Berlin:20090901T165900 END:VJOURNAL END:VCALENDAR libkolab-1.0.2/tests/testfiles/v3/journal/complex.ics.mime000066400000000000000000000044351262531616600235520ustar00rootroot00000000000000Date: Fri, 27 Apr 2012 17:01:37 +0200 X-Kolab-Type: application/x-vnd.kolab.journal X-Kolab-Mime-Version: 3.0 User-Agent: Libkolab-0.2.0 Content-Type: multipart/mixed; boundary="nextPart6582735.aG9ClxN0L7" Subject: KOrganizer-2037616327.585 MIME-Version: 1.0 --nextPart6582735.aG9ClxN0L7 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart6582735.aG9ClxN0L7 Content-Type: application/calendar+xml; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" Libkolab-0.2.0 Libkolabxml-0.4.0 2.0 3.0dev1 KOrganizer-2037616327.585 2009-09-01T15:00:09Z 2012-05-05T05:05:05Z 0 PUBLIC Business Meeting Miscellaneous /kolab.org/Europe/Berlin 2009-09-01T16:59:00 Complex Journal Some notes on this journal. --nextPart6582735.aG9ClxN0L7-- libkolab-1.0.2/tests/testfiles/v3/journal/simple.ics000066400000000000000000000004701262531616600224410ustar00rootroot00000000000000BEGIN:VCALENDAR PRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN VERSION:2.0 BEGIN:VJOURNAL DTSTAMP:20090901T145756Z CREATED:20090901T145756Z UID:KOrganizer-1941104064.609 LAST-MODIFIED:20090901T145756Z SUMMARY:Simple Journal Entry DTSTART;TZID=Europe/Berlin:20090901T165700 END:VJOURNAL END:VCALENDAR libkolab-1.0.2/tests/testfiles/v3/journal/simple.ics.mime000066400000000000000000000040431262531616600233670ustar00rootroot00000000000000Date: Fri, 27 Apr 2012 17:01:07 +0200 X-Kolab-Type: application/x-vnd.kolab.journal X-Kolab-Mime-Version: 3.0 User-Agent: Libkolab-0.2.0 Content-Type: multipart/mixed; boundary="nextPart2827197.7XEdf2UEaf" Subject: KOrganizer-1941104064.609 MIME-Version: 1.0 --nextPart2827197.7XEdf2UEaf Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart2827197.7XEdf2UEaf Content-Type: application/calendar+xml; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" Libkolab-0.2.0 Libkolabxml-0.4.0 2.0 3.0dev1 KOrganizer-1941104064.609 2009-09-01T14:57:56Z 2012-05-05T05:05:05Z 0 PUBLIC /kolab.org/Europe/Berlin 2009-09-01T16:57:00 Simple Journal Entry --nextPart2827197.7XEdf2UEaf-- libkolab-1.0.2/tests/testfiles/v3/note/000077500000000000000000000000001262531616600177425ustar00rootroot00000000000000libkolab-1.0.2/tests/testfiles/v3/note/note.mime000066400000000000000000000004061262531616600215600ustar00rootroot00000000000000Subject: title Content-Type: text/plain Date: Sat, 05 May 2012 05:05:05 +0000 From: kolab@kde4 X-Akonotes-LastModified: Sat, 05 May 2012 05:05:06 +0000 X-Akonotes-UID: c04ad759-ff7f-0000-e12b-a41f537f0000 X-Akonotes-Classification: Public MIME-Version: 1.0 textlibkolab-1.0.2/tests/testfiles/v3/note/note.mime.mime000066400000000000000000000023751262531616600225150ustar00rootroot00000000000000Date: Fri, 27 Apr 2012 23:36:50 +0200 X-Kolab-Type: application/x-vnd.kolab.note X-Kolab-Mime-Version: 3.0 User-Agent: Libkolab-0.2.0 Content-Type: multipart/mixed; boundary="nextPart2028861.pg0urxaLml" Subject: c04ad759-ff7f-0000-e12b-a41f537f0000 MIME-Version: 1.0 --nextPart2028861.pg0urxaLml Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart2028861.pg0urxaLml Content-Type: application/vnd.kolab+xml; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" c04ad759-ff7f-0000-e12b-a41f537f0000 Libkolab-0.2.0 Libkolabxml-0.4.0 2012-05-05T05:05:05Z 2012-05-05T05:05:06Z= PUBLIC title text --nextPart2028861.pg0urxaLml-- libkolab-1.0.2/tests/testfiles/v3/readonly/000077500000000000000000000000001262531616600206125ustar00rootroot00000000000000libkolab-1.0.2/tests/testfiles/v3/readonly/png.vcf000066400000000000000000000226001262531616600220760ustar00rootroot00000000000000BEGIN:VCARD CLASS:PUBLIC FN:Picture Perfect N:Perfect;Picture;;; PHOTO;ENCODING=b;TYPE=png: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 = UID:4f641580-eb05-11e2-a64e-525400896ca1 VERSION:3.0 END:VCARDlibkolab-1.0.2/tests/testfiles/v3/readonly/png.vcf.mime000066400000000000000000000250161262531616600230300ustar00rootroot00000000000000MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=_40faed378be3e90d8d34690488727b1d" From: john.doe@example.org To: john.doe@example.org Date: Fri, 12 Jul 2013 15:11:21 +0000 X-Kolab-Type: application/x-vnd.kolab.contact X-Kolab-Mime-Version: 3.0 Subject: 4f641580-eb05-11e2-a64e-525400896ca1 User-Agent: Roundcube Webmail/0.9.1-2.el6.kolab_3.0 --=_40faed378be3e90d8d34690488727b1d Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=ISO-8859-1 This is a Kolab Groupware object. To view this object you will need an emai= l client that understands the Kolab Groupware format. For a list of such em= ail clients please visit http://www.kolab.org/ --=_40faed378be3e90d8d34690488727b1d Content-Transfer-Encoding: 8bit Content-Type: application/vcard+xml; charset=UTF-8; name=kolab.xml Content-Disposition: attachment; filename=kolab.xml urn:uuid:4f641580-eb05-11e2-a64e-525400896ca1 3.0dev1 Roundcube-libkolab-0.9 Libkolabxml-0.8.4 20120505T050505Z individual Picture Perfect Perfect Picture data:image/png;base64,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 --=_40faed378be3e90d8d34690488727b1d--libkolab-1.0.2/tests/testfiles/v3/task/000077500000000000000000000000001262531616600177375ustar00rootroot00000000000000libkolab-1.0.2/tests/testfiles/v3/task/complex.ics000066400000000000000000000044101262531616600221050ustar00rootroot00000000000000BEGIN:VCALENDAR PRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN VERSION:2.0 BEGIN:VTODO DTSTAMP:20090901T133915Z ATTENDEE;CN="Attendee1";RSVP=TRUE;PARTSTAT=NEEDS-ACTION; ROLE=REQ-PARTICIPANT:mailto:a1@example.com ATTENDEE;CN="Attendee2";RSVP=TRUE;PARTSTAT=TENTATIVE;ROLE=REQ-PARTICIPANT:mailto: a2@example.com ATTENDEE;CN="Attendee3";RSVP=FALSE;PARTSTAT=ACCEPTED; ROLE=OPT-PARTICIPANT:mailto:a3@example.com CREATED:20090901T133915Z UID:KOrganizer-396756838.184 LAST-MODIFIED:20090901T133915Z DESCRIPTION:Some notes on this task. SUMMARY:Complex Task LOCATION:Here CLASS:PRIVATE PRIORITY:1 CATEGORIES:Business\,Education ATTACH;VALUE=BINARY;FMTTYPE=image/png;ENCODING=BASE64;X-LABEL=akonadi.png: iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP 8A/wD/oL2nkwAAAAlwSFlzAAAbrwAAG68BXhqRHAAAAAd0SU1FB9gFEQkdFPibCIYAAAMrSURB VDjLpZNLaBx1AMZ/M/P/78zOzO7ObDbvNUnTxsUUm6YmaulNxN70UKEIRTyIBy8KHrypRUTw4E k8CqKnXuyhHgQRFTRNAvVFbOnDNO/EfWZmdmczszPrwcdBvPnBd/ng98F3+OB/Svl3cPbSx5mZ +ZkXjKx+setHs4cHbaW+7d2s79SvhK29j+6vvXH0nwVPfLh1WsTptdnxuDDxoGv3NZWuf4S3G1 C722BrrcrOnY1f/ebO05s337n3N6cBLLy1bI7njr4uD4nJhx4by5SGLQYcAzWnI6SGVFUkQKwM RqH/jGHNfXJYXwoBBMDc/MhLThpOJ6ZEMzM4moquQpIVxI5Br5QlHrEImw5xuzRJ0n4beBlABR gwxcXhUp5Ww6OXQvCXo/TPjUJq6FmJldPJOTZ2znj++HOfnwQQ0y9+e67X6iykpmTCNTnY9xBj eTQVelFC0u3RjxNI+6iaQiajYtmGlXa6NxZe/f4pobv24/X9thBSYebUEHc26zT6kLMkaZTQ84 +IvYioE9PrRvTTCBSF2PczUTxyVuiOsXHju58Y0XTaQcTJM0OsXt9kaqqIrinEQUTYCPGrAR2v RbcbELS7ZGWEj72hzL+5MqS0uzvBys/CzbsUxx0KJROvnTBZLtCPU/y6j1erE/g1wrBNdqREWK wktdB4QP3h8qO/K6Z2RR8bJmjtUx7KMDtd4MSozuatXX5Zus3tH29Rre7S18GtjFNanAMpr37w 2ti+ABAyeT0eLJ7vtWoDX1z9BiXV0DRJmqakSRfd1iiMOmSPjeKeqVC/H3oPT8r3ZNyzVID3L1 V2nDzPqsPlQ2PiGKoJCQFJ4qPIFH0gh3P6ONlHKlQ3ve6EEb57fl7GSh9DAVjaqmrNRsv97Kv1 xeurjcthkCyqURs7JzBdE6NokQgJSbQ+O65+euqEszo4UPytWMhvCwBUkSqq1jk356xNDUevLK /sPbl+L7jQ8ZLyUaepGE1xMDZhfDlbKSwPFt1tXcp9qWk1VWjhP2e6dneLvhdqLc/L7B3UzfX1 qttsdfKKguo4ZlguO36xWAgLth3mbSsyTatnyFz6B+BnWV0A/UiAAAAAAElFTkSuQmCC DUE;TZID=Europe/Berlin:20090908T160000 DTSTART;TZID=Europe/Berlin:20090901T160000 RELATED-TO:f064e7de-b197-466c-a10e-bdf8e83ab08c PERCENT-COMPLETE:50 RECURRENCE-ID;TZID=Europe/Berlin:20090908T160000 BEGIN:VALARM DESCRIPTION: ACTION:DISPLAY TRIGGER;VALUE=DURATION;RELATED=END:-PT15M END:VALARM END:VTODO END:VCALENDAR libkolab-1.0.2/tests/testfiles/v3/task/complex.ics.mime000066400000000000000000000156711262531616600230460ustar00rootroot00000000000000Date: Fri, 27 Apr 2012 16:58:49 +0200 X-Kolab-Type: application/x-vnd.kolab.task X-Kolab-Mime-Version: 3.0 User-Agent: Libkolab-0.2.0 Content-Type: multipart/mixed; boundary="nextPart1676922.i4WXLoZAWe" Subject: KOrganizer-396756838.184 MIME-Version: 1.0 --nextPart1676922.i4WXLoZAWe Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart1676922.i4WXLoZAWe Content-Type: application/calendar+xml; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" Libkolab-0.2.0 Libkolabxml-0.4.0 2.0 3.0dev1 KOrganizer-396756838.184 2009-09-01T13:39:15Z 2012-05-05T05:05:05Z 0 PRIVATE Business Education f064e7de-b197-466c-a10e-bdf8e83ab08c /kolab.org/Europe/Berlin 2009-09-01T16:00:00 /kolab.org/Europe/Berlin 2009-09-08T16:00:00 /kolab.org/Europe/Berlin 2009-09-08T16:00:00 Complex Task Some notes on this task. 1 50 Here Attendee1 NEEDS-ACTION REQ-PARTICIPANT true mailto:%3Ca1%40example.com%3E Attendee2 TENTATIVE REQ-PARTICIPANT true mailto:%3Ca2%40example.com%3E Attendee3 ACCEPTED OPT-PARTICIPANT mailto:%3Ca3%40example.com%3E image/png akonadi.png cid:2838853.9Y25si6h6e@kolab.resource.akonadi DISPLAY END -PT900S PT5S 0 --nextPart1676922.i4WXLoZAWe Content-ID: <2838853.9Y25si6h6e@kolab.resource.akonadi> Content-Type: image/png; name="akonadi.png" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="akonadi.png" iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A /wD/oL2nkwAAAAlwSFlzAAAbrwAAG68BXhqRHAAAAAd0SU1FB9gFEQkdFPibCIYAAAMrSURBVDjL pZNLaBx1AMZ/M/P/78zOzO7ObDbvNUnTxsUUm6YmaulNxN70UKEIRTyIBy8KHrypRUTw4Ek8CqKn XuyhHgQRFTRNAvVFbOnDNO/EfWZmdmczszPrwcdBvPnBd/ng98F3+OB/Svl3cPbSx5mZ+ZkXjKx+ setHs4cHbaW+7d2s79SvhK29j+6vvXH0nwVPfLh1WsTptdnxuDDxoGv3NZWuf4S3G1C722BrrcrO nY1f/ebO05s337n3N6cBLLy1bI7njr4uD4nJhx4by5SGLQYcAzWnI6SGVFUkQKwMRqH/jGHNfXJY XwoBBMDc/MhLThpOJ6ZEMzM4moquQpIVxI5Br5QlHrEImw5xuzRJ0n4beBlABRgwxcXhUp5Ww6OX QvCXo/TPjUJq6FmJldPJOTZ2znj++HOfnwQQ0y9+e67X6iykpmTCNTnY9xBjeTQVelFC0u3RjxNI +6iaQiajYtmGlXa6NxZe/f4pobv24/X9thBSYebUEHc26zT6kLMkaZTQ84+IvYioE9PrRvTTCBSF 2PczUTxyVuiOsXHju58Y0XTaQcTJM0OsXt9kaqqIrinEQUTYCPGrAR2vRbcbELS7ZGWEj72hzL+5 MqS0uzvBys/CzbsUxx0KJROvnTBZLtCPU/y6j1erE/g1wrBNdqREWKwktdB4QP3h8qO/K6Z2RR8b JmjtUx7KMDtd4MSozuatXX5Zus3tH29Rre7S18GtjFNanAMpr37w2ti+ABAyeT0eLJ7vtWoDX1z9 BiXV0DRJmqakSRfd1iiMOmSPjeKeqVC/H3oPT8r3ZNyzVID3L1V2nDzPqsPlQ2PiGKoJCQFJ4qPI FH0gh3P6ONlHKlQ3ve6EEb57fl7GSh9DAVjaqmrNRsv97Kv1xeurjcthkCyqURs7JzBdE6NokQgJ SbQ+O65+euqEszo4UPytWMhvCwBUkSqq1jk356xNDUevLK/sPbl+L7jQ8ZLyUaepGE1xMDZhfDlb KSwPFt1tXcp9qWk1VWjhP2e6dneLvhdqLc/L7B3UzfX1qttsdfKKguo4ZlguO36xWAgLth3mbSsy TatnyFz6B+BnWV0A/UiAAAAAAElFTkSuQmCC --nextPart1676922.i4WXLoZAWe-- libkolab-1.0.2/tests/testfiles/v3/task/simple.ics000066400000000000000000000004341262531616600217310ustar00rootroot00000000000000BEGIN:VCALENDAR PRODID:-//K Desktop Environment//NONSGML libkcal 3.2//EN VERSION:2.0 BEGIN:VTODO DTSTAMP:20090901T131703Z CREATED:20090901T131703Z UID:KOrganizer-2105012348.490 LAST-MODIFIED:20090901T131703Z SUMMARY:Simple Task PERCENT-COMPLETE:0 PRIORITY:7 END:VTODO END:VCALENDAR libkolab-1.0.2/tests/testfiles/v3/task/simple.ics.mime000066400000000000000000000035511262531616600226620ustar00rootroot00000000000000Date: Fri, 27 Apr 2012 16:56:44 +0200 X-Kolab-Type: application/x-vnd.kolab.task X-Kolab-Mime-Version: 3.0 User-Agent: Libkolab-0.2.0 Content-Type: multipart/mixed; boundary="nextPart7341281.t3AojKazdB" Subject: KOrganizer-2105012348.490 MIME-Version: 1.0 --nextPart7341281.t3AojKazdB Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit This is a Kolab Groupware object. To view this object you will need an email client that can understand the Kolab Groupware format. For a list of such email clients please visit http://www.kolab.org/get-kolab --nextPart7341281.t3AojKazdB Content-Type: application/calendar+xml; name="kolab.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kolab.xml" Libkolab-0.2.0 Libkolabxml-0.4.0 2.0 3.0dev1 KOrganizer-2105012348.490 2009-09-01T13:17:03Z 2012-05-05T05:05:05Z 0 PUBLIC Simple Task 7 --nextPart7341281.t3AojKazdB-- libkolab-1.0.2/tests/testhelpers.h000066400000000000000000000246531262531616600171700ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef TESTHELPERS_H #define TESTHELPERS_H #include #include #include #include #include #include #include #include #include Q_DECLARE_METATYPE(Kolab::Duration); Q_DECLARE_METATYPE(Kolab::cDateTime); Q_DECLARE_METATYPE(std::vector); Q_DECLARE_METATYPE(Kolab::Event); Q_DECLARE_METATYPE(std::vector); Q_DECLARE_METATYPE(Kolab::Todo); Q_DECLARE_METATYPE(Kolab::Journal); Q_DECLARE_METATYPE(Kolab::Contact); Q_DECLARE_METATYPE(Kolab::Period); Q_DECLARE_METATYPE(std::vector); Q_DECLARE_METATYPE(KCalCore::Event); Q_DECLARE_METATYPE(KCalCore::Todo); Q_DECLARE_METATYPE(KCalCore::Journal); namespace QTest { template<> char *toString(const Kolab::cDateTime &dt) { QByteArray ba = "Kolab::cDateTime("; ba += QByteArray::number(dt.year()) + ", " + QByteArray::number(dt.month())+ ", " + QByteArray::number(dt.day()) + ", "; ba += QByteArray::number(dt.hour()) + ", " + QByteArray::number(dt.minute()) + ", " + QByteArray::number(dt.second())+ ", "; ba += QByteArray(dt.isUTC()?QByteArray("UTC"):QByteArray("TZ: "+QByteArray::fromStdString(dt.timezone()))); ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const KDateTime &dt) { QByteArray ba = "KDateTime("; ba += dt.toString().toAscii(); ba += dt.timeZone().name().toAscii(); ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const KCalCore::Attendee &at) { QByteArray ba = "Attendee("; ba += at.name().toAscii() + ", "; ba += at.email().toAscii() + ", "; ba += QByteArray::number(at.role()) + ", "; ba += QByteArray::number(at.status()) + ", "; ba += QByteArray::number(at.RSVP()) + ", "; ba += at.delegate().toAscii() + ", "; ba += at.delegator().toAscii() + ", "; ba += at.uid().toAscii() + ", "; ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const QList &l) { QByteArray ba = "QList("; foreach(int i, l) { ba += QByteArray::number(i) + ", "; } ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const QList &l) { QByteArray ba = "QList("; foreach(const KCalCore::RecurrenceRule::WDayPos &i, l) { ba += QByteArray::number(i.pos()) + " "; ba += QByteArray::number(i.day()) + ", "; } ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const KCalCore::DateList &l) { QByteArray ba = "KCalCore::DateList("; foreach(const QDate &i, l) { ba += i.toString().toLatin1(); } ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const KCalCore::DateTimeList &l) { QByteArray ba = "KCalCore::DateTimeList("; foreach(const KDateTime &i, l) { ba += toString(i); } ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const KCalCore::Recurrence &at) { // at.dump(); KCalCore::RecurrenceRule *r = at.defaultRRule(); QByteArray ba; if (!r) { ba += "Recurrence( )"; } else { Q_ASSERT(r); Q_ASSERT(at.rRules().size() == 1); ba += "Recurrence("; ba += QByteArray::number(r->recurrenceType()) + "\n"; ba += QByteArray::number(r->frequency()) + "\n"; ba += QByteArray::number(r->duration()) + "\n"; ba += QByteArray(toString(r->startDt())) + "\n"; ba += QByteArray(toString(r->endDt())) + "\n"; ba += QByteArray(toString(r->bySeconds())) + "\n"; ba += QByteArray(toString(r->byMinutes())) + "\n"; ba += QByteArray(toString(r->byHours())) + "\n"; ba += QByteArray(toString(r->byDays())) + "\n"; ba += QByteArray(toString(r->byMonthDays())) + "\n"; ba += QByteArray(toString(r->byYearDays())) + "\n"; ba += QByteArray(toString(r->byMonths())) + "\n"; ba += ")\n"; ba += QByteArray(toString(at.exDates())) + "\n"; ba += QByteArray(toString(at.exDateTimes())) + "\n"; ba += QByteArray(toString(at.rDates())) + "\n"; ba += QByteArray(toString(at.rDateTimes())) + "\n"; } return qstrdup(ba.data()); } template<> char *toString(const Kolab::RecurrenceRule &at) { QByteArray ba; ba += "KolabRecurrenceRule("; ba += QByteArray::number(at.weekStart()) + "\n"; ba += QByteArray::number(at.frequency()) + "\n"; ba += QByteArray::number(at.interval()) + "\n"; ba += QByteArray::number(at.count()) + "\n"; ba += QByteArray(toString(at.end())) + "\n"; ba += QByteArray(toString(at.bysecond())) + "\n"; ba += QByteArray(toString(at.byminute())) + "\n"; ba += QByteArray(toString(at.byhour())) + "\n"; ba += QByteArray(toString(at.byday())) + "\n"; ba += QByteArray(toString(at.bymonthday())) + "\n"; ba += QByteArray(toString(at.byyearday())) + "\n"; ba += QByteArray(toString(at.byweekno())) + "\n"; ba += QByteArray(toString(at.bymonth())) + "\n"; ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const KCalCore::Duration &d) { QByteArray ba; ba += "KCalCore::Duration("; ba += QByteArray::number(d.isDaily()) + ", "; ba += QByteArray::number(d.value()) + " "; ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const Kolab::ContactReference &a) { QByteArray ba = "Kolab::ContactReference("; ba += QByteArray::fromStdString(a.email()) + ", "; ba += QByteArray::fromStdString(a.name()) + ", "; ba += QByteArray::fromStdString(a.uid()); ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const std::vector &v) { QByteArray ba = "vector("; for (std::size_t i = 0; i < v.size(); i++) { ba += QByteArray(toString(v.at(i)))+ "\n"; } ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const Kolab::Attendee &a) { QByteArray ba = "Kolab::Attendee("; ba += QByteArray::fromStdString(a.contact().email()) + "\n"; ba += QByteArray::fromStdString(a.contact().name()) + "\n"; ba += QByteArray::number(a.partStat()) + "\n"; ba += QByteArray::number(a.role()) + "\n"; ba += QByteArray::number(a.rsvp()) + "\n"; ba += QByteArray::fromStdString(a.contact().uid())+"\n"; ba += QByteArray(toString(a.delegatedTo()))+"\n"; ba += QByteArray(toString(a.delegatedFrom()))+ "\n"; ba += QByteArray::number(a.cutype())+ "\n"; ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const std::vector &v) { QByteArray ba = "vector("; for (std::size_t i = 0; i < v.size(); i++) { ba += QByteArray(toString(v.at(i)))+ "\n"; ba += QByteArray("#######################")+ "\n"; } ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const Kolab::CustomProperty &a) { QByteArray ba = "Kolab::CustomProperty("; ba += QByteArray::fromStdString(a.identifier) + ", "; ba += QByteArray::fromStdString(a.value); ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const std::vector &v) { QByteArray ba = "vector("; for (std::size_t i = 0; i < v.size(); i++) { ba += QByteArray(toString(v.at(i)))+ "\n"; } ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const Kolab::Period &p) { QByteArray ba = "Kolab::Period("; ba += QByteArray(toString(p.start))+ "\n"; ba += QByteArray(toString(p.end))+ "\n"; ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const std::vector &v) { QByteArray ba = "vector("; for (std::size_t i = 0; i < v.size(); i++) { ba += QByteArray(toString(v.at(i)))+ "\n"; } ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const Kolab::FreebusyPeriod &p) { QByteArray ba = "Kolab::FreebusyPeriod("; ba += QByteArray::number(p.type())+ "\n"; ba += QByteArray::fromStdString(p.eventUid())+ "\n"; ba += QByteArray::fromStdString(p.eventLocation())+ "\n"; ba += QByteArray::fromStdString(p.eventSummary())+ "\n"; ba += QByteArray(toString(p.periods()))+ "\n"; ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const Kolab::Duration &p) { QByteArray ba = "Kolab::Duration"; ba += p.isNegative() ? "-": "+"; ba += "("; ba += QByteArray::number(p.weeks())+ ", "; ba += QByteArray::number(p.days())+ ", "; ba += QByteArray::number(p.hours())+ ", "; ba += QByteArray::number(p.minutes())+ ", "; ba += QByteArray::number(p.seconds()); ba += ")"; return qstrdup(ba.data()); } } #endif libkolab-1.0.2/tests/testutils.h000066400000000000000000000244121262531616600166570ustar00rootroot00000000000000/* * Copyright (C) 2012 Christian Mollekopf * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see . */ #ifndef TESTUTILS_H #define TESTUTILS_H #include #include #include #include #include #include "kolabformat/kolabobject.h" Q_DECLARE_METATYPE(Kolab::ObjectType); Q_DECLARE_METATYPE(Kolab::Version); #define KCOMPARE(actual, expected) \ do {\ if ( !(actual == expected) ) { \ qDebug() << __FILE__ << ':' << __LINE__ << "Actual: " #actual ": " << actual << "\nExpected: " #expected ": " << expected; \ return false; \ } \ } while (0) #endif #define DIFFCOMPARE(actual, expected) \ do {\ if ( !(actual.simplified() == expected.simplified()) ) { \ qDebug() << "Content not the same."; \ showDiff(expected, actual); \ QTest::qFail("Compared versions differ.", __FILE__, __LINE__); \ return; \ } \ } while (0) #define TESTVALUE(type, name)\ *static_cast(QTest::qData(#name, ::qMetaTypeId())) const QString TESTFILEDIR = QString::fromLatin1(TEST_DATA_PATH "/testfiles/"); QString getPath(const char *file) { return TESTFILEDIR+QString::fromLatin1(file); } void showDiff(const QString &expected, const QString &converted) { if (expected.isEmpty() || converted.isEmpty()) { qWarning() << "files are emtpy"; return; } if (expected == converted) { qWarning() << "contents are the same"; return; } bool showDiff = true; if (showDiff) { QTemporaryFile expectedFile("expectedFile"); QTemporaryFile convertedFile("convertedFile"); if (expectedFile.open() && convertedFile.open()) { expectedFile.write(expected.toLatin1()); convertedFile.write(converted.toLatin1()); expectedFile.close(); convertedFile.close(); QProcess::execute("kdiff3", QStringList() << expectedFile.fileName() << convertedFile.fileName()); } else { qWarning() << "files are not open"; } } else { qDebug() << "EXPECTED: " << expected; qDebug() << "CONVERTED: " << converted; } } KMime::Message::Ptr readMimeFile( const QString &fileName, bool &ok) { // qDebug() << fileName; QFile file( fileName ); ok = file.open( QFile::ReadOnly ); if (!ok) { qWarning() << "failed to open file: " << fileName; return KMime::Message::Ptr(); } const QByteArray data = file.readAll(); KMime::Message::Ptr msg = KMime::Message::Ptr(new KMime::Message); msg->setContent( data ); msg->parse(); return msg; } void normalizeMimemessage(QString &content) { content.replace(QRegExp("\\bLibkolab-\\d.\\d.\\d\\b", Qt::CaseSensitive), "Libkolab-x.x.x"); content.replace(QRegExp("\\bLibkolabxml-\\d.\\d.\\d\\b", Qt::CaseSensitive), "Libkolabxml-x.x.x"); content.replace(QRegExp("\\bLibkolab-\\d.\\d\\b", Qt::CaseSensitive), "Libkolab-x.x.x"); content.replace(QRegExp("\\bLibkolabxml-\\d.\\d\\b", Qt::CaseSensitive), "Libkolabxml-x.x.x"); content.replace(QRegExp("cid:*@kolab.resource.akonadi", Qt::CaseSensitive, QRegExp::Wildcard), "cid:id@kolab.resource.akonadi"); content.replace(QRegExp("Content-ID: <*@kolab.resource.akonadi>", Qt::CaseSensitive, QRegExp::Wildcard), "Content-ID: "); content.replace(QRegExp("mailto:*", Qt::CaseSensitive, QRegExp::Wildcard), "mailto:"); content.replace(QRegExp("mailto:*", Qt::CaseSensitive, QRegExp::Wildcard), "mailto:"); content.replace(QRegExp("data:*", Qt::CaseSensitive, QRegExp::Wildcard), "data:"); content.replace(QRegExp("*", Qt::CaseSensitive, QRegExp::Wildcard), ""); //We no longer support pobox, so remove pobox lines content.replace(QRegExp("*", Qt::CaseSensitive, QRegExp::Wildcard), ""); content.replace(QRegExp("*", Qt::CaseSensitive, QRegExp::Wildcard), ""); content.replace(QRegExp("*", Qt::CaseSensitive, QRegExp::Wildcard), ""); content.replace(QRegExp("--nextPart\\S*", Qt::CaseSensitive), "--part"); content.replace(QRegExp("\\bboundary=\"nextPart[^\\n]*", Qt::CaseSensitive), "boundary"); content.replace(QRegExp("Date[^\\n]*", Qt::CaseSensitive), "Date"); //The sort order of the attributes in kolabV2 is unpredictable content.replace(QRegExp("", Qt::CaseSensitive, QRegExp::Wildcard), ""); //quoted-printable encoding changes where the linebreaks are every now and then (an all are valid), so we remove the linebreaks content.replace(QRegExp("=\\n", Qt::CaseSensitive), ""); } QString normalizeVCardMessage(QString content) { //The encoding changes every now and then content.replace(QRegExp("ENCODING=b;TYPE=png:*", Qt::CaseSensitive, QRegExp::Wildcard), "ENCODING=b;TYPE=png:picturedata"); return content; } //Normalize incidences for comparison void normalizeIncidence( KCalCore::Incidence::Ptr incidence) { //The UID is not persistent (it's just the internal pointer), therefore we clear it //TODO make sure that the UID does really not need to be persistent foreach(KCalCore::Attendee::Ptr attendee, incidence->attendees()) { attendee->setUid(QString()); } //FIXME even if hasDueDate can differ, it shouldn't because it breaks equality. Check why they differ in the first place. if ( incidence->type() == KCalCore::IncidenceBase::TypeTodo ) { KCalCore::Todo::Ptr todo = incidence.dynamicCast(); Q_ASSERT(todo.data()); if ( !todo->hasDueDate() && !todo->hasStartDate() ) todo->setAllDay( false ); // all day has no meaning if there are no start and due dates but may differ nevertheless } } template