diff --git a/CMakeLists.txt b/CMakeLists.txt index f9ce7df..3bec3f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,211 +1,213 @@ project(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 1) #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 ${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) diff --git a/icalendar/imip.cpp b/icalendar/imip.cpp index f4dca36..3241568 100644 --- a/icalendar/imip.cpp +++ b/icalendar/imip.cpp @@ -1,238 +1,238 @@ /* 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( message.get() ); + 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( bodyMessage ); + 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( attachMessage ); + 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(); } diff --git a/kolabformat/mimeobject.cpp b/kolabformat/mimeobject.cpp index d5b21e1..d2eadf1 100644 --- a/kolabformat/mimeobject.cpp +++ b/kolabformat/mimeobject.cpp @@ -1,753 +1,754 @@ /* * 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->getHeaderByType(X_KOLAB_TYPE_HEADER)) { + 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->getHeaderByType(X_KOLAB_MIME_VERSION_HEADER); + 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->getHeaderByType(X_KOLAB_MIME_VERSION_HEADER_COMPAT); + 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(QString::fromLatin1(KMime::uniqueString())).arg("kolab.resource.akonadi").toStdString(); + 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(); } } diff --git a/mime/mimeutils.cpp b/mime/mimeutils.cpp index 640d3e5..153fe66 100644 --- a/mime/mimeutils.cpp +++ b/mime/mimeutils.cpp @@ -1,231 +1,235 @@ /* * 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()); - message->appendHeader(new KMime::Headers::Generic(X_KOLAB_TYPE_HEADER, message.get(), xKolabType, "utf-8")); + KMime::Headers::Generic* h = new KMime::Headers::Generic(X_KOLAB_TYPE_HEADER); + h->fromUnicodeString(xKolabType, "utf-8"); + message->appendHeader(h); if (v3) { - message->appendHeader(new KMime::Headers::Generic(X_KOLAB_MIME_VERSION_HEADER, message.get(), KOLAB_VERSION_V3, "utf-8")); + 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 diff --git a/tests/formattest.cpp b/tests/formattest.cpp index a3edc0e..15b9c40 100644 --- a/tests/formattest.cpp +++ b/tests/formattest.cpp @@ -1,496 +1,496 @@ /* * 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.get()); + QVERIFY(convertedNote.data()); //Parse note const KMime::Message::Ptr &realNote = readMimeFile( noteFileName, ok ); QVERIFY(ok); - QVERIFY(realNote.get()); + 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.get()); - QVERIFY(msg.get()); + 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"