diff --git a/CMakeLists.txt b/CMakeLists.txt index d71b59d11..4e09232d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,180 +1,181 @@ project(kdepimlibs) # where to look first for cmake modules. This line must be the first one or cmake will use the system's FindFoo.cmake set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules") ############### Build Options ############### option(KDEPIM_ONLY_KLEO "Only build the libraries needed by Kleopatra." FALSE) ############### The kdepimlibs version (used e.g. in KdepimLibsConfig.cmake) ############### set(KDEPIMLIBS_VERSION_MAJOR 4) set(KDEPIMLIBS_VERSION_MINOR 3) set(KDEPIMLIBS_VERSION_PATCH 60) set(KDEPIMLIBS_VERSION ${KDEPIMLIBS_VERSION_MAJOR}.${KDEPIMLIBS_VERSION_MINOR}.${KDEPIMLIBS_VERSION_PATCH}) ############### search packages used by KDE ############### find_package(KDE4 4.2.90 REQUIRED) include(KDE4Defaults) include(MacroLibrary) ############### Needed commands before building anything ############### add_definitions (${QT_DEFINITIONS} ${KDE4_DEFINITIONS}) include_directories (${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES}) ############### Find the stuff we need ############### set(Boost_MINIMUM_VERSION "1.33.1") find_package(Boost) macro_log_feature(Boost_FOUND "Boost" "Boost C++ Libraries" "http://www.boost.org" TRUE "" "Required by several critical KDEPIM apps.") #FindGpgme.cmake already handles the log message but we must ensure it is required. find_package(Gpgme REQUIRED) # configure macros if (GPGME_FOUND) include (gpgme++/ConfigureChecks.cmake) endif (GPGME_FOUND) if (NOT KDEPIM_ONLY_KLEO) #FindAkonadi.cmake is only there for compatibility reasons, but we don't want to use that. find_package(Akonadi 1.1.91 QUIET NO_MODULE) macro_log_feature(Akonadi_FOUND "Akonadi" "Akonadi server libraries (from kdesupport)" "http://pim.kde.org/akonadi" TRUE "1.1.95" "Akonadi is required to build KdepimLibs.") find_package(Sasl2) macro_log_feature(SASL2_FOUND "cyrus-sasl" "Cyrus SASL API" "http://asg.web.cmu.edu/sasl/sasl-library.html" TRUE "" "Required to support authentication of logins in the IMAP and Sieve kioslaves.") include (ConfigureChecks.cmake) set(SHARED_MIME_INFO_MINIMUM_VERSION "0.30") find_package(SharedMimeInfo) macro_log_feature(SHARED_MIME_INFO_FOUND "SMI" "SharedMimeInfo" "http://freedesktop.org/wiki/Software/shared-mime-info" TRUE "0.30" "SharedMimeInfo is required.") endif (NOT KDEPIM_ONLY_KLEO) ############### Now, we add the KDEPIMLibs components ############### # These targets will always be built add_subdirectory(cmake) add_subdirectory(gpgme++) add_subdirectory(qgpgme) if (NOT KDEPIM_ONLY_KLEO) add_subdirectory(akonadi) add_subdirectory(kabc) add_subdirectory(kblog) add_subdirectory(kcal) add_subdirectory(kholidays) add_subdirectory(kimap) add_subdirectory(kioslave) add_subdirectory(kldap) add_subdirectory(kmime) add_subdirectory(kpimidentities) add_subdirectory(kpimutils) add_subdirectory(kpimtextedit) add_subdirectory(kresources) add_subdirectory(ktnef) add_subdirectory(kxmlrpcclient) add_subdirectory(mailtransport) + add_subdirectory(messagecomposer) add_subdirectory(microblog) add_subdirectory(syndication) # Build the CamelCase headers add_subdirectory(includes) endif (NOT KDEPIM_ONLY_KLEO) # doc must be a subdir of kdepimlibs macro_optional_add_subdirectory(doc) # All done, let's display what we found... macro_display_feature_log() ############### Here we install some extra stuff ############### if (NOT KDEPIM_ONLY_KLEO) install(FILES kdepimlibs-mime.xml DESTINATION ${XDG_MIME_INSTALL_DIR}) update_xdg_mimetypes(${XDG_MIME_INSTALL_DIR}) endif (NOT KDEPIM_ONLY_KLEO) # now create the KdepimLibsConfig.cmake file, which will be loaded by # kdelibs/cmake/modules/FindKdepimLibs.cmake and which has to contain all information # about the installed kdepimlibs anybody would like to have. Alex # we need the absolute directories where stuff will be installed too # but since the variables which contain the destinations can be relative # or absolute paths, we need this macro to make them all absoulte, Alex macro(MAKE_INSTALL_PATH_ABSOLUTE out in) if (IS_ABSOLUTE "${in}") # IS_ABSOLUTE is new since cmake 2.4.8 set(${out} "${in}") else (IS_ABSOLUTE "${in}") set(${out} "\${KDEPIMLIBS_INSTALL_DIR}/${in}") endif (IS_ABSOLUTE "${in}") endmacro(MAKE_INSTALL_PATH_ABSOLUTE out in) # all the following variables are put into KdepimLibsConfig.cmake, so # they are usable by projects using kdepimlibs. Alex make_install_path_absolute(KDEPIMLIBS_DATA_DIR ${DATA_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_DBUS_INTERFACES_DIR ${DBUS_INTERFACES_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_DBUS_SERVICES_DIR ${DBUS_SERVICES_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_INCLUDE_DIR ${INCLUDE_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_LIB_DIR ${LIB_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_BIN_DIR ${BIN_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_LIBEXEC_DIR ${LIBEXEC_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_SBIN_DIR ${SBIN_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_HTML_DIR ${HTML_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_CONFIG_DIR ${CONFIG_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_ICON_DIR ${ICON_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_KCFG_DIR ${KCFG_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_LOCALE_DIR ${LOCALE_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_MIME_DIR ${MIME_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_SOUND_DIR ${SOUND_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_TEMPLATES_DIR ${TEMPLATES_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_WALLPAPER_DIR ${WALLPAPER_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_KCONF_UPDATE_DIR ${KCONF_UPDATE_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_AUTOSTART_DIR ${AUTOSTART_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_XDG_APPS_DIR ${XDG_APPS_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_XDG_DIRECTORY_DIR ${XDG_DIRECTORY_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_SYSCONF_DIR ${SYSCONF_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_MAN_DIR ${MAN_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_INFO_DIR ${INFO_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_SERVICES_DIR ${SERVICES_INSTALL_DIR}) make_install_path_absolute(KDEPIMLIBS_SERVICETYPES_DIR ${SERVICETYPES_INSTALL_DIR}) # Used in configure_file() and install(EXPORT) set(KDEPIMLIBS_TARGET_PREFIX KDEPIMLibs__) # this file is installed and contains all necessary information about the installed kdepimlibs, it also loads the file with the exported targets configure_file(KdepimLibsConfig.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/KdepimLibsConfig.cmake" @ONLY) # this file will be installed too and will be used by cmake when searching for the Config.cmake file to check the version of kdepimlibs, Alex macro_write_basic_cmake_version_file(${CMAKE_CURRENT_BINARY_DIR}/KdepimLibsConfigVersion.cmake ${KDEPIMLIBS_VERSION_MAJOR} ${KDEPIMLIBS_VERSION_MINOR} ${KDEPIMLIBS_VERSION_PATCH}) set(_KdepimLibsConfig_INSTALL_DIR ${LIB_INSTALL_DIR}/KdepimLibs/cmake) # places where find_package() looks for FooConfig.cmake files: # CMake >= 2.6.0 looks in lib/Foo*/cmake/, CMake >= 2.6.3 also looks in # lib/cmake/Foo*/, which packagers prefer. So they can set the KDE4_USE_COMMON_CMAKE_PACKAGE_CONFIG_DIR # option to have kdepimlibs install its Config file there. Alex if(KDE4_USE_COMMON_CMAKE_PACKAGE_CONFIG_DIR) set(_KdepimLibsConfig_INSTALL_DIR ${LIB_INSTALL_DIR}/cmake/KdepimLibs) endif(KDE4_USE_COMMON_CMAKE_PACKAGE_CONFIG_DIR) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/KdepimLibsConfigVersion.cmake ${CMAKE_CURRENT_BINARY_DIR}/KdepimLibsConfig.cmake DESTINATION ${_KdepimLibsConfig_INSTALL_DIR} ) # Install the file with the exported targets, use ${KDEPIMLIBS_TARGET_PREFIX} as prefix for the names of these targets, Alex install(EXPORT kdepimlibsLibraryTargets NAMESPACE ${KDEPIMLIBS_TARGET_PREFIX} DESTINATION ${_KdepimLibsConfig_INSTALL_DIR} FILE KDEPimLibsLibraryTargetsWithPrefix.cmake ) # Install a KDEPimLibsDependencies.cmake so people using kdepimlibs 4.2 with kdelibs < 4.2 get a useful error message, Alex file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/KDEPimLibsDependencies.cmake "\n message(FATAL_ERROR \"For using this version of kdepimlibs (${KDEPIMLIBS_VERSION}) you need a newer version of kdelibs, please update.\")\n") install(FILES ${CMAKE_CURRENT_BINARY_DIR}/KDEPimLibsDependencies.cmake DESTINATION ${DATA_INSTALL_DIR}/cmake/modules) diff --git a/messagecomposer/CMakeLists.txt b/messagecomposer/CMakeLists.txt new file mode 100644 index 000000000..20a05f0d8 --- /dev/null +++ b/messagecomposer/CMakeLists.txt @@ -0,0 +1,45 @@ +set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}" ) + +add_subdirectory( tests ) + +set( messagecomposer_src + + composer.cpp + behaviour.cpp + attachmentpart.cpp + finalmessage.cpp + infopart.cpp + messagepart.cpp + skeletonmessagejob.cpp + textpart.cpp + + job.cpp + contentjob.cpp + maintextjob.cpp + multipartjob.cpp +) + +kde4_add_library( messagecomposer SHARED ${messagecomposer_src} ) +target_link_libraries( messagecomposer ${KDE4_KIO_LIBS} kmime ) +set_target_properties( messagecomposer PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION} ) + +install( TARGETS messagecomposer EXPORT kdepimlibsLibraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS} ) +install( FILES + messagecomposer_export.h + + composer.h + behaviour.h + attachmentpart.h + finalmessage.h + infopart.h + messagepart.h + skeletonmessagejob.h + textpart.h + + job.h + contentjob.h + maintextjob.h + multipartjob.h + + DESTINATION ${INCLUDE_INSTALL_DIR}/messagecomposer COMPONENT Devel ) + diff --git a/messagecomposer/DESIGN b/messagecomposer/DESIGN new file mode 100644 index 000000000..bf9d468fa --- /dev/null +++ b/messagecomposer/DESIGN @@ -0,0 +1,60 @@ +How the composer works: +-------------------------- +Input data: + +MessagePart classes represent the data of messages in an abstract way that is very close to +the way a GUI composer would see the data. Thus, the composer takes the folowing input data: +* InfoPart: + - Mode: compose the messages to be sent, or to be saved somewhere locally. + - Sender and recipients. + - The transport to use. + - Signing and encryption settings. +* TextPart: + - The plain text and, optionally, the HTML text from an editor. + - The charsets the user prefers. +* Zero or more AttachmentParts: + - The file to be attached. + - Signing and encryption settings for the attachment. + +-------------------------- +Output data: + +The composer outputs a set of Messages. If crypto is used, we have to encrypt the message +separately with each recipient's public key, hence we may need to send more than one message. +A Message contains the KMime::Message to be sent, and the From:, To:, Cc:, and Bcc: strings +to use for the transport. Note that, because of crypto and the fact that Bcc: need to be +blind, these fields used for transport may be different from the corresponding headers encoded +in the KMime::Message. If the message is composed for saving (as opposed to being composed +for sending), these fields are saved in the KMime::Message as custom X- fields. + +-------------------------- +Class hierarchy: ++ Composer (:KJob) -- The master object that controls everything else. ++ FinalMessage (:) -- Container for a final KMime::Message as well as sender and + recipient addresses to be used for transport. ++ Job (:KJob) -- Abstract base class for representing some content part from a KMime + point of view. FIXME not true + + ... ++ MessagePart (:QObject) -- Abstract base class for representing some part of the message from + a GUI composer point of view. + + ... + +-------------------------- +Logic: + +Definitions: +* Early attachment -- An attachment that has the same signing / crypto settings as the main + text part, and is joined with the text part before any signing or + encryption. +* Late attachment -- An attachment that has different signing / crypto settings from the main + text part, and is encrypted, signed, and added only after the main part + has been signed and encrypted. + +Algorithm: +1) Take the text content (plain or plain+HTML) and the early attachments, and compose them + into contentBeforeCrypto. +2) For each recipient of the message, encrypt contentBeforeCrypto, encrypt and add the late + attachments, save the recipients address (so that we know whom to send this message to), + and save this as one of the final messages. + +-------------------------- diff --git a/messagecomposer/PLAN b/messagecomposer/PLAN new file mode 100644 index 000000000..1491a310f --- /dev/null +++ b/messagecomposer/PLAN @@ -0,0 +1,38 @@ +1) Make it work for plain text (including charset, word wrapping stuff) +2) Figure out headers (groups, display names, empty to:, local usernames, comments?) +3) HTML +4) Transport +5) Attachments +6) Signing & Crypto ++tests at every step. + +Questions: +* Plain messages with only us-ascii characters: KMail makes them MIME messages + anyway. Do we ever want to send a non-MIME message? +* When is the "default" charset used? +* If multi-recipient-crypto, save all in sent-mail or just one unencrypted copy? + KMail seems to save the encrypted stuff, but then how can it be decrypted + without someone's private key? Or does KMail save a copy encrypted with my own + key??? --> Now I think that's exactly what it does. +* What should be in namespace KMail? +* Do we ever want to send a html-only message with no plaintext alternative? +* Why is KeyResolver in KMail and not kleopatra / libkleo??? +* Can KMime::Message::Ptr be forward-declared somehow? +* I have no clue how to make this extensible... and Behaviour is already a problem. +* What is the policy on Content-Transfer-Encoding? +* When should I have a virtual destructor if it's empty? (I guess only then someone + might subclass...) +* Disable copy constructors of jobs... +* Should drafts be encrypted to self? +* Figure out if MessagePart & family need to be qobjects at all... +* Currently MessagePart is a useless empty base class. +* I get an error from boost if I don't enable exceptions. But KMime seems to work + without them just fine. WTF? +* MessageComposer::Job and Akonadi::Job collide... +* The errors are defined in Job and Composer does not inherit that. I don't want + to make it inherit Job because it is really different from a Job (it doesn't + create a content, for starters). But then apps need to compare with + Job::SomeError instead of Composer::SomeError, and need to include job.h just for + that :-( +* Copying headers, contents, messages... is tricky. +* What is a good guideline for when I should call Content::assemble()? diff --git a/messagecomposer/TODO.cberzan b/messagecomposer/TODO.cberzan new file mode 100644 index 000000000..dbc3f26e3 --- /dev/null +++ b/messagecomposer/TODO.cberzan @@ -0,0 +1,3 @@ +Design: +* Lots of duplication between AttachmentStrategy, AlternativeStrategy, + RelatedStrategy on one hand, and GpgSigned, GpgEncrypted on the other hand... diff --git a/messagecomposer/attachmentpart.cpp b/messagecomposer/attachmentpart.cpp new file mode 100644 index 000000000..6110b6fc6 --- /dev/null +++ b/messagecomposer/attachmentpart.cpp @@ -0,0 +1,68 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "attachmentpart.h" + +#include + +using namespace MessageComposer; + +class MessageComposer::AttachmentPart::Private +{ + public: + KUrl url; + bool dataLoaded; + QByteArray data; +}; + +AttachmentPart::AttachmentPart( QObject *parent ) + : MessagePart( parent ) + , d( new Private ) +{ + d->dataLoaded = false; +} + +AttachmentPart::~AttachmentPart() +{ + delete d; +} + +KUrl AttachmentPart::url() const +{ + return d->url; +} + +void AttachmentPart::setUrl( const KUrl &url ) +{ + d->url = url; + d->dataLoaded = false; +} + +bool AttachmentPart::isDataLoaded() const +{ + return d->dataLoaded; +} + +bool AttachmentPart::loadData() +{ + // TODO + return false; +} + +#include "attachmentpart.moc" diff --git a/messagecomposer/attachmentpart.h b/messagecomposer/attachmentpart.h new file mode 100644 index 000000000..7ac36807a --- /dev/null +++ b/messagecomposer/attachmentpart.h @@ -0,0 +1,56 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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 MESSAGECOMPOSER_ATTACHMENTPART_H +#define MESSAGECOMPOSER_ATTACHMENTPART_H + +#include "messagepart.h" + +#include + +class KUrl; + +namespace MessageComposer { + +class MESSAGECOMPOSER_EXPORT AttachmentPart : public MessagePart +{ + Q_OBJECT + + public: + typedef QList List; + + explicit AttachmentPart( QObject *parent = 0 ); + virtual ~AttachmentPart(); + + KUrl url() const; + void setUrl( const KUrl &url ); + + bool isDataLoaded() const; + bool loadData(); + + // TODO handle mime type; charset for textual types, etc. + + private: + class Private; + Private *const d; +}; + +} // namespace MessageComposer + +#endif // MESSAGECOMPOSER_INFOPART_H diff --git a/messagecomposer/behaviour.cpp b/messagecomposer/behaviour.cpp new file mode 100644 index 000000000..a95fd9aa5 --- /dev/null +++ b/messagecomposer/behaviour.cpp @@ -0,0 +1,123 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "behaviour.h" + +using namespace MessageComposer; + +Behaviour::Behaviour() + : d( new Private ) +{ + // Default behaviour for sending. + d->actions[ UseGui ] = true; + d->actions[ UseCrypto ] = true; + d->actions[ UseWrapping ] = true; + d->actions[ UseFallbackCharset ] = false; + d->actions[ WarnBadCharset ] = true; + d->actions[ WarnZeroRecipients ] = true; + d->actions[ CustomHeaders ] = false; +} + +Behaviour::~Behaviour() +{ + // d is a QSharedDataPointer. +} + +bool Behaviour::isActionEnabled( Action action ) const +{ + Q_ASSERT( action >= 0 && action < LastAction ); + return d->actions[ action ]; +} + +void Behaviour::enableAction( Action action, bool enable ) +{ + Q_ASSERT( action >= 0 && action < LastAction ); + d->actions[ action ] = enable; +} + +void Behaviour::disableAction( Action action ) +{ + Q_ASSERT( action >= 0 && action < LastAction ); + d->actions[ action ] = false; +} + + + +//static +Behaviour Behaviour::behaviourForSending() +{ + static Behaviour beh; + // A default-constructed Behaviour has default sending behaviour. + return beh; +} + +//static +Behaviour Behaviour::behaviourForPrinting() +{ + static bool init = false; + static Behaviour beh; + if( !init ) { + beh.d->actions[ UseGui ] = true; + beh.d->actions[ UseCrypto ] = false; + beh.d->actions[ UseWrapping ] = true; + beh.d->actions[ UseFallbackCharset ] = false; + beh.d->actions[ WarnBadCharset ] = true; + beh.d->actions[ WarnZeroRecipients ] = false; + beh.d->actions[ CustomHeaders ] = false; + init = true; + } + return beh; +} + +//static +Behaviour Behaviour::behaviourForAutosaving() +{ + static bool init = false; + static Behaviour beh; + if( !init ) { + beh.d->actions[ UseGui ] = false; + beh.d->actions[ UseCrypto ] = false; + beh.d->actions[ UseWrapping ] = false; + beh.d->actions[ UseFallbackCharset ] = true; + beh.d->actions[ WarnBadCharset ] = false; + beh.d->actions[ WarnZeroRecipients ] = false; + beh.d->actions[ CustomHeaders ] = true; + init = true; + } + return beh; +} + +//static +Behaviour Behaviour::behaviourForSavingLocally() +{ + static bool init = false; + static Behaviour beh; + if( !init ) { + beh.d->actions[ UseGui ] = true; + beh.d->actions[ UseCrypto ] = false; + beh.d->actions[ UseWrapping ] = false; + beh.d->actions[ UseFallbackCharset ] = false; + beh.d->actions[ WarnBadCharset ] = true; + beh.d->actions[ WarnZeroRecipients ] = false; + beh.d->actions[ CustomHeaders ] = true; + init = true; + } + return beh; +} + diff --git a/messagecomposer/behaviour.h b/messagecomposer/behaviour.h new file mode 100644 index 000000000..274b04bb1 --- /dev/null +++ b/messagecomposer/behaviour.h @@ -0,0 +1,95 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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 MESSAGECOMPOSER_BEHAVIOUR_H +#define MESSAGECOMPOSER_BEHAVIOUR_H + +#include "messagecomposer_export.h" + +#include + +namespace MessageComposer { + +/** +*/ +class MESSAGECOMPOSER_EXPORT Behaviour +{ + public: + enum Action + { + UseGui, + UseCrypto, + UseWrapping, + UseFallbackCharset, + WarnBadCharset, + WarnZeroRecipients, + CustomHeaders, + LastAction // TODO should this be made =100 for further expansion? + }; + + Behaviour(); + virtual ~Behaviour(); + + bool isActionEnabled( Action action ) const; + void enableAction( Action action, bool enable = true ); + void disableAction( Action action ); + + static Behaviour behaviourForSending(); + static Behaviour behaviourForPrinting(); + static Behaviour behaviourForAutosaving(); + static Behaviour behaviourForSavingLocally(); + + private: + class Private; + QSharedDataPointer d; +}; + +/* + FIXME + I can't figure out how else to make this work. If I put it in the cpp or in another + file like behaviour_p.h, I get 'incomplete type' errors. If I put it in behavior_p.h + and include it in the bottom, I need to install the _p anyway. + The problem seems to be that Behaviour needs Behaviour::Private (for QSharedDataPointer), + but Behaviour::Private needs Behaviour back (for Behaviour:LastAction). + -> I removed the latter dependency and the problem persists :-/ +*/ +/** + @internal +*/ +class Behaviour::Private : public QSharedData +{ + public: + Private() + { + } + + Private( const Private &other ) + : QSharedData( other ) + { + for( int i = 0; i < Behaviour::LastAction; i++ ) { + actions[i] = other.actions[i]; + } + } + + bool actions[ Behaviour::LastAction ]; +}; + +} + +#endif diff --git a/messagecomposer/behaviour_p.h b/messagecomposer/behaviour_p.h new file mode 100644 index 000000000..34dcf87af --- /dev/null +++ b/messagecomposer/behaviour_p.h @@ -0,0 +1,33 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include + +#ifndef MESSAGECOMPOSER_BEHAVIOUR_P_H +#define MESSAGECOMPOSER_BEHAVIOUR_P_H + +namespace MessageComposer { + +/** + @internal +*/ + +} + +#endif diff --git a/messagecomposer/composer.cpp b/messagecomposer/composer.cpp new file mode 100644 index 000000000..ebf6ffa0b --- /dev/null +++ b/messagecomposer/composer.cpp @@ -0,0 +1,374 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "composer.h" + +#include "attachmentpart.h" +#include "finalmessage_p.h" +#include "infopart.h" +#include "textpart.h" +#include "maintextjob.h" +#include "multipartjob.h" +#include "skeletonmessagejob.h" + +#include + +#include + +using namespace MessageComposer; +using namespace KMime; + +class Composer::Private +{ + public: + Private( Composer *qq ) + : q( qq ) + , started( false ) + , finished( false ) + , parentWidget( 0 ) + , infoPart( new InfoPart( q ) ) + , textPart( new TextPart( q ) ) + , skeletonMessage( 0 ) + , contentBeforeCrypto( 0 ) +#if 0 + , pendingCryptoJobs( 0 ) +#endif + { + } + + void doStart(); // slot + void composeStep1(); + void splitAttachmentsIntoEarlyLate(); + void skeletonJobFinished( KJob *job ); // slot + void composeStep2(); + void beforeCryptoJobFinished( KJob *job ); // slot + void composeStep3(); + FinalMessage *createFinalMessage( Content *content ); + + Composer *q; + Behaviour behaviour; + bool started; + bool finished; + FinalMessage::List messages; + + // Stuff that the application plays with. + QWidget *parentWidget; + InfoPart *infoPart; + TextPart *textPart; + AttachmentPart::List attachmentParts; + + // Stuff that we play with. + AttachmentPart::List earlyAttachments; + AttachmentPart::List lateAttachments; + Message *skeletonMessage; + Content *contentBeforeCrypto; + // TODO crypto: for each resulting message, keep track of its recipient. + // See keyresolver in kmail... + // We need a structure to keep track of a recipient (list) as well as type + // (to or cc or bcc), and createFinalMessage needs to honour it. +#if 0 + int pendingCryptoJobs; + QList contentsAfterCrypto; +#endif +}; + +void Composer::Private::doStart() +{ + Q_ASSERT( !started ); + started = true; + composeStep1(); +} + +void Composer::Private::composeStep1() +{ + // Split the attachments into early and late. (see DESIGN) + splitAttachmentsIntoEarlyLate(); + + // Create skeleton message (containing headers only; no content). + SkeletonMessageJob *skeletonJob = new SkeletonMessageJob( infoPart, q ); + connect( skeletonJob, SIGNAL(finished(KJob*)), q, SLOT(skeletonJobFinished(KJob*)) ); + q->addSubjob( skeletonJob ); + skeletonJob->start(); +} + +void Composer::Private::splitAttachmentsIntoEarlyLate() +{ + // TODO + earlyAttachments = attachmentParts; +} + +void Composer::Private::skeletonJobFinished( KJob *job ) +{ + if( job->error() ) { + return; // KCompositeJob takes care of the error. + } + + Q_ASSERT( dynamic_cast( job ) ); + SkeletonMessageJob *sjob = static_cast( job ); + // SkeletonMessageJob is a special job creating a Message instead of a Content. + Q_ASSERT( skeletonMessage == 0 ); + skeletonMessage = sjob->message(); + Q_ASSERT( skeletonMessage ); + skeletonMessage->assemble(); + kDebug() << "encoded content of skeleton" << skeletonMessage->encodedContent(); + + composeStep2(); +} + +void Composer::Private::composeStep2() +{ + Job *beforeCryptoJob = 0; + // Create contentBeforeCrypto from the main text part and early attachments. + if( earlyAttachments.isEmpty() ) { + // We have no attachments. Use whatever content the textPart gives us. + beforeCryptoJob = new MainTextJob( textPart, q ); + } else { + // We have attachments. Create a multipart/mixed content. + // TODO + Q_ASSERT( false ); +#if 0 + beforeCryptoJob = new MultipartJob( q ); + beforeCryptoJob->setMultipartSubtype( "mixed" ); + new MainTextJob( textPart, beforeCryptoJob ); + foreach( AttachmentPart *part, earlyAttachments ) { + new AttachmentJob( part, beforeCryptoJob ); + } +#endif + } + connect( beforeCryptoJob, SIGNAL(finished(KJob*)), q, SLOT(beforeCryptoJobFinished(KJob*)) ); + q->addSubjob( beforeCryptoJob ); + beforeCryptoJob->start(); +} + +void Composer::Private::beforeCryptoJobFinished( KJob *job ) +{ + if( job->error() ) { + return; // KCompositeJob takes care of the error. + } + + Q_ASSERT( dynamic_cast( job ) ); + Job *cjob = static_cast( job ); + contentBeforeCrypto = cjob->content(); + contentBeforeCrypto->assemble(); + + composeStep3(); +} + +void Composer::Private::composeStep3() +{ + // (temporary until crypto) Compose final message. + FinalMessage *msg = createFinalMessage( contentBeforeCrypto ); + delete contentBeforeCrypto; + contentBeforeCrypto = 0; + messages << msg; + kDebug() << "Finished composing the single lousy unencrypted message."; + finished = true; + q->emitResult(); + +#if 0 + // The contentBeforeCrypto is done; now create contentsAfterCrypto. + QList afterCryptoJobs = createAfterCryptoJobs(); + pendingCryptoJobs = afterCryptoJobs.count(); + foreach( const Job *cryptoJob, afterCryptoJobs ) { + connect( cryptoJob, SIGNAL(finished(KJob*)), q, SLOT(afterCryptoJobFinished(KJob*)) ); + cryptoJob->start(); + } +#endif +} + +#if 0 +void Composer::Private::afterCryptoJobFinished( KJob *job ) +{ + if( job->error() ) { + return; // KCompositeJob takes care of the error. + } + + Q_ASSERT( dynamic_cast( job ) ); + Job *cryptoJob = static_cast( job ); + contentsAfterCrypto << cryptoJob->content(); + pendingCryptoJobs--; + Q_ASSERT( pendingCryptoJobs >= 0 ); + if( pendingCryptoJobs == 0 ) { + // All contentsAfterCrypto are done; now add the late attachments. + } +} +#endif + +FinalMessage *Composer::Private::createFinalMessage( Content *content ) +{ + Q_ASSERT( skeletonMessage ); + Message *message = new Message; + // Merge the headers from skeletonMessage with the headers + content + // of beforeCryptoJobFinished. FIXME HACK There should be a better way. + QByteArray allData = skeletonMessage->head() + content->encodedContent(); + message->setContent( allData ); +#if 0 // this was the second attempt + QByteArray head = skeletonMessage->head() + content->head(); + kDebug() << "head" << head; + QByteArray body = content->body(); + kDebug() << "body" << body; + message->setHead( head ); + message->setBody( body ); + + // With the above, for some reason the CTE thinks it has already encoded + // the content, and so we get non-encoded content :-/ +#endif +#if 0 // this was the first attempt + // Copy the content. FIXME There should be an easier way. + content->assemble(); + message->setContent( content->encodedContent() ); + kDebug() << "encoded content" << content->encodedContent(); + + // Extract the headers from the skeletonMessage and copy them. + // FIXME There should be an easier way. + QByteArray head = skeletonMessage->head(); + while( true ) { + Headers::Base *header = skeletonMessage->nextHeader( head ); // Shouldn't this be static? + if( !header ) { + break; + } + kDebug() << "header from skeleton" << header->as7BitString(); + message->setHeader( header ); + header->setParent( message ); + kDebug() << "created header @" << header; + + // The above SIGSEGVs for a reason I don't understand. + // (when Akonadi tries to serialize the item) + } +#endif + + // Assemble the FinalMessage. +#if 0 // part of 2nd attempt debugging + //message->parse(); + { + kDebug() << "for the bloody content:"; + Headers::ContentTransferEncoding *cte = content->contentTransferEncoding( false ); + kDebug() << "CTE" << (cte ? cte->as7BitString() : "NULL"); + if( cte ) { + kDebug() << "decoded" << cte->decoded() << "needToEncode" << cte->needToEncode(); + } + } + { + kDebug() << "for the bloody message:"; + Headers::ContentTransferEncoding *cte = message->contentTransferEncoding( false ); + kDebug() << "CTE" << (cte ? cte->as7BitString() : "NULL"); + if( cte ) { + kDebug() << "decoded" << cte->decoded() << "needToEncode" << cte->needToEncode(); + } + } +#endif + message->assemble(); + kDebug() << "encoded message after assembly" << message->encodedContent(); + FinalMessage *finalMessage = new FinalMessage( message ); + finalMessage->d->hasCustomHeaders = false; // TODO save those if not sending... + finalMessage->d->transportId = infoPart->transportId(); + + // TODO will need to change this for crypto... + finalMessage->d->from = infoPart->from(); + finalMessage->d->to = infoPart->to(); + finalMessage->d->cc = infoPart->cc(); + finalMessage->d->bcc = infoPart->bcc(); + + return finalMessage; +} + + + +Composer::Composer( QObject *parent ) + : KCompositeJob( parent ) + , d( new Private( this ) ) +{ +} + +Composer::~Composer() +{ + delete d; +} + +Behaviour &Composer::behaviour() +{ + return d->behaviour; +} + +void Composer::setBehaviour( const Behaviour &beh ) +{ + d->behaviour = beh; +} + +QWidget *Composer::parentWidget() const +{ + return d->parentWidget; +} + +void Composer::setParentWidget( QWidget *widget ) +{ + d->parentWidget = widget; +} + +FinalMessage::List Composer::messages() const +{ + Q_ASSERT( d->finished ); + Q_ASSERT( !error() ); + return d->messages; +} + +InfoPart *Composer::infoPart() +{ + return d->infoPart; +} + +TextPart *Composer::textPart() +{ + return d->textPart; +} + +QList Composer::attachmentParts() +{ + return d->attachmentParts; +} + +void Composer::addAttachmentPart( AttachmentPart *part ) +{ + Q_ASSERT( !d->started ); + Q_ASSERT( !d->attachmentParts.contains( part ) ); + d->attachmentParts.append( part ); +} + +void Composer::removeAttachmentPart( AttachmentPart *part, bool del ) +{ + Q_ASSERT( !d->started ); + if( d->attachmentParts.contains( part ) ) { + d->attachmentParts.removeAll( part ); + } else { + kWarning() << "Unknown attachment part" << part; + Q_ASSERT( false ); + return; + } + + if( del ) { + delete part; + } +} + +void Composer::start() +{ + QTimer::singleShot( 0, this, SLOT(doStart()) ); +} + +#include "composer.moc" diff --git a/messagecomposer/composer.h b/messagecomposer/composer.h new file mode 100644 index 000000000..1d8d5dc19 --- /dev/null +++ b/messagecomposer/composer.h @@ -0,0 +1,83 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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 MESSAGECOMPOSER_COMPOSER_H +#define MESSAGECOMPOSER_COMPOSER_H + +#include "attachmentpart.h" +#include "behaviour.h" +#include "finalmessage.h" +#include "job.h" +#include "messagecomposer_export.h" + +#include +#include + +#include + +namespace MessageComposer { + +class InfoPart; +class TextPart; + +/** + The message composer. +*/ +class MESSAGECOMPOSER_EXPORT Composer : public KCompositeJob +{ + Q_OBJECT + + public: + // TODO figure out how to share Job::Error (See PLAN). + + explicit Composer( QObject *parent = 0 ); + virtual ~Composer(); + + Behaviour &behaviour(); + void setBehaviour( const Behaviour &beh ); + QWidget *parentWidget() const; // TODO make this part of Behaviour?? + void setParentWidget( QWidget *widget ); + FinalMessage::List messages() const; + + InfoPart *infoPart(); + //void setInfoPart( InfoPart *part, bool delOldPart = true ); + TextPart *textPart(); + //void setTextPart( TextPart *part, bool delOldPart = true ); + // TODO figure out how to make this extensible... + // and how to handle d->composer in MessagePart... + AttachmentPart::List attachmentParts(); + void addAttachmentPart( AttachmentPart *part ); + void removeAttachmentPart( AttachmentPart *part, bool del = true ); + + public Q_SLOTS: + virtual void start(); + + private: + class Private; + friend class Private; + Private *const d; + + Q_PRIVATE_SLOT( d, void doStart() ) + Q_PRIVATE_SLOT( d, void skeletonJobFinished(KJob*) ) + Q_PRIVATE_SLOT( d, void beforeCryptoJobFinished(KJob*) ) +}; + +} + +#endif diff --git a/messagecomposer/contentjob.cpp b/messagecomposer/contentjob.cpp new file mode 100644 index 000000000..7ae8bca27 --- /dev/null +++ b/messagecomposer/contentjob.cpp @@ -0,0 +1,112 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "contentjob.h" +#include "job_p.h" + +#include + +#include +#include + +using namespace MessageComposer; +using namespace KMime; + +class MessageComposer::ContentJobPrivate : public JobPrivate +{ + public: + ContentJobPrivate( ContentJob *qq ) + : JobPrivate( qq ) + , contentTransferEncoding( 0 ) + , contentType( 0 ) + { + } + + QByteArray data; + Headers::ContentTransferEncoding *contentTransferEncoding; + Headers::ContentType *contentType; +}; + +ContentJob::ContentJob( QObject *parent ) + : Job( *new ContentJobPrivate( this ), parent ) +{ +} + +ContentJob::~ContentJob() +{ +} + +QByteArray ContentJob::data() const +{ + Q_D( const ContentJob ); + return d->data; +} + +void ContentJob::setData( const QByteArray &data ) +{ + Q_D( ContentJob ); + d->data = data; +} + +Headers::ContentTransferEncoding *ContentJob::contentTransferEncoding() +{ + Q_D( ContentJob ); + if( !d->contentTransferEncoding ) { + d->contentTransferEncoding = new Headers::ContentTransferEncoding; + } + return d->contentTransferEncoding; +} + +Headers::ContentType *ContentJob::contentType() +{ + Q_D( ContentJob ); + if( !d->contentType ) { + d->contentType = new Headers::ContentType; + } + return d->contentType; +} + +void ContentJob::process() +{ + Q_D( ContentJob ); + Q_ASSERT( d->resultContent == 0 ); // Not processed before. + d->resultContent = new Content; + + // Headers. + if( d->contentTransferEncoding ) { + d->resultContent->setHeader( d->contentTransferEncoding ); + d->contentTransferEncoding->setParent( d->resultContent ); + + kDebug() << "decoded" << d->contentTransferEncoding->decoded() + << "needToEncode" << d->contentTransferEncoding->needToEncode(); + } + if( d->contentType ) { + d->resultContent->setHeader( d->contentType ); + d->contentType->setParent( d->resultContent ); + } + + // Data. + d->resultContent->setBody( d->data ); + + kDebug() << "encoded content" << d->resultContent->encodedContent(); + + emitResult(); +} + +#include "contentjob.moc" diff --git a/messagecomposer/contentjob.h b/messagecomposer/contentjob.h new file mode 100644 index 000000000..268afa80e --- /dev/null +++ b/messagecomposer/contentjob.h @@ -0,0 +1,63 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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 MESSAGECOMPOSER_CONTENTJOB_H +#define MESSAGECOMPOSER_CONTENTJOB_H + +#include "job.h" +#include "messagecomposer_export.h" + +namespace KMime { + namespace Headers { + class ContentTransferEncoding; + class ContentType; + } +} + +namespace MessageComposer { + +class ContentJobPrivate; + +/** +*/ +class MESSAGECOMPOSER_EXPORT ContentJob : public Job +{ + Q_OBJECT + + public: + ContentJob( QObject *parent = 0 ); + virtual ~ContentJob(); + + QByteArray data() const; + void setData( const QByteArray &data ); + + /// created on first call. delete them if you don't use the content + KMime::Headers::ContentTransferEncoding *contentTransferEncoding(); + KMime::Headers::ContentType *contentType(); + + protected Q_SLOTS: + virtual void process(); + + private: + Q_DECLARE_PRIVATE( ContentJob ) +}; + +} + +#endif diff --git a/messagecomposer/finalmessage.cpp b/messagecomposer/finalmessage.cpp new file mode 100644 index 000000000..9b5a61991 --- /dev/null +++ b/messagecomposer/finalmessage.cpp @@ -0,0 +1,73 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "finalmessage.h" +#include "finalmessage_p.h" + +using namespace KMime; +using namespace MessageComposer; + +FinalMessage::FinalMessage( Message *message ) + : d( new Private ) +{ + d->message = Message::Ptr( message ); + d->hasCustomHeaders = false; + d->transportId = -1; +} + +FinalMessage::~FinalMessage() +{ + delete d; +} + +Message::Ptr FinalMessage::message() const +{ + return d->message; +} + +int FinalMessage::transportId() const +{ + return d->transportId; +} + +bool FinalMessage::hasCustomHeaders() const +{ + return d->hasCustomHeaders; +} + +QString FinalMessage::from() const +{ + return d->from; +} + +QStringList FinalMessage::to() const +{ + return d->to; +} + +QStringList FinalMessage::cc() const +{ + return d->cc; +} + +QStringList FinalMessage::bcc() const +{ + return d->bcc; +} + diff --git a/messagecomposer/finalmessage.h b/messagecomposer/finalmessage.h new file mode 100644 index 000000000..c7274506f --- /dev/null +++ b/messagecomposer/finalmessage.h @@ -0,0 +1,62 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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 MESSAGECOMPOSER_FINALMESSAGE_H +#define MESSAGECOMPOSER_FINALMESSAGE_H + +#include "messagecomposer_export.h" + +#include +#include + +#include +#include + +namespace MessageComposer { + +class Composer; + +/** +*/ +class MESSAGECOMPOSER_EXPORT FinalMessage +{ + public: + typedef QList List; + + KMime::Message::Ptr message() const; + int transportId() const; + bool hasCustomHeaders() const; + QString from() const; + QStringList to() const; + QStringList cc() const; + QStringList bcc() const; + + private: + // Only used by our friend the Composer. + friend class Composer; + explicit FinalMessage( KMime::Message *message = 0 ); + virtual ~FinalMessage(); + + class Private; + Private *const d; +}; + +} + +#endif diff --git a/messagecomposer/finalmessage_p.h b/messagecomposer/finalmessage_p.h new file mode 100644 index 000000000..8ce0f2352 --- /dev/null +++ b/messagecomposer/finalmessage_p.h @@ -0,0 +1,47 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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 MESSAGECOMPOSER_FINALMESSAGE_P_H +#define MESSAGECOMPOSER_FINALMESSAGE_P_H + +#include + +#include +#include + +namespace MessageComposer { + +/** + @internal +*/ +class FinalMessage::Private +{ + public: + bool hasCustomHeaders; + KMime::Message::Ptr message; + int transportId; + QString from; + QStringList to; + QStringList cc; + QStringList bcc; +}; + +} + +#endif diff --git a/messagecomposer/infopart.cpp b/messagecomposer/infopart.cpp new file mode 100644 index 000000000..9756b6db7 --- /dev/null +++ b/messagecomposer/infopart.cpp @@ -0,0 +1,107 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "infopart.h" + +using namespace MessageComposer; + +class InfoPart::Private +{ + public: + QString from; + QStringList to; + QStringList cc; + QStringList bcc; + QString subject; + int transportId; +}; + +InfoPart::InfoPart( QObject *parent ) + : MessagePart( parent ) + , d( new Private ) +{ + d->transportId = 0; +} + +InfoPart::~InfoPart() +{ + delete d; +} + +QString InfoPart::from() const +{ + return d->from; +} + +void InfoPart::setFrom( const QString &from ) +{ + d->from = from; +} + +QStringList InfoPart::to() const +{ + return d->to; +} + +void InfoPart::setTo( const QStringList &to ) +{ + d->to = to; +} + +QStringList InfoPart::cc() const +{ + return d->cc; +} + +void InfoPart::setCc( const QStringList &cc ) +{ + d->cc = cc; +} + +QStringList InfoPart::bcc() const +{ + return d->bcc; +} + +void InfoPart::setBcc( const QStringList &bcc ) +{ + d->bcc = bcc; +} + +QString InfoPart::subject() const +{ + return d->subject; +} + +void InfoPart::setSubject( const QString &subject ) +{ + d->subject = subject; +} + +int InfoPart::transportId() const +{ + return d->transportId; +} + +void InfoPart::setTransportId( int tid ) +{ + d->transportId = tid; +} + +#include "infopart.moc" diff --git a/messagecomposer/infopart.h b/messagecomposer/infopart.h new file mode 100644 index 000000000..bb4ccc081 --- /dev/null +++ b/messagecomposer/infopart.h @@ -0,0 +1,62 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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 MESSAGECOMPOSER_INFOPART_H +#define MESSAGECOMPOSER_INFOPART_H + +#include "messagepart.h" + +#include + +#include +#include + +namespace MessageComposer { + +class MESSAGECOMPOSER_EXPORT InfoPart : public MessagePart +{ + Q_OBJECT + + public: + explicit InfoPart( QObject *parent = 0 ); + virtual ~InfoPart(); + + QString from() const; + void setFrom( const QString &from ); + QStringList to() const; + void setTo( const QStringList &to ); + QStringList cc() const; + void setCc( const QStringList &cc ); + QStringList bcc() const; + void setBcc( const QStringList &bcc ); + + QString subject() const; + void setSubject( const QString &subject ); + + int transportId() const; + void setTransportId( int tid ); + + private: + class Private; + Private *const d; +}; + +} // namespace MessageComposer + +#endif // MESSAGECOMPOSER_INFOPART_H diff --git a/messagecomposer/job.cpp b/messagecomposer/job.cpp new file mode 100644 index 000000000..64e0e5425 --- /dev/null +++ b/messagecomposer/job.cpp @@ -0,0 +1,125 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "job.h" +#include "job_p.h" + +#include "composer.h" + +#include + +#include + +#include + +using namespace MessageComposer; +using namespace KMime; + +void JobPrivate::init( QObject *parent ) +{ + Composer *parentComposer = dynamic_cast( parent ); + if( parentComposer ) { + composer = parentComposer; + return; + } + + Job *parentJob = dynamic_cast( parent ); + if( parentJob ) { + composer = parentJob->d_ptr->composer; + parentJob->addSubjob( q_ptr ); + return; + } + + composer = 0; +} + +void JobPrivate::doNextSubjob() +{ + Q_Q( Job ); + if( q->hasSubjobs() ) { + q->subjobs().first()->start(); + } else { + kDebug() << "Calling process."; + q->process(); + } +} + + + +Job::Job( QObject *parent ) + : KCompositeJob( parent ) + , d_ptr( new JobPrivate( this ) ) +{ + d_ptr->init( parent ); +} + +Job::Job( JobPrivate &dd, QObject *parent ) + : KCompositeJob( parent ) + , d_ptr( &dd ) +{ + d_ptr->init( parent ); +} + +Job::~Job() +{ + delete d_ptr; +} + +void Job::start() +{ + QTimer::singleShot( 0, this, SLOT(doStart()) ); +} + +Content *Job::content() const +{ + Q_D( const Job ); + //Q_ASSERT( !hasSubjobs() ); // Finished. // KCompositeJob::hasSubjobs is not const :-/ + Q_ASSERT( d->resultContent ); // process() should do something. + return d->resultContent; +} + +void Job::doStart() +{ + Q_D( Job ); + Q_ASSERT( d->resultContent == 0 && d->subjobContents.isEmpty() ); // Not started. + Q_ASSERT( !error() ); // Jobs emitting an error in doStart should not call Job::doStart(). + d->doNextSubjob(); +} + +void Job::slotResult( KJob *job ) +{ + Q_D( Job ); + KCompositeJob::slotResult( job ); // Handles errors and removes subjob. + kDebug() << "A subjob finished." << subjobs().count() << "more to go."; + if( error() ) { + return; + } + + Q_ASSERT( dynamic_cast( job ) ); + Job *cjob = static_cast( job ); + d->subjobContents.append( cjob->content() ); + d->doNextSubjob(); +} + +void Job::setComposer( Composer *composer ) +{ + d_ptr->composer = composer; +} + +#include "job.moc" diff --git a/messagecomposer/job.h b/messagecomposer/job.h new file mode 100644 index 000000000..9470b75d1 --- /dev/null +++ b/messagecomposer/job.h @@ -0,0 +1,102 @@ +/* + Copyright (c) 2009 Constantin Berzan + Based on ideas by Stephen Kelly. + + 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 MESSAGECOMPOSER_JOB_H +#define MESSAGECOMPOSER_JOB_H + +#include "messagecomposer_export.h" + +#include + +#include + +namespace KMime { + class Content; +} + +namespace MessageComposer { + +class Composer; +class JobPrivate; + +class MESSAGECOMPOSER_EXPORT Job : public KCompositeJob +{ + Q_OBJECT + + public: + typedef QList List; + + enum Error + { + BugError = UserDefinedError + 1, + IncompleteError, + UserCancelledError, + UserError = UserDefinedError + 42 + }; + + explicit Job( QObject *parent = 0 ); + virtual ~Job(); + + /** + Starts processing this Job asynchronously. + This processes all children in order first, then calls process(). + Emits finished() after all processing is done, and the + content is reachable through content(). + */ + virtual void start(); + + /** + Get the resulting KMime::Content that the Job has generated. + Jobs never delete their content. + */ + KMime::Content *content() const; + + protected: + JobPrivate *const d_ptr; + Job( JobPrivate &dd, QObject *parent ); + + protected Q_SLOTS: + /** + Reimplement to do additional stuff before processing children, such as + adding more subjobs. Remember to call the base implementation. + */ + virtual void doStart(); + + /** + This is called after all the children have been processed. + (You must use their resulting contents, or delete them.) + Reimplement in subclasses to process concrete content. Call + emitResult() when finished. + */ + virtual void process() = 0; + + /* reimpl */ + virtual void slotResult( KJob *job ); + + private: + friend class Composer; + void setComposer( Composer *composer ); + + Q_DECLARE_PRIVATE( Job ) +}; + +} // namespace MessageComposer + +#endif diff --git a/messagecomposer/job_p.h b/messagecomposer/job_p.h new file mode 100644 index 000000000..9d054dd89 --- /dev/null +++ b/messagecomposer/job_p.h @@ -0,0 +1,58 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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 MESSAGECOMPOSER_JOB_P_H +#define MESSAGECOMPOSER_JOB_P_H + +#include "job.h" + +#include + +namespace MessageComposer { + +class Composer; + +class JobPrivate +{ + public: + JobPrivate( Job *qq ) + : composer( 0 ) + , resultContent( 0 ) + , q_ptr( qq ) + { + } + + virtual ~JobPrivate() + { + } + + void init( QObject *parent ); + void doNextSubjob(); + + Composer *composer; + KMime::Content *resultContent; + KMime::Content::List subjobContents; + + Job *q_ptr; + Q_DECLARE_PUBLIC( Job ) +}; + +} + +#endif diff --git a/messagecomposer/maintextjob.cpp b/messagecomposer/maintextjob.cpp new file mode 100644 index 000000000..f16a0a3ab --- /dev/null +++ b/messagecomposer/maintextjob.cpp @@ -0,0 +1,251 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "maintextjob.h" + +#include "composer.h" +#include "contentjob.h" +#include "job_p.h" +#include "textpart.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include + +using namespace MessageComposer; +using namespace KMime; + +class MessageComposer::MainTextJobPrivate : public JobPrivate +{ + public: + MainTextJobPrivate( MainTextJob *qq ) + : JobPrivate( qq ) + , textPart( 0 ) + { + } + + bool chooseCharsetAndEncode(); + bool chooseCharset(); + void encodeTexts(); + + TextPart *textPart; + QList charsets; + QByteArray chosenCharset; + QString sourcePlainText; + QByteArray encodedPlainText; + QByteArray encodedHtml; + + // TODO related images + + Q_DECLARE_PUBLIC( MainTextJob ) +}; + +bool MainTextJobPrivate::chooseCharsetAndEncode() +{ + Q_Q( MainTextJob ); + Q_ASSERT( composer ); + const Behaviour &beh = composer->behaviour(); + + Q_ASSERT( textPart ); + charsets = textPart->charsets(); + foreach( const QByteArray &name, textPart->charsets() ) { + charsets << name.toLower(); + } + if( beh.isActionEnabled( Behaviour::UseFallbackCharset ) ) { + charsets << "utf-8"; + // TODO somehow save the chosen charset in a custom header if behaviour allows it... + } + Q_ASSERT( !charsets.isEmpty() ); + + if( chooseCharset() ) { + // Good, one of the charsets can encode the data without loss. + encodeTexts(); + return true; + } else { + // No good charset was found. + if( beh.isActionEnabled( Behaviour::UseGui ) && + beh.isActionEnabled( Behaviour::WarnBadCharset ) ) { + // Warn the user and give them a chance to go back. + int result = KMessageBox::warningYesNo( + composer->parentWidget(), + i18n( "Encoding the message with %1 will lose some characters.\n" + "Do you want to continue?", QString::fromLatin1( charsets.first() ) ), + i18n( "Some Characters Will Be Lost" ), + KGuiItem( i18n("Lose Characters") ), + KGuiItem( i18n("Change Encoding") ) + ); + if( result == KMessageBox::No ) { + q->setError( Job::UserCancelledError ); + q->setErrorText( i18n( "User decided to change the encoding." ) ); + return false; + } else { + chosenCharset = charsets.first(); + encodeTexts(); + return true; + } + } else if( beh.isActionEnabled( Behaviour::WarnBadCharset ) ) { + // Should warn user but no Gui available. + kDebug() << "WarnBadCharset but not UseGui."; + q->setError( Job::UserError ); + q->setErrorText( i18n( "The selected encoding (%1) cannot fully encode the message.", + QString::fromLatin1( charsets.first() ) ) ); + return false; + } else { + // OK to go ahead with a bad charset. + chosenCharset = charsets.first(); + encodeTexts(); + return true; + + // FIXME: This is based on the assumption that QTextCodec will replace + // unknown characters with '?' or some other meaningful thing. The code in + // QTextCodec indeed uses '?', but this behaviour is not documented. + } + } + + // Should not reach here. + Q_ASSERT( false ); + return false; +} + +bool MainTextJobPrivate::chooseCharset() +{ + Q_ASSERT( !charsets.isEmpty() ); + Q_ASSERT( textPart ); + QString toTry = sourcePlainText; + if( textPart->isHtmlUsed() ) { + toTry = textPart->cleanHtml(); + } + foreach( const QByteArray &name, charsets ) { + // We use KCharsets::codecForName() instead of QTextCodec::codecForName() here, because + // the former knows us-ascii is latin1. + QTextCodec *codec = KGlobal::charsets()->codecForName( name ); + if( !codec ) { + kWarning() << "Could not get text codec for charset" << name; + continue; + } + if( codec->canEncode( toTry ) ) { + // Special check for us-ascii (needed because us-ascii is not exactly latin1). + if( name == "us-ascii" && !isUsAscii( toTry ) ) { + continue; + } + kDebug() << "Chosen charset" << name; + chosenCharset = name; + return true; + } + } + kDebug() << "No appropriate charset found."; + return false; +} + +void MainTextJobPrivate::encodeTexts() +{ + Q_Q( MainTextJob ); + QTextCodec *codec = KGlobal::charsets()->codecForName( chosenCharset ); + if( !codec ) { + kError() << "Could not get text codec for charset" << chosenCharset; + q->setError( Job::BugError ); + q->setErrorText( i18n( "Could not get text codec for charset \"%1\".", QString::fromLatin1( chosenCharset ) ) ); + return; + } + encodedPlainText = codec->fromUnicode( sourcePlainText ); + encodedHtml = codec->fromUnicode( textPart->cleanHtml() ); + kDebug() << "Done."; +} + + + +MainTextJob::MainTextJob( TextPart *textPart, QObject *parent ) + : Job( *new MainTextJobPrivate( this ), parent ) +{ + Q_D( MainTextJob ); + d->textPart = textPart; +} + +MainTextJob::~MainTextJob() +{ +} + +TextPart *MainTextJob::textPart() const +{ + Q_D( const MainTextJob ); + return d->textPart; +} + +void MainTextJob::setTextPart( TextPart *part ) +{ + Q_D( MainTextJob ); + d->textPart = part; +} + +void MainTextJob::doStart() +{ + Q_D( MainTextJob ); + Q_ASSERT( d->textPart ); + Q_ASSERT( d->composer ); + + // Word wrapping. + if( d->composer->behaviour().isActionEnabled( Behaviour::UseWrapping ) ) { + d->sourcePlainText = d->textPart->wrappedPlainText(); + } else { + d->sourcePlainText = d->textPart->cleanPlainText(); + } + + // Charset. + if( d->chooseCharsetAndEncode() ) { + // Encoding was successful. The user and we are happy with the charset, even if it may + // lose characters. + if( d->encodedHtml.isEmpty() ) { + kDebug() << "Making text/plain"; + // Content is text/plain. + ContentJob *cjob = new ContentJob( this ); + cjob->contentType()->setMimeType( "text/plain" ); + cjob->contentType()->setCharset( d->chosenCharset ); + cjob->setData( d->encodedPlainText ); + + // TODO temporary until I figure out what the CTE policy is. + cjob->contentTransferEncoding()->setEncoding( Headers::CEquPr ); + } else { + // TODO Handle multipart/alternative and multipart/related. + Q_ASSERT( false ); + } + Job::doStart(); + } else { + // chooseCharsetAndEncode has set an error. + Q_ASSERT( error() ); + emitResult(); + } +} + +void MainTextJob::process() +{ + Q_D( MainTextJob ); + // The content has been created by our subjob. + Q_ASSERT( d->subjobContents.count() == 1 ); + d->resultContent = d->subjobContents.first(); + emitResult(); +} + +#include "maintextjob.moc" diff --git a/messagecomposer/maintextjob.h b/messagecomposer/maintextjob.h new file mode 100644 index 000000000..3b2b45cb7 --- /dev/null +++ b/messagecomposer/maintextjob.h @@ -0,0 +1,53 @@ +/* + Copyright (c) 2009 Constantin Berzan + Based on ideas by Stephen Kelly. + + 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 MESSAGECOMPOSER_MAINTEXTJOB_H +#define MESSAGECOMPOSER_MAINTEXTJOB_H + +#include "job.h" +#include "messagecomposer_export.h" + +namespace MessageComposer { + +class MainTextJobPrivate; +class TextPart; + +class MESSAGECOMPOSER_EXPORT MainTextJob : public Job +{ + Q_OBJECT + + public: + explicit MainTextJob( TextPart *textPart = 0, QObject *parent = 0 ); + virtual ~MainTextJob(); + + TextPart *textPart() const; + void setTextPart( TextPart *part ); + + protected Q_SLOTS: + virtual void doStart(); + virtual void process(); + + private: + Q_DECLARE_PRIVATE( MainTextJob ) +}; + +} // namespace MessageComposer + +#endif diff --git a/messagecomposer/messagecomposer_export.h b/messagecomposer/messagecomposer_export.h new file mode 100644 index 000000000..8e3c9c36f --- /dev/null +++ b/messagecomposer/messagecomposer_export.h @@ -0,0 +1,35 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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 MESSAGECOMPOSER_MESSAGECOMPOSER_EXPORT_H +#define MESSAGECOMPOSER_MESSAGECOMPOSER_EXPORT_H + +#include + +#ifndef MESSAGECOMPOSER_EXPORT +# if defined(MAKE_MESSAGECOMPOSER_LIB) + /* We are building this library */ +# define MESSAGECOMPOSER_EXPORT KDE_EXPORT +# else + /* We are using this library */ +# define MESSAGECOMPOSER_EXPORT KDE_IMPORT +# endif +#endif + +#endif diff --git a/messagecomposer/messagepart.cpp b/messagecomposer/messagepart.cpp new file mode 100644 index 000000000..d69a811a0 --- /dev/null +++ b/messagecomposer/messagepart.cpp @@ -0,0 +1,44 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "messagepart.h" + +#include + +using namespace MessageComposer; + +class MessagePart::Private +{ + public: +}; + + + +MessagePart::MessagePart( QObject *parent ) + : QObject( parent ) + , d( new Private ) +{ +} + +MessagePart::~MessagePart() +{ + delete d; +} + +#include "messagepart.moc" diff --git a/messagecomposer/messagepart.h b/messagecomposer/messagepart.h new file mode 100644 index 000000000..7cb3c6a5b --- /dev/null +++ b/messagecomposer/messagepart.h @@ -0,0 +1,49 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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 MESSAGECOMPOSER_MESSAGEPART_H +#define MESSAGECOMPOSER_MESSAGEPART_H + +#include "behaviour.h" +#include "messagecomposer_export.h" + +#include + +namespace MessageComposer { + +class MessagePartPrivate; + +/** +*/ +class MESSAGECOMPOSER_EXPORT MessagePart : public QObject +{ + Q_OBJECT + + public: + MessagePart( QObject *parent = 0 ); + virtual ~MessagePart(); + + private: + class Private; + Private *const d; +}; + +} + +#endif diff --git a/messagecomposer/multipartjob.cpp b/messagecomposer/multipartjob.cpp new file mode 100644 index 000000000..94c17c0ba --- /dev/null +++ b/messagecomposer/multipartjob.cpp @@ -0,0 +1,79 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "multipartjob.h" +#include "job_p.h" + +#include + +#include + +using namespace MessageComposer; +using namespace KMime; + +class MessageComposer::MultipartJobPrivate : public JobPrivate +{ + public: + MultipartJobPrivate( MultipartJob *qq ) + : JobPrivate( qq ) + { + } + + QByteArray subtype; + +}; + +MultipartJob::MultipartJob( QObject *parent ) + : Job( *new MultipartJobPrivate( this ), parent ) +{ +} + +MultipartJob::~MultipartJob() +{ +} + +QByteArray MultipartJob::multipartSubtype() const +{ + Q_D( const MultipartJob ); + return d->subtype; +} + +void MultipartJob::setMultipartSubtype( const QByteArray &subtype ) +{ + Q_D( MultipartJob ); + d->subtype = subtype; +} + +void MultipartJob::process() +{ + Q_D( MultipartJob ); + Q_ASSERT( d->resultContent == 0 ); // Not processed before. + Q_ASSERT( !d->subtype.isEmpty() ); + d->resultContent = new Content; + d->resultContent->contentType( true )->setMimeType( "multipart/" + d->subtype ); + d->resultContent->contentType()->setBoundary( KMime::multiPartBoundary() ); + foreach( Content *c, d->subjobContents ) { + d->resultContent->addContent( c ); + } + kDebug() << "Created" << d->resultContent->contentType()->name() << "content with" + << d->resultContent->contents().count() << "subjobContents."; + emitResult(); +} + +#include "multipartjob.moc" diff --git a/messagecomposer/multipartjob.h b/messagecomposer/multipartjob.h new file mode 100644 index 000000000..76821b060 --- /dev/null +++ b/messagecomposer/multipartjob.h @@ -0,0 +1,52 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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 MESSAGECOMPOSER_MULTIPARTJOB_H +#define MESSAGECOMPOSER_MULTIPARTJOB_H + +#include "job.h" +#include "messagecomposer_export.h" + +namespace MessageComposer { + +class MultipartJobPrivate; + +/** +*/ +class MESSAGECOMPOSER_EXPORT MultipartJob : public Job +{ + Q_OBJECT + + public: + MultipartJob( QObject *parent = 0 ); + virtual ~MultipartJob(); + + QByteArray multipartSubtype() const; + void setMultipartSubtype( const QByteArray &subtype ); + + protected Q_SLOTS: + virtual void process(); + + private: + Q_DECLARE_PRIVATE( MultipartJob ) +}; + +} + +#endif diff --git a/messagecomposer/skeletonmessagejob.cpp b/messagecomposer/skeletonmessagejob.cpp new file mode 100644 index 000000000..3e1f2bf74 --- /dev/null +++ b/messagecomposer/skeletonmessagejob.cpp @@ -0,0 +1,142 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "skeletonmessagejob.h" + +#include "infopart.h" +#include "job_p.h" +#include "textpart.h" + +#include + +#include +#include +#include + +#include + +using namespace MessageComposer; +using namespace KMime; + +class MessageComposer::SkeletonMessageJobPrivate : public JobPrivate +{ + public: + SkeletonMessageJobPrivate( SkeletonMessageJob *qq ) + : JobPrivate( qq ) + , infoPart( 0 ) + { + } + + InfoPart *infoPart; +}; + + + +SkeletonMessageJob::SkeletonMessageJob( InfoPart *infoPart, QObject *parent ) + : Job( *new SkeletonMessageJobPrivate( this ), parent ) +{ + Q_D( SkeletonMessageJob ); + d->infoPart = infoPart; +} + +SkeletonMessageJob::~SkeletonMessageJob() +{ +} + +InfoPart *SkeletonMessageJob::infoPart() const +{ + Q_D( const SkeletonMessageJob ); + return d->infoPart; +} + +void SkeletonMessageJob::setInfoPart( InfoPart *part ) +{ + Q_D( SkeletonMessageJob ); + d->infoPart = part; +} + +Message *SkeletonMessageJob::message() const +{ + Q_D( const SkeletonMessageJob ); + Q_ASSERT( d->resultContent ); + Q_ASSERT( dynamic_cast( d->resultContent ) ); + return static_cast( d->resultContent ); +} + +void SkeletonMessageJob::process() +{ + Q_D( SkeletonMessageJob ); + Q_ASSERT( d->infoPart ); + Q_ASSERT( d->subjobContents.isEmpty() ); // Cannot have subjobs. + Message *message = new Message; + + // From: + { + Headers::From *from = new Headers::From( message ); + Types::Mailbox address; + address.fromUnicodeString( d->infoPart->from() ); + from->addAddress( address ); + message->setHeader( from ); + } + + // To: + { + Headers::To *to = new Headers::To( message ); + foreach( const QString &a, d->infoPart->to() ) { + Types::Mailbox address; + address.fromUnicodeString( a ); + to->addAddress( address ); + } + message->setHeader( to ); + } + + // Cc: + { + Headers::Cc *cc = new Headers::Cc( message ); + foreach( const QString &a, d->infoPart->cc() ) { + Types::Mailbox address; + address.fromUnicodeString( a ); + cc->addAddress( address ); + } + message->setHeader( cc ); + } + + // Bcc: + { + Headers::Bcc *bcc = new Headers::Bcc( message ); + foreach( const QString &a, d->infoPart->bcc() ) { + Types::Mailbox address; + address.fromUnicodeString( a ); + bcc->addAddress( address ); + } + message->setHeader( bcc ); + } + + // Subject: + { + Headers::Subject *subject = new Headers::Subject( message ); + subject->fromUnicodeString( d->infoPart->subject(), QByteArray() ); // TODO charset?? + message->setHeader( subject ); + } + + d->resultContent = message; + emitResult(); +} + +#include "skeletonmessagejob.moc" diff --git a/messagecomposer/skeletonmessagejob.h b/messagecomposer/skeletonmessagejob.h new file mode 100644 index 000000000..b1b8eddd6 --- /dev/null +++ b/messagecomposer/skeletonmessagejob.h @@ -0,0 +1,63 @@ +/* + Copyright (c) 2009 Constantin Berzan + Based on ideas by Stephen Kelly. + + 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 MESSAGECOMPOSER_SKELETONMESSAGEJOB_H +#define MESSAGECOMPOSER_SKELETONMESSAGEJOB_H + +#include "job.h" +#include "messagecomposer_export.h" + +namespace KMime { + class Message; +} + +namespace MessageComposer { + +class SkeletonMessageJobPrivate; +class InfoPart; + +/** + A message containing only the headers... +*/ +class MESSAGECOMPOSER_EXPORT SkeletonMessageJob : public Job +{ + Q_OBJECT + + public: + explicit SkeletonMessageJob( InfoPart *infoPart = 0, QObject *parent = 0 ); + virtual ~SkeletonMessageJob(); + + InfoPart *infoPart() const; + void setInfoPart( InfoPart *part ); + + KMime::Message *message() const; + // TODO I think there is a way in C++ to make content() private, even if it's public + // in the base class. + + protected Q_SLOTS: + virtual void process(); + + private: + Q_DECLARE_PRIVATE( SkeletonMessageJob ) +}; + +} // namespace MessageComposer + +#endif diff --git a/messagecomposer/tests/CMakeLists.txt b/messagecomposer/tests/CMakeLists.txt new file mode 100644 index 000000000..a6cafe490 --- /dev/null +++ b/messagecomposer/tests/CMakeLists.txt @@ -0,0 +1,22 @@ +set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) + +# convenience macro to add messagecomposer unit tests +macro( add_messagecomposer_test _source ) + set( _test ${_source} ) + get_filename_component( _name ${_source} NAME_WE ) + kde4_add_unit_test( ${_name} TESTNAME messagecomposer-${_name} ${_test} ) + target_link_libraries( ${_name} kmime messagecomposer ${QT_QTTEST_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTCORE_LIBRARY} ${KDE4_KDEUI_LIBS} ) +endmacro( add_messagecomposer_test ) + + +# Utility stuff. +add_messagecomposer_test( behaviourtest.cpp ) + +# Basic jobs. +add_messagecomposer_test( contentjobtest.cpp ) +add_messagecomposer_test( multipartjobtest.cpp ) + +# More complex jobs. +add_messagecomposer_test( skeletonmessagejobtest.cpp ) + +# Composer. diff --git a/messagecomposer/tests/behaviourtest.cpp b/messagecomposer/tests/behaviourtest.cpp new file mode 100644 index 000000000..99e7d6843 --- /dev/null +++ b/messagecomposer/tests/behaviourtest.cpp @@ -0,0 +1,47 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "behaviourtest.h" + +#include + +#include +using namespace MessageComposer; + +QTEST_KDEMAIN( BehaviourTest, NoGUI ) + +void BehaviourTest::testApi() +{ + Behaviour beh; // Has sending behaviour by default. + QVERIFY( !beh.isActionEnabled( Behaviour::CustomHeaders ) ); + beh.enableAction( Behaviour::CustomHeaders ); + QVERIFY( beh.isActionEnabled( Behaviour::CustomHeaders ) ); + beh.enableAction( Behaviour::CustomHeaders, false ); + QVERIFY( !beh.isActionEnabled( Behaviour::CustomHeaders ) ); + beh.enableAction( Behaviour::CustomHeaders ); + QVERIFY( beh.isActionEnabled( Behaviour::CustomHeaders ) ); + beh.disableAction( Behaviour::CustomHeaders ); + QVERIFY( !beh.isActionEnabled( Behaviour::CustomHeaders ) ); + + Behaviour send = Behaviour::behaviourForSending(); + QCOMPARE( beh.isActionEnabled( Behaviour::CustomHeaders ), + send.isActionEnabled( Behaviour::CustomHeaders ) ); +} + +#include "behaviourtest.moc" diff --git a/messagecomposer/tests/behaviourtest.h b/messagecomposer/tests/behaviourtest.h new file mode 100644 index 000000000..2317b3f51 --- /dev/null +++ b/messagecomposer/tests/behaviourtest.h @@ -0,0 +1,32 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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 BEHAVIOURTEST_H +#define BEHAVIOURTEST_H + +#include + +class BehaviourTest : public QObject +{ + Q_OBJECT + private Q_SLOTS: + void testApi(); +}; + +#endif diff --git a/messagecomposer/tests/contentjobtest.cpp b/messagecomposer/tests/contentjobtest.cpp new file mode 100644 index 000000000..7816d6e8e --- /dev/null +++ b/messagecomposer/tests/contentjobtest.cpp @@ -0,0 +1,83 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "contentjobtest.h" + +#include +#include + +#include +using namespace KMime; + +#include +#include +using namespace MessageComposer; + +QTEST_KDEMAIN( ContentJobTest, NoGUI ) + +void ContentJobTest::testContent() +{ + Composer *composer = new Composer; + ContentJob *cjob = new ContentJob( composer ); + QByteArray data( "birds came flying from the underground"); + cjob->setData( data ); + QVERIFY( cjob->exec() ); + Content *result = cjob->content(); + result->assemble(); + kDebug() << result->encodedContent(); + QCOMPARE( result->body(), data ); + QVERIFY( result->contentType( false ) == 0 ); // Not created unless demanded. + QVERIFY( result->contentTransferEncoding( false ) ); // KMime gives it a default one (7bit). +} + +void ContentJobTest::testContentType() +{ + Composer *composer = new Composer; + ContentJob *cjob = new ContentJob( composer ); + QByteArray data( "birds came flying from the underground"); + cjob->setData( data ); + QByteArray mimeType( "text/plain" ); + cjob->contentType()->setMimeType( mimeType ); + QVERIFY( cjob->exec() ); + Content *result = cjob->content(); + result->assemble(); + kDebug() << result->encodedContent(); + QCOMPARE( result->body(), data ); + QVERIFY( result->contentType( false ) ); + QCOMPARE( result->contentType()->mimeType(), mimeType ); +} + +void ContentJobTest::testContentTransferEncoding() +{ + Composer *composer = new Composer; + ContentJob *cjob = new ContentJob( composer ); + QByteArray data( "birds came flying from the underground"); + cjob->setData( data ); + cjob->contentTransferEncoding()->setEncoding( Headers::CEquPr ); + QVERIFY( cjob->exec() ); + Content *result = cjob->content(); + result->assemble(); + kDebug() << result->encodedContent(); + QCOMPARE( result->body(), data ); + QVERIFY( result->contentType( false ) == 0 ); // Not created unless demanded. + QVERIFY( result->contentTransferEncoding( false ) ); + QCOMPARE( result->contentTransferEncoding()->encoding(), Headers::CEquPr ); +} + +#include "contentjobtest.moc" diff --git a/messagecomposer/tests/contentjobtest.h b/messagecomposer/tests/contentjobtest.h new file mode 100644 index 000000000..b7da81aa5 --- /dev/null +++ b/messagecomposer/tests/contentjobtest.h @@ -0,0 +1,34 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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 CONTENTJOBTEST_H +#define CONTENTJOBTEST_H + +#include + +class ContentJobTest : public QObject +{ + Q_OBJECT + private Q_SLOTS: + void testContent(); + void testContentType(); + void testContentTransferEncoding(); +}; + +#endif diff --git a/messagecomposer/tests/maintextjobtest.cpp b/messagecomposer/tests/maintextjobtest.cpp new file mode 100644 index 000000000..7fb2a1159 --- /dev/null +++ b/messagecomposer/tests/maintextjobtest.cpp @@ -0,0 +1,51 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "maintextjobtest.h" + +#include +#include + +#include +using namespace KMime; + +#include +#include +using namespace MessageComposer; + +QTEST_KDEMAIN( ContentJobTest, GUI ) + +void MainTextJobTest::testPlainText() +{ + // LEFT TODO +} + +void MainTextJobTest::testCustomCharset() +{ +} + +void MainTextJobTest::testBadCharset() +{ +} + +void MainTextJobTest::testFallbackCharset() +{ +} + +#include "maintextjobtest.moc" diff --git a/messagecomposer/tests/maintextjobtest.h b/messagecomposer/tests/maintextjobtest.h new file mode 100644 index 000000000..b97486e82 --- /dev/null +++ b/messagecomposer/tests/maintextjobtest.h @@ -0,0 +1,35 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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 MAINTEXTJOBTEST_H +#define MAINTEXTJOBTEST_H + +#include + +class MainTextJobTest : public QObject +{ + Q_OBJECT + private Q_SLOTS: + void testPlainText(); + void testCustomCharset(); + void testBadCharset(); + void testFallbackCharset(); +}; + +#endif diff --git a/messagecomposer/tests/multipartjobtest.cpp b/messagecomposer/tests/multipartjobtest.cpp new file mode 100644 index 000000000..1622c3e57 --- /dev/null +++ b/messagecomposer/tests/multipartjobtest.cpp @@ -0,0 +1,82 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "multipartjobtest.h" + +#include +#include + +#include +using namespace KMime; + +#include +#include +#include +using namespace MessageComposer; + +QTEST_KDEMAIN( MultipartJobTest, NoGUI ) + +void MultipartJobTest::testMultipartMixed() +{ + Composer *composer = new Composer; + MultipartJob *mjob = new MultipartJob( composer ); + mjob->setMultipartSubtype( "mixed" ); + + QByteArray data1( "one" ); + QByteArray data2( "two" ); + QByteArray type1( "text/plain" ); + QByteArray type2( "application/x-mors-ontologica" ); + + { + ContentJob *cjob = new ContentJob( mjob ); + cjob->setData( data1 ); + cjob->contentType()->setMimeType( type1 ); + } + + { + ContentJob *cjob = new ContentJob( mjob ); + cjob->setData( data2 ); + cjob->contentType()->setMimeType( type2 ); + } + + QVERIFY( mjob->exec() ); + Content *result = mjob->content(); + result->assemble(); + kDebug() << result->encodedContent(); + + QVERIFY( result->contentType( false ) ); + QCOMPARE( result->contentType()->mimeType(), QByteArray( "multipart/mixed" ) ); + QCOMPARE( result->contents().count(), 2 ); + + { + Content *c = result->contents().at( 0 ); + QCOMPARE( c->body(), data1 ); + QVERIFY( c->contentType( false ) ); + QCOMPARE( c->contentType()->mimeType(), type1 ); + } + + { + Content *c = result->contents().at( 1 ); + QCOMPARE( c->body(), data2 ); + QVERIFY( c->contentType( false ) ); + QCOMPARE( c->contentType()->mimeType(), type2 ); + } +} + +#include "multipartjobtest.moc" diff --git a/messagecomposer/tests/multipartjobtest.h b/messagecomposer/tests/multipartjobtest.h new file mode 100644 index 000000000..98eed2d82 --- /dev/null +++ b/messagecomposer/tests/multipartjobtest.h @@ -0,0 +1,32 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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 MULTIPARTJOBTEST_H +#define MULTIPARTJOBTEST_H + +#include + +class MultipartJobTest : public QObject +{ + Q_OBJECT + private Q_SLOTS: + void testMultipartMixed(); +}; + +#endif diff --git a/messagecomposer/tests/skeletonmessagejobtest.cpp b/messagecomposer/tests/skeletonmessagejobtest.cpp new file mode 100644 index 000000000..56774a169 --- /dev/null +++ b/messagecomposer/tests/skeletonmessagejobtest.cpp @@ -0,0 +1,174 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "skeletonmessagejobtest.h" + +#include +#include + +#include +using namespace KMime; + +#include +#include +#include +using namespace MessageComposer; + +QTEST_KDEMAIN( SkeletonMessageJobTest, NoGUI ) + +void SkeletonMessageJobTest::testSubject_data() +{ + QTest::addColumn( "subject" ); + + QTest::newRow( "simple subject" ) << "Antaa virrata sateen..."; + QTest::newRow( "non-ascii subject" ) << "Muzicologă în bej, vând whisky și tequila, preț fix."; + // NOTE: This works fine, but shows ????s in the debug output. Why? +} + +void SkeletonMessageJobTest::testSubject() +{ + // An InfoPart should belong to a Composer, even if we don't use the composer itself. + Composer *composer = new Composer; + InfoPart *infoPart = composer->infoPart(); + Q_ASSERT( infoPart ); + + QFETCH( QString, subject ); + //kDebug() << subject; + infoPart->setSubject( subject ); + SkeletonMessageJob *sjob = new SkeletonMessageJob( infoPart, composer ); + QVERIFY( sjob->exec() ); + Message *message = sjob->message(); + QVERIFY( message->subject( false ) ); + kDebug() << message->subject()->asUnicodeString(); + QCOMPARE( subject, message->subject()->asUnicodeString() ); +} + +void SkeletonMessageJobTest::testAddresses_data() +{ + QTest::addColumn( "from" ); + QTest::addColumn( "to" ); + QTest::addColumn( "cc" ); + QTest::addColumn( "bcc" ); + + { + QString from( "one@example.com" ); + QStringList to( "two@example.com" ); + QStringList cc( "three@example.com" ); + QStringList bcc( "four@example.com" ); + + QTest::newRow( "simple single address" ) << from << to << cc << bcc; + } + + { + QString from( "one@example.com" ); + QStringList to( "two@example.com" ); + to << "two.two@example.com"; + QStringList cc( "three@example.com" ); + cc << "three.three@example.com"; + QStringList bcc( "four@example.com" ); + bcc << "four.four@example.com"; + + QTest::newRow( "simple multi address" ) << from << to << cc << bcc; + } + + { + QString from( "Me " ); + QStringList to( "You " ); + to << "two.two@example.com"; + QStringList cc( "And you " ); + cc << "three.three@example.com"; + QStringList bcc( "And you too " ); + bcc << "four.four@example.com"; + + QTest::newRow( "named multi address" ) << from << to << cc << bcc; + } + + { + QString from( "Şîşkin " ); + QStringList to( "Ivan Turbincă " ); + to << "two.two@example.com"; + QStringList cc( "Luceafărul " ); + cc << "three.three@example.com"; + QStringList bcc( "Zburătorul " ); + bcc << "four.four@example.com"; + + QTest::newRow( "non-ascii named multi address" ) << from << to << cc << bcc; + } +} + +void SkeletonMessageJobTest::testAddresses() +{ + // An InfoPart should belong to a Composer, even if we don't use the composer itself. + Composer *composer = new Composer; + InfoPart *infoPart = composer->infoPart(); + Q_ASSERT( infoPart ); + + QFETCH( QString, from ); + QFETCH( QStringList, to ); + QFETCH( QStringList, cc ); + QFETCH( QStringList, bcc ); + infoPart->setFrom( from ); + infoPart->setTo( to ); + infoPart->setCc( cc ); + infoPart->setBcc( bcc ); + SkeletonMessageJob *sjob = new SkeletonMessageJob( infoPart, composer ); + QVERIFY( sjob->exec() ); + Message *message = sjob->message(); + + { + QVERIFY( message->from( false ) ); + kDebug() << "From:" << message->from()->asUnicodeString(); + QCOMPARE( from, message->from()->asUnicodeString() ); + } + + { + QVERIFY( message->to( false ) ); + kDebug() << "To:" << message->to()->asUnicodeString(); + foreach( const QString &addr, message->to()->prettyAddresses() ) { + kDebug() << addr; + QVERIFY( to.contains( addr ) ); + to.removeOne( addr ); + } + QVERIFY( to.isEmpty() ); + } + + { + QVERIFY( message->cc( false ) ); + kDebug() << "Cc:" << message->cc()->asUnicodeString(); + foreach( const QString &addr, message->cc()->prettyAddresses() ) { + kDebug() << addr; + QVERIFY( cc.contains( addr ) ); + cc.removeOne( addr ); + } + QVERIFY( cc.isEmpty() ); + } + + { + QVERIFY( message->bcc( false ) ); + kDebug() << "Bcc:" << message->bcc()->asUnicodeString(); + foreach( const QString &addr, message->bcc()->prettyAddresses() ) { + kDebug() << addr; + QVERIFY( bcc.contains( addr ) ); + bcc.removeOne( addr ); + } + QVERIFY( bcc.isEmpty() ); + } +} + +#include "skeletonmessagejobtest.moc" diff --git a/messagecomposer/tests/skeletonmessagejobtest.h b/messagecomposer/tests/skeletonmessagejobtest.h new file mode 100644 index 000000000..d9db5574f --- /dev/null +++ b/messagecomposer/tests/skeletonmessagejobtest.h @@ -0,0 +1,35 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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 SKELETONMESSAGEJOBTEST_H +#define SKELETONMESSAGEJOBTEST_H + +#include + +class SkeletonMessageJobTest : public QObject +{ + Q_OBJECT + private Q_SLOTS: + void testSubject_data(); + void testSubject(); + void testAddresses_data(); + void testAddresses(); +}; + +#endif diff --git a/messagecomposer/textpart.cpp b/messagecomposer/textpart.cpp new file mode 100644 index 000000000..06cf2946f --- /dev/null +++ b/messagecomposer/textpart.cpp @@ -0,0 +1,92 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "textpart.h" + +using namespace MessageComposer; + +class TextPart::Private +{ + public: + QString cleanPlainText; + QString wrappedPlainText; + QString cleanHtml; + QList charsets; + + // TODO related images +}; + +TextPart::TextPart( QObject *parent ) + : MessagePart( parent ) + , d( new Private ) +{ +} + +TextPart::~TextPart() +{ + delete d; +} + +QList TextPart::charsets() const +{ + return d->charsets; +} + +void TextPart::setCharsets( const QList &charsets ) +{ + d->charsets = charsets; +} + +QString TextPart::cleanPlainText() const +{ + return d->cleanPlainText; +} + +void TextPart::setCleanPlainText( const QString &text ) +{ + d->cleanPlainText = text; +} + +QString TextPart::wrappedPlainText() const +{ + return d->wrappedPlainText; +} + +void TextPart::setWrappedPlainText( const QString &text ) +{ + d->wrappedPlainText = text; +} + +bool TextPart::isHtmlUsed() const +{ + // TODO + return false; +} + +QString TextPart::cleanHtml() const +{ + return d->cleanHtml; +} + +void TextPart::setCleanHtml( const QString &text ) +{ + d->cleanHtml = text; +} + +#include "textpart.moc" diff --git a/messagecomposer/textpart.h b/messagecomposer/textpart.h new file mode 100644 index 000000000..919c36cdf --- /dev/null +++ b/messagecomposer/textpart.h @@ -0,0 +1,57 @@ +/* + Copyright (c) 2009 Constantin Berzan + + 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 MESSAGECOMPOSER_TEXTPART_H +#define MESSAGECOMPOSER_TEXTPART_H + +#include + +#include "messagecomposer_export.h" +#include "messagepart.h" + +namespace MessageComposer { + +class MESSAGECOMPOSER_EXPORT TextPart : public MessagePart +{ + Q_OBJECT + + public: + explicit TextPart( QObject *parent = 0 ); + virtual ~TextPart(); + + QList charsets() const; + void setCharsets( const QList &charsets ); + + QString cleanPlainText() const; + void setCleanPlainText( const QString &text ); + QString wrappedPlainText() const; + void setWrappedPlainText( const QString &text ); + + bool isHtmlUsed() const; + QString cleanHtml() const; + void setCleanHtml( const QString &text ); + + private: + class Private; + Private *const d; +}; + +} // namespace MessageComposer + +#endif // MESSAGECOMPOSER_TEXTPART_H