diff --git a/CMakeLists.txt b/CMakeLists.txt index 61820c9e4..d95fd67f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,180 +1,180 @@ 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 62) set(KDEPIMLIBS_VERSION ${KDEPIMLIBS_VERSION_MAJOR}.${KDEPIMLIBS_VERSION_MINOR}.${KDEPIMLIBS_VERSION_PATCH}) ############### search packages used by KDE ############### find_package(KDE4 4.3.62 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.2.60 QUIET NO_MODULE) macro_log_feature(Akonadi_FOUND "Akonadi" "Akonadi server libraries (from kdesupport)" "http://pim.kde.org/akonadi" TRUE "1.2.60" "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(microblog) - add_subdirectory(kpimtextedit) 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/akonadi/CMakeLists.txt b/akonadi/CMakeLists.txt index 9bcae53a2..e4d9a2760 100644 --- a/akonadi/CMakeLists.txt +++ b/akonadi/CMakeLists.txt @@ -1,262 +1,269 @@ project(akonadi-kde) add_definitions( -DKDE_DEFAULT_DEBUG_AREA=5250 ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}" ) if(CMAKE_COMPILE_GCOV) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") endif(CMAKE_COMPILE_GCOV) if (KDE4_BUILD_TESTS) # only with this macro the AKONADI_TESTS_EXPORT macro will do something add_definitions(-DCOMPILING_TESTS) add_subdirectory( tests ) endif (KDE4_BUILD_TESTS) add_definitions( -DQT_NO_CAST_FROM_ASCII ) add_definitions( -DQT_NO_CAST_TO_ASCII ) add_subdirectory( kabc ) add_subdirectory( kmime ) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${QT_QTDBUS_INCLUDE_DIR} ${Boost_INCLUDE_DIR} ${KDE4_INCLUDE_DIR} ${AKONADI_INCLUDE_DIR} ${AKONADI_INCLUDE_DIR}/akonadi/private ) # libakonadi-kde set( akonadikde_LIB_SRC entity.cpp # keep it at top to not break enable-final agentbase.cpp agentfilterproxymodel.cpp agentinstance.cpp agentinstancecreatejob.cpp agentinstancemodel.cpp agentinstancewidget.cpp agentmanager.cpp agenttype.cpp agenttypemodel.cpp agenttypewidget.cpp agenttypedialog.cpp attribute.cpp attributefactory.cpp cachepolicy.cpp cachepolicypage.cpp changerecorder.cpp collection.cpp collectioncopyjob.cpp collectioncreatejob.cpp collectiondeletejob.cpp collectiondialog.cpp collectionfilterproxymodel.cpp collectiongeneralpropertiespage.cpp collectionfetchjob.cpp collectionfetchscope.cpp collectionmodel.cpp collectionmodel_p.cpp collectionmodifyjob.cpp collectionmovejob.cpp collectionpathresolver.cpp collectionpropertiesdialog.cpp collectionpropertiespage.cpp collectionrequester.cpp collectionrightsattribute.cpp collectionselectjob.cpp collectionstatistics.cpp collectionstatisticsdelegate.cpp collectionstatisticsjob.cpp collectionstatisticsmodel.cpp collectionsync.cpp collectionview.cpp control.cpp descendantsproxymodel.cpp entitycache.cpp entitydisplayattribute.cpp entityhiddenattribute.cpp entitytreemodel.cpp entitytreemodel_p.cpp entityfilterproxymodel.cpp entitytreeviewstatesaver.cpp erroroverlay.cpp exception.cpp favoritecollectionsmodel.cpp firstrun.cpp flatcollectionproxymodel.cpp item.cpp itemcreatejob.cpp itemcopyjob.cpp itemdeletejob.cpp itemfetchjob.cpp itemfetchscope.cpp itemmodel.cpp itemmonitor.cpp itemmovejob.cpp itemsearchjob.cpp itemserializer.cpp itemserializerplugin.cpp itemmodifyjob.cpp itemsync.cpp itemview.cpp job.cpp linkjob.cpp + filteractionjob.cpp mimetypechecker.cpp monitor.cpp monitor_p.cpp pastehelper.cpp preprocessorbase.cpp protocolhelper.cpp resourcebase.cpp resourcescheduler.cpp resourceselectjob.cpp searchcreatejob.cpp selectionproxymodel.cpp selftestdialog.cpp session.cpp servermanager.cpp standardactionmanager.cpp statisticsproxymodel.cpp statisticstooltipproxymodel.cpp subscriptionjob.cpp subscriptionchangeproxymodel.cpp subscriptiondialog.cpp subscriptionmodel.cpp transactionjobs.cpp transactionsequence.cpp + transportresourcebase.cpp unlinkjob.cpp # Temporary until ported to Qt-plugin framework pluginloader.cpp ) # DBus interfaces and adaptors set(akonadi_xml ${AKONADI_DBUS_INTERFACES_DIR}/org.freedesktop.Akonadi.NotificationManager.xml) set_source_files_properties(${akonadi_xml} PROPERTIES INCLUDE "notificationmessage_p.h") qt4_add_dbus_interface( akonadikde_LIB_SRC ${akonadi_xml} notificationmanagerinterface ) qt4_add_dbus_interfaces( akonadikde_LIB_SRC ${AKONADI_DBUS_INTERFACES_DIR}/org.freedesktop.Akonadi.AgentManager.xml ) qt4_add_dbus_interfaces( akonadikde_LIB_SRC ${AKONADI_DBUS_INTERFACES_DIR}/org.freedesktop.Akonadi.Tracer.xml ) qt4_add_dbus_adaptor( akonadikde_LIB_SRC ${AKONADI_DBUS_INTERFACES_DIR}/org.freedesktop.Akonadi.Resource.xml resourcebase.h Akonadi::ResourceBase ) qt4_add_dbus_adaptor( akonadikde_LIB_SRC ${AKONADI_DBUS_INTERFACES_DIR}/org.freedesktop.Akonadi.Preprocessor.xml preprocessorbase.h Akonadi::PreprocessorBase ) qt4_add_dbus_adaptor( akonadikde_LIB_SRC ${AKONADI_DBUS_INTERFACES_DIR}/org.freedesktop.Akonadi.Agent.Status.xml agentbase.h Akonadi::AgentBase ) qt4_add_dbus_adaptor( akonadikde_LIB_SRC ${AKONADI_DBUS_INTERFACES_DIR}/org.freedesktop.Akonadi.Agent.Control.xml agentbase.h Akonadi::AgentBase ) +# TODO move this to kdesupport/akonadi/interfaces +qt4_add_dbus_adaptor( akonadikde_LIB_SRC interfaces/org.freedesktop.Akonadi.Resource.Transport.xml transportresourcebase_p.h Akonadi::TransportResourceBasePrivate ) +#qt4_add_dbus_interface( akonadikde_LIB_SRC interfaces/org.freedesktop.Akonadi.Resource.Transport.xml resourcetransportinterface ) kde4_add_ui_files( akonadikde_LIB_SRC cachepolicypage.ui collectiongeneralpropertiespage.ui subscriptiondialog.ui controlprogressindicator.ui selftestdialog.ui ) kde4_add_library( akonadi-kde SHARED ${akonadikde_LIB_SRC} ) macro_ensure_version( "4.2.0" ${KDE_VERSION} KDE_IS_AT_LEAST_42 ) target_link_libraries( akonadi-kde ${KDE4_SOLID_LIBS} ${QT_QTNETWORK_LIBRARY} ${QT_QTDBUS_LIBRARY} ${QT_QTSQL_LIBRARY} ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ${AKONADI_COMMON_LIBRARIES} ) set( AKONADI_KDE_DEPS ${KDE4_KDEUI_LIBS} ${QT_QTDBUS_LIBRARY} ${QT_QTCORE_LIBRARY} ) if(${KDE_IS_AT_LEAST_42}) target_link_libraries( akonadi-kde LINK_INTERFACE_LIBRARIES ${AKONADI_KDE_DEPS}) else(${KDE_IS_AT_LEAST_42}) target_link_libraries( akonadi-kde ${AKONADI_KDE_DEPS}) endif(${KDE_IS_AT_LEAST_42}) set_target_properties( akonadi-kde PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION} ) install( TARGETS akonadi-kde EXPORT kdepimlibsLibraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS} ) ########### install files ############### install( FILES akonadi_export.h agentbase.h agentfilterproxymodel.h agentinstance.h agentinstancecreatejob.h agentinstancemodel.h agentinstancewidget.h agentmanager.h agenttype.h agenttypemodel.h agenttypewidget.h agenttypedialog.h attribute.h attributefactory.h cachepolicy.h changerecorder.h collection.h collectioncopyjob.h collectioncreatejob.h collectiondeletejob.h collectiondialog.h collectionfilterproxymodel.h collectionfetchjob.h collectionfetchscope.h collectionmodel.h collectionmodifyjob.h collectionpropertiesdialog.h collectionpropertiespage.h collectionrequester.h collectionstatisticsdelegate.h collectionstatisticsmodel.h collectionstatistics.h collectionstatisticsjob.h collectionview.h control.h descendantsproxymodel.h entity.h entitydisplayattribute.h entityhiddenattribute.h entitytreemodel.h entityfilterproxymodel.h entitytreeviewstatesaver.h exception.h favoritecollectionsmodel.h item.h itemcreatejob.h itemcopyjob.h itemdeletejob.h itemfetchjob.h itemfetchscope.h itemmodel.h itemmodifyjob.h itemmonitor.h itemmovejob.h itempayloadinternals_p.h itemsearchjob.h itemserializerplugin.h itemsync.h itemview.h job.h linkjob.h + filteractionjob.h mimetypechecker.h monitor.h qtest_akonadi.h preprocessorbase.h resourcebase.h searchcreatejob.h selectionproxymodel.h session.h servermanager.h standardactionmanager.h statisticsproxymodel.h statisticstooltipproxymodel.h transactionjobs.h transactionsequence.h + transportresourcebase.h unlinkjob.h DESTINATION ${INCLUDE_INSTALL_DIR}/akonadi COMPONENT Devel ) install( FILES collectionpathresolver_p.h DESTINATION ${INCLUDE_INSTALL_DIR}/akonadi/private COMPONENT Devel ) install( FILES kcfg2dbus.xsl DESTINATION ${DATA_INSTALL_DIR}/akonadi-kde ) diff --git a/akonadi/filteractionjob.cpp b/akonadi/filteractionjob.cpp new file mode 100644 index 000000000..8111cb417 --- /dev/null +++ b/akonadi/filteractionjob.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 "filteractionjob.h" + +#include "collection.h" +#include "itemfetchjob.h" +#include "itemfetchscope.h" +#include "job_p.h" + +#include + +using namespace Akonadi; + +class Akonadi::FilterActionJob::Private +{ + public: + Private( FilterActionJob *qq ) + : q( qq ) + , functor( 0 ) + { + } + + ~Private() + { + delete functor; + } + + FilterActionJob *q; + Collection collection; + Item::List items; + FilterAction *functor; + ItemFetchScope fetchScope; + + // slots: + void fetchResult( KJob *job ); + + void traverseItems(); +}; + +void FilterActionJob::Private::fetchResult( KJob *job ) +{ + if ( job->error() ) { + // KCompositeJob takes care of errors. + return; + } + + ItemFetchJob *fjob = dynamic_cast( job ); + Q_ASSERT( fjob ); + Q_ASSERT( items.isEmpty() ); + items = fjob->items(); + traverseItems(); +} + +void FilterActionJob::Private::traverseItems() +{ + Q_ASSERT( functor ); + kDebug() << "Traversing" << items.count() << "items."; + foreach( const Item &item, items ) { + if( functor->itemAccepted( item ) ) { + q->addSubjob( functor->itemAction( item ) ); + kDebug() << "Added subjob for item" << item.id(); + } + } + if( q->subjobs().isEmpty() ) { + kDebug() << "No subjobs; I am done."; + q->emitResult(); + } else { + kDebug() << "Have subjobs; calling commit()."; + q->commit(); + } +} + + + +FilterAction::~FilterAction() +{ +} + + + +FilterActionJob::FilterActionJob( const Item &item, FilterAction *functor, QObject *parent ) + : TransactionSequence( parent ) + , d( new Private( this ) ) +{ + d->functor = functor; + d->items << item; +} + +FilterActionJob::FilterActionJob( const Item::List &items, FilterAction *functor, QObject *parent ) + : TransactionSequence( parent ) + , d( new Private( this ) ) +{ + d->functor = functor; + d->items = items; +} + +FilterActionJob::FilterActionJob( const Collection &collection, FilterAction *functor, QObject *parent ) + : TransactionSequence( parent ) + , d( new Private( this ) ) +{ + d->functor = functor; + Q_ASSERT( collection.isValid() ); + d->collection = collection; +} + +FilterActionJob::~FilterActionJob() +{ + delete d; +} + +void FilterActionJob::doStart() +{ + if( d->collection.isValid() ) { + kDebug() << "Fetching collection" << d->collection.id(); + ItemFetchJob *fjob = new ItemFetchJob( d->collection, this ); + Q_ASSERT( d->functor ); + d->fetchScope = d->functor->fetchScope(); + fjob->setFetchScope( d->fetchScope ); + connect( fjob, SIGNAL(result(KJob*)), this, SLOT(fetchResult(KJob*)) ); + } else { + d->traverseItems(); + } +} + +#include "filteractionjob.moc" diff --git a/akonadi/filteractionjob.h b/akonadi/filteractionjob.h new file mode 100644 index 000000000..4a07ad7ac --- /dev/null +++ b/akonadi/filteractionjob.h @@ -0,0 +1,173 @@ +/* + 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 AKONADI_FILTERACTIONJOB_H +#define AKONADI_FILTERACTIONJOB_H + +#include "item.h" +#include "transactionsequence.h" + +namespace Akonadi { + +class Collection; +class ItemFetchScope; +class Job; + +/** + @short Base class for a filter/action for FilterActionJob. + + Abstract class defining an interface for a filter and an action for + FilterActionJob. The virtual methods must be implemented in subclasses. + + @code + class ClearErrorAction : public Akonadi::FilterAction + { + public: + // reimpl + virtual Akonadi::ItemFetchScope fetchScope() const + { + ItemFetchScope scope; + scope.fetchFullPayload( false ); + scope.fetchAttribute(); + return scope; + } + + virtual bool itemAccepted( const Akonadi::Item &item ) const + { + return item.hasAttribute(); + } + + virtual Akonadi::Job *itemAction( const Akonadi::Item &item ) const + { + Item cp = item; + cp.removeAttribute(); + return new ItemModifyJob( cp ); + } + }; + @endcode + + @see FilterActionJob + + @author Constantin Berzan + @since 4.4 +*/ +class AKONADI_EXPORT FilterAction +{ + public: + /** + Destroys this FilterAction. + A FilterActionJob will delete its FilterAction automatically. + */ + virtual ~FilterAction(); + + /** + Returns an ItemFetchScope to use if the FilterActionJob needs to fetch + the items from a collection. + Note that the items are not fetched unless FilterActionJob is + constructed with a Collection parameter. + */ + virtual Akonadi::ItemFetchScope fetchScope() const = 0; + + /** + Returns true if the @p item is accepted by the filter and should be + acted upon by the FilterActionJob. + */ + virtual bool itemAccepted( const Akonadi::Item &item ) const = 0; + + /** + Returns a job to act on the @p item. + The FilterActionJob will finish when all such jobs are finished. + */ + virtual Akonadi::Job *itemAction( const Akonadi::Item &item ) const = 0; +}; + + + +/** + @short Job to filter and apply an action on a set of items. + + This jobs filters through a set of items, and applies an action to the + items which are accepted by the filter. The filter and action + are provided by a functor class derived from FilterAction. + + For example, a MarkAsRead action/filter may be used to mark all messages + in a folder as read. + + @code + FilterActionJob *mjob = new FilterActionJob( LocalFolders::self()->outbox(), + new ClearErrorAction, this ); + connect( mjob, SIGNAL(result(KJob*)), this, SLOT(massModifyResult(KJob*)) ); + @endcode + + @see FilterAction + + @author Constantin Berzan + @since 4.4 +*/ +class AKONADI_EXPORT FilterActionJob : public TransactionSequence +{ + Q_OBJECT + + public: + /** + Creates a FilterActionJob to act on a single item. + + @param item The item to act on. The item is not re-fetched. + @param functor The FilterAction to use. + */ + FilterActionJob( const Item &item, FilterAction *functor, QObject *parent = 0 ); + + /** + Creates a FilterActionJob to act on a set of items. + + @param items The items to act on. The items are not re-fetched. + @param functor The FilterAction to use. + */ + FilterActionJob( const Item::List &items, FilterAction *functor, QObject *parent = 0 ); + + /** + Creates a FilterActionJob to act on items in a collection. + + @param items The items to act on. The items are fetched using functor->fetchScope(). + @param functor The FilterAction to use. + */ + FilterActionJob( const Collection &collection, FilterAction *functor, QObject *parent = 0 ); + + /** + Destroys this FilterActionJob. + This job autodeletes itself. + */ + ~FilterActionJob(); + + protected: + /* reimpl */ + virtual void doStart(); + + private: + //@cond PRIVATE + class Private; + Private *const d; + + Q_PRIVATE_SLOT( d, void fetchResult( KJob* ) ) + //@endcond +}; + +} // namespace Akonadi + +#endif // AKONADI_FILTERACTIONJOB_H diff --git a/akonadi/interfaces/org.freedesktop.Akonadi.Resource.Transport.xml b/akonadi/interfaces/org.freedesktop.Akonadi.Resource.Transport.xml new file mode 100644 index 000000000..bafc74baa --- /dev/null +++ b/akonadi/interfaces/org.freedesktop.Akonadi.Resource.Transport.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/akonadi/kmime/CMakeLists.txt b/akonadi/kmime/CMakeLists.txt index 4cee5cf31..878d6c9bd 100644 --- a/akonadi/kmime/CMakeLists.txt +++ b/akonadi/kmime/CMakeLists.txt @@ -1,33 +1,44 @@ include_directories( ${CMAKE_SOURCE_DIR}/ ${QT_QTDBUS_INCLUDE_DIR} ${Boost_INCLUDE_DIR} ) +add_subdirectory( tests ) + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII ${KDE4_ENABLE_EXCEPTIONS}" ) ########### next target ############### set( kmimeakonadi_LIB_SRC + addressattribute.cpp + localfolders.cpp + localfoldersbuildjob.cpp messagemodel.cpp messageparts.cpp messagethreadingattribute.cpp messagethreaderproxymodel.cpp + resourcesynchronizationjob.cpp # copied from playground/pim/akonaditest/resourcetester ) +kde4_add_kcfg_files( kmimeakonadi_LIB_SRC localfolderssettings.kcfgc ) +install( FILES localfolders.kcfg DESTINATION ${KCFG_INSTALL_DIR} ) + kde4_add_library( akonadi-kmime SHARED ${kmimeakonadi_LIB_SRC} ) -target_link_libraries( akonadi-kmime akonadi-kde kmime ${QT_QTGUI_LIBRARY} ${KDE4_KDECORE_LIBS} ) +target_link_libraries( akonadi-kmime akonadi-kde kmime ${QT_QTGUI_LIBRARY} ${KDE4_KDECORE_LIBS} ${KDE4_KDEUI_LIBS}) set_target_properties( akonadi-kmime PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION} ) install(TARGETS akonadi-kmime EXPORT kdepimlibsLibraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) ########### install files ############### install( FILES + addressattribute.h + localfolders.h akonadi-kmime_export.h messagemodel.h messageparts.h messagethreadingattribute.h messagethreaderproxymodel.h DESTINATION ${INCLUDE_INSTALL_DIR}/akonadi/kmime COMPONENT Devel ) diff --git a/akonadi/kmime/addressattribute.cpp b/akonadi/kmime/addressattribute.cpp new file mode 100644 index 000000000..4ab5469c9 --- /dev/null +++ b/akonadi/kmime/addressattribute.cpp @@ -0,0 +1,142 @@ +/* + Copyright 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 "addressattribute.h" + +#include + +#include + +#include + +using namespace Akonadi; + +/** + @internal +*/ +class AddressAttribute::Private +{ + public: + QString mFrom; + QStringList mTo; + QStringList mCc; + QStringList mBcc; +}; + +AddressAttribute::AddressAttribute( const QString &from, const QStringList &to, + const QStringList &cc, const QStringList &bcc ) + : d( new Private ) +{ + d->mFrom = from; + d->mTo = to; + d->mCc = cc; + d->mBcc = bcc; +} + +AddressAttribute::~AddressAttribute() +{ + delete d; +} + +AddressAttribute* AddressAttribute::clone() const +{ + return new AddressAttribute( d->mFrom, d->mTo, d->mCc, d->mBcc ); +} + +QByteArray AddressAttribute::type() const +{ + static const QByteArray sType( "AddressAttribute" ); + return sType; +} + +QByteArray AddressAttribute::serialized() const +{ + QByteArray serializedData; + QDataStream serializer( &serializedData, QIODevice::WriteOnly ); + serializer.setVersion( QDataStream::Qt_4_5 ); + serializer << d->mFrom; + serializer << d->mTo; + serializer << d->mCc; + serializer << d->mBcc; + return serializedData; +} + +void AddressAttribute::deserialize( const QByteArray &data ) +{ + QDataStream deserializer( data ); + deserializer.setVersion( QDataStream::Qt_4_5 ); + deserializer >> d->mFrom; + deserializer >> d->mTo; + deserializer >> d->mCc; + deserializer >> d->mBcc; +} + +QString AddressAttribute::from() const +{ + return d->mFrom; +} + +void AddressAttribute::setFrom( const QString &from ) +{ + d->mFrom = from; +} + +QStringList AddressAttribute::to() const +{ + return d->mTo; +} + +void AddressAttribute::setTo( const QStringList &to ) +{ + d->mTo = to; +} + +QStringList AddressAttribute::cc() const +{ + return d->mCc; +} + +void AddressAttribute::setCc( const QStringList &cc ) +{ + d->mCc = cc; +} + +QStringList AddressAttribute::bcc() const +{ + return d->mBcc; +} + +void AddressAttribute::setBcc( const QStringList &bcc ) +{ + d->mBcc = bcc; +} + +// Register the attribute when the library is loaded. +namespace { + +bool dummy() +{ + using namespace Akonadi; + AttributeFactory::registerAttribute(); + return true; +} + +const bool registered = dummy(); + +} diff --git a/akonadi/kmime/addressattribute.h b/akonadi/kmime/addressattribute.h new file mode 100644 index 000000000..796fbb350 --- /dev/null +++ b/akonadi/kmime/addressattribute.h @@ -0,0 +1,112 @@ +/* + Copyright 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 AKONADI_ADDRESSATTRIBUTE_H +#define AKONADI_ADDRESSATTRIBUTE_H + +#include "akonadi-kmime_export.h" + +#include +#include + +#include + +namespace MailTransport { + class Transport; +} + +namespace Akonadi { + +/** + Attribute storing the From, To, Cc, Bcc addresses of a message. + + @author Constantin Berzan + @since 4.4 +*/ +class AKONADI_KMIME_EXPORT AddressAttribute : public Akonadi::Attribute +{ + public: + /** + Creates a new AddressAttribute. + */ + explicit AddressAttribute( const QString &from = QString(), + const QStringList &to = QStringList(), + const QStringList &cc = QStringList(), + const QStringList &bcc = QStringList() ); + /** + Destroys the AddressAttribute. + */ + virtual ~AddressAttribute(); + + + /* reimpl */ + virtual AddressAttribute* clone() const; + virtual QByteArray type() const; + virtual QByteArray serialized() const; + virtual void deserialize( const QByteArray &data ); + + /** + Returns the address of the sender. + */ + QString from() const; + + /** + Sets the address of the sender. + */ + void setFrom( const QString &from ); + + /** + Returns the addresses of the "To:" receivers. + */ + QStringList to() const; + + /** + Sets the addresses of the "To:" receivers." + */ + void setTo( const QStringList &to ); + + /** + Returns the addresses of the "Cc:" receivers. + */ + QStringList cc() const; + + /** + Sets the addresses of the "Cc:" receivers." + */ + void setCc( const QStringList &cc ); + + /** + Returns the addresses of the "Bcc:" receivers. + */ + QStringList bcc() const; + + /** + Sets the addresses of the "Bcc:" receivers." + */ + void setBcc( const QStringList &bcc ); + + private: + class Private; + Private *const d; + +}; + +} // namespace Akonadi + +#endif // AKONADI_ADDRESSATTRIBUTE_H diff --git a/akonadi/kmime/localfolders.cpp b/akonadi/kmime/localfolders.cpp new file mode 100644 index 000000000..68fcc85ba --- /dev/null +++ b/akonadi/kmime/localfolders.cpp @@ -0,0 +1,279 @@ +/* + 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 "localfolders.h" + +#include "localfoldersbuildjob_p.h" +#include "localfolderssettings.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define DBUS_SERVICE_NAME QLatin1String( "org.kde.pim.LocalFolders" ) + +using namespace Akonadi; + +typedef LocalFoldersSettings Settings; + +/** + @internal +*/ +class Akonadi::LocalFoldersPrivate +{ + public: + LocalFoldersPrivate(); + ~LocalFoldersPrivate(); + + LocalFolders *instance; + bool ready; + bool preparing; + bool scheduled; + bool isMainInstance; + Collection rootMaildir; + Collection::List defaultFolders; + QSet pendingJobs; + Monitor *monitor; + + /** + If this is the main instance, attempts to build and fetch the local + folder structure. Otherwise, it waits for the structure to be created + by the main instance, and then just fetches it. + + Will emit foldersReady() when the folders are ready. + */ + void prepare(); // slot + + // slots: + void buildResult( KJob *job ); + void collectionRemoved( const Collection &col ); + + /** + Schedules a prepare() in 1 second. + Called when this is not the main instance and we need to wait, or when + something disappeared and needs to be recreated. + */ + void schedulePrepare(); + +}; + + +K_GLOBAL_STATIC( LocalFoldersPrivate, sInstance ) + + +LocalFolders::LocalFolders( LocalFoldersPrivate *dd ) + : QObject() + , d( dd ) +{ +} + +LocalFolders *LocalFolders::self() +{ + return sInstance->instance; +} + +void LocalFolders::fetch() +{ + d->prepare(); +} + +bool LocalFolders::isReady() const +{ + return d->ready; +} + +Collection LocalFolders::root() const +{ + return folder( Root ); +} + +Collection LocalFolders::inbox() const +{ + return folder( Inbox ); +} + +Collection LocalFolders::outbox() const +{ + return folder( Outbox ); +} + +Collection LocalFolders::sentMail() const +{ + return folder( SentMail ); +} + +Collection LocalFolders::trash() const +{ + return folder( Trash ); +} + +Collection LocalFolders::drafts() const +{ + return folder( Drafts ); +} + +Collection LocalFolders::templates() const +{ + return folder( Templates ); +} + +Collection LocalFolders::folder( int type ) const +{ + Q_ASSERT( d->ready ); + Q_ASSERT( type >= 0 && type < LastDefaultType ); + return d->defaultFolders[ type ]; +} + + + +LocalFoldersPrivate::LocalFoldersPrivate() + : instance( new LocalFolders(this) ) +{ + isMainInstance = false; + ready = false; + preparing = false; + monitor = 0; + prepare(); +} + +LocalFoldersPrivate::~LocalFoldersPrivate() +{ + delete instance; +} + +void LocalFoldersPrivate::prepare() +{ + if( ready ) { + kDebug() << "Already ready. Emitting foldersReady()."; + emit instance->foldersReady(); + return; + } + if( preparing ) { + kDebug() << "Already preparing."; + return; + } + + // Try to grab main instance status (if previous main instance quit). + if( !isMainInstance ) { + isMainInstance = QDBusConnection::sessionBus().registerService( DBUS_SERVICE_NAME ); + } + + // Fetch / build the folder structure. + { + kDebug() << "Preparing. isMainInstance" << isMainInstance; + preparing = true; + scheduled = false; + LocalFoldersBuildJob *bjob = new LocalFoldersBuildJob( isMainInstance, instance ); + QObject::connect( bjob, SIGNAL(result(KJob*)), instance, SLOT(buildResult(KJob*)) ); + // auto-starts + } +} + +void LocalFoldersPrivate::buildResult( KJob *job ) +{ + if( job->error() ) { + kDebug() << "BuildJob failed with error" << job->errorString(); + schedulePrepare(); + return; + } + + // Get the folders from the job. + { + Q_ASSERT( dynamic_cast( job ) ); + LocalFoldersBuildJob *bjob = static_cast( job ); + Q_ASSERT( defaultFolders.isEmpty() ); + defaultFolders = bjob->defaultFolders(); + } + + // Verify everything. + { + Q_ASSERT( defaultFolders.count() == LocalFolders::LastDefaultType ); + Collection::Id rootId = defaultFolders[ LocalFolders::Root ].id(); + Q_ASSERT( rootId >= 0 ); + for( int type = 1; type < LocalFolders::LastDefaultType; type++ ) { + Q_ASSERT( defaultFolders[ type ].isValid() ); + Q_ASSERT( defaultFolders[ type ].parent() == rootId ); + } + } + + // Connect monitor. + { + Q_ASSERT( monitor == 0 ); + monitor = new Monitor( instance ); + monitor->setResourceMonitored( Settings::resourceId().toAscii() ); + QObject::connect( monitor, SIGNAL(collectionRemoved(Akonadi::Collection)), + instance, SLOT(collectionRemoved(Akonadi::Collection)) ); + } + + // Emit ready. + { + kDebug() << "Local folders ready."; + Q_ASSERT( !ready ); + ready = true; + preparing = false; + emit instance->foldersReady(); + } +} + +void LocalFoldersPrivate::collectionRemoved( const Akonadi::Collection &col ) +{ + kDebug() << "id" << col.id(); + if( defaultFolders.contains( col ) ) { + // These are undeletable folders. If one of them got removed, it means + // the entire resource has been removed. + schedulePrepare(); + } +} + +void LocalFoldersPrivate::schedulePrepare() +{ + if( scheduled ) { + kDebug() << "Prepare already scheduled."; + return; + } + + // Clean up. + { + if( monitor ) { + monitor->disconnect( instance ); + monitor->deleteLater(); + monitor = 0; + } + defaultFolders.clear(); + } + + // Schedule prepare in 1s. + { + kDebug() << "Scheduling prepare."; + ready = false; + preparing = false; + scheduled = true; + QTimer::singleShot( 1000, instance, SLOT( prepare() ) ); + } +} + +#include "localfolders.moc" diff --git a/akonadi/kmime/localfolders.h b/akonadi/kmime/localfolders.h new file mode 100644 index 000000000..929512b1a --- /dev/null +++ b/akonadi/kmime/localfolders.h @@ -0,0 +1,184 @@ +/* + 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 AKONADI_LOCALFOLDERS_H +#define AKONADI_LOCALFOLDERS_H + +#include "akonadi-kmime_export.h" + +#include + +#include + +class KJob; + +namespace Akonadi { + +class LocalFoldersPrivate; + +/** + @short Interface to local folders such as inbox, outbox etc. + + This class provides access to the following default (and undeletable) local + folders: inbox, outbox, sent-mail, trash, drafts, and templates; as well as + the root local folder containing them. The user may create custom + subfolders in the root local folder, or in any of the default local folders. + + By default, these folders are stored in a maildir in + $HOME/.local/share/mail. + + This class also monitors the local folders and the maildir resource hosting + them, and re-creates them when necessary (for example, if the user + accidentally removed the maildir resource). For this reason, you must make + sure the local folders are ready before calling any of the accessor + functions. It is also recommended that you always use this class to access + the local folders, instead of, for example, storing the result of + LocalFolders::self()->outbox() locally. + + @code + connect( LocalFolders::self(), SIGNAL(foldersReady()), + this, SLOT(riseAndShine()) ); + LocalFolders::self()->fetch(); + @endcode + + @author Constantin Berzan + @since 4.4 +*/ +class AKONADI_KMIME_EXPORT LocalFolders : public QObject +{ + Q_OBJECT + + public: + /** + Each local folder has one of the types below. There cannot be more + than one folder of each type, except for Custom. + */ + enum Type + { + Root, ///< the root folder containing the local folders + Inbox, ///< inbox + Outbox, ///< outbox + SentMail, ///< sent-mail + Trash, ///< trash + Drafts, ///< drafts + Templates, ///< templates + LastDefaultType, ///< @internal marker + Custom = 15 ///< for custom folders created by the user + }; + + /** + Returns the LocalFolders instance. + Does a fetch() when first called. + + @see fetch + */ + static LocalFolders *self(); + + /** + Returns whether the local folder collections have been fetched and are + ready to be accessed. + + @see fetch + @see foldersReady + */ + bool isReady() const; + + /** + Returns the root collection containing all local folders. + */ + Akonadi::Collection root() const; + + /** + Returns the inbox collection. + */ + Akonadi::Collection inbox() const; + + /** + Returns the outbox collection. + */ + Akonadi::Collection outbox() const; + + /** + Returns the sent-mail collection. + */ + Akonadi::Collection sentMail() const; + + /** + Returns the trash collection. + */ + Akonadi::Collection trash() const; + + /** + Returns the drafts collection. + */ + Akonadi::Collection drafts() const; + + /** + Returns the templates collection. + */ + Akonadi::Collection templates() const; + + /** + Get a folder by its type. + Returns an invalid collection if no such folder exists. + This function only works for default (non-Custom) folder types. + + @see Type + */ + Akonadi::Collection folder( int type ) const; + + public Q_SLOTS: + /** + Begins fetching the resource and collections, or creating them if + necessary. Emits foldersReady() when done. + + @code + connect( LocalFolders::self(), SIGNAL(foldersReady()), + this, SLOT(riseAndShine()) ); + LocalFolders::self()->fetch(); + @endcode + */ + void fetch(); + + Q_SIGNALS: + /** + Emitted when the local folder collections have been fetched and + are ready to be accessed. + + @see isReady + */ + void foldersReady(); + + private: + friend class LocalFoldersPrivate; + + // singleton class; the only instance resides in sInstance->instance + LocalFolders( LocalFoldersPrivate *dd ); + + LocalFoldersPrivate *const d; + + Q_PRIVATE_SLOT( d, void prepare() ) + Q_PRIVATE_SLOT( d, void buildResult( KJob* ) ) + Q_PRIVATE_SLOT( d, void collectionRemoved( Akonadi::Collection ) ) + +}; + +} // namespace Akonadi + +#endif // AKONADI_LOCALFOLDERS_H diff --git a/akonadi/kmime/localfolders.kcfg b/akonadi/kmime/localfolders.kcfg new file mode 100644 index 000000000..39ca5b4d3 --- /dev/null +++ b/akonadi/kmime/localfolders.kcfg @@ -0,0 +1,14 @@ + + + + + + + Id of the maildir resource containing the local folder collections. + + + + diff --git a/akonadi/kmime/localfoldersbuildjob.cpp b/akonadi/kmime/localfoldersbuildjob.cpp new file mode 100644 index 000000000..78017cec6 --- /dev/null +++ b/akonadi/kmime/localfoldersbuildjob.cpp @@ -0,0 +1,405 @@ +/* + 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 "localfoldersbuildjob_p.h" + +#include "localfolders.h" +#include "localfolderssettings.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include // copied from playground/pim/akonaditest + +using namespace Akonadi; + +typedef LocalFoldersSettings Settings; + +/** + @internal +*/ +class Akonadi::LocalFoldersBuildJob::Private +{ + public: + Private( LocalFoldersBuildJob *qq ) + : q( qq ) + { + for( int type = 0; type < LocalFolders::LastDefaultType; type++ ) { + defaultFolders.append( Collection() ); + } + } + + void resourceCreateResult( KJob *job ); // slot + void resourceSyncResult( KJob *job ); // slot + void fetchCollections(); + void collectionFetchResult( KJob *job ); // slot + void createAndConfigureCollections(); + void collectionCreateResult( KJob *job ); // slot + void collectionModifyResult( KJob *job ); // slot + + // May be called for any default type, including Root. + static QString nameForType( int type ); + + // May be called for any default type, including Root. + static QString iconNameForType( int type ); + + // May be called for any default or custom type, other than Root. + static LocalFolders::Type typeForName( const QString &name ); + + LocalFoldersBuildJob *q; + bool canBuild; + Collection::List defaultFolders; + //QSet customFolders; + QSet pendingJobs; + +}; + + + +LocalFoldersBuildJob::LocalFoldersBuildJob( bool canBuild, QObject *parent ) + : TransactionSequence( parent ) + , d( new Private( this ) ) +{ + d->canBuild = canBuild; +} + +LocalFoldersBuildJob::~LocalFoldersBuildJob() +{ + delete d; +} + +const Collection::List &LocalFoldersBuildJob::defaultFolders() const +{ + return d->defaultFolders; +} + +#if 0 +const QSet &LocalFoldersBuildJob::customFolders() const +{ + return d->customFolders; +} +#endif + +void LocalFoldersBuildJob::doStart() +{ + // Update config and check if resource exists. + Settings::self()->readConfig(); + kDebug() << "resourceId from settings" << Settings::resourceId(); + AgentInstance resource = AgentManager::self()->instance( Settings::resourceId() ); + if( resource.isValid() ) { + // Good, the resource exists. + d->fetchCollections(); + } else { + // Create resource if allowed. + if( !d->canBuild ) { + setError( UserDefinedError ); + setErrorText( QLatin1String( "Resource not found, and creating not allowed." ) ); + emitResult(); + } else { + kDebug() << "Creating maildir resource."; + AgentType type = AgentManager::self()->type( QString::fromLatin1( "akonadi_maildir_resource" ) ); + AgentInstanceCreateJob *job = new AgentInstanceCreateJob( type, this ); + connect( job, SIGNAL(result(KJob*)), this, SLOT(resourceCreateResult(KJob*)) ); + job->start(); // non-Akonadi::Job + } + } +} + + + +void LocalFoldersBuildJob::Private::resourceCreateResult( KJob *job ) +{ + Q_ASSERT( canBuild ); + if( job->error() ) { + q->setError( UserDefinedError ); + q->setErrorText( QLatin1String( "Resource creation failed." ) ); + q->emitResult(); + } else { + AgentInstance agent; + + // Get the resource instance, and save its ID to config. + { + Q_ASSERT( dynamic_cast( job ) ); + AgentInstanceCreateJob *cjob = static_cast( job ); + agent = cjob->instance(); + Settings::setResourceId( agent.identifier() ); + kDebug() << "Created maildir resource with id" << Settings::resourceId(); + } + + // Configure the resource. + { + agent.setName( i18n( "Local Mail Folders" ) ); + QDBusInterface conf( QString::fromLatin1( "org.freedesktop.Akonadi.Resource." ) + Settings::resourceId(), + QString::fromLatin1( "/Settings" ), + QString::fromLatin1( "org.kde.Akonadi.Maildir.Settings" ) ); + QDBusReply reply = conf.call( QString::fromLatin1( "setPath" ), + KGlobal::dirs()->localxdgdatadir() + QString::fromLatin1( "mail" ) ); + if( !reply.isValid() ) { + q->setError( UserDefinedError ); + q->setErrorText( QLatin1String( "Failed to set the root maildir via D-Bus." ) ); + q->emitResult(); + } else { + agent.reconfigure(); + } + } + + // Sync the resource. + if( !q->error() ) + { + ResourceSynchronizationJob *sjob = new ResourceSynchronizationJob( agent, q ); + QObject::connect( sjob, SIGNAL(result(KJob*)), q, SLOT(resourceSyncResult(KJob*)) ); + sjob->start(); // non-Akonadi + } + } +} + +void LocalFoldersBuildJob::Private::resourceSyncResult( KJob *job ) +{ + Q_ASSERT( canBuild ); + if( job->error() ) { + q->setError( UserDefinedError ); + q->setErrorText( QLatin1String( "ResourceSynchronizationJob failed." ) ); + q->emitResult(); + } else { + fetchCollections(); + } +} + +void LocalFoldersBuildJob::Private::fetchCollections() +{ + kDebug() << "Fetching collections in the maildir resource."; + + CollectionFetchJob *job = new CollectionFetchJob( Collection::root(), CollectionFetchJob::Recursive, q ); + job->setResource( Settings::resourceId() ); // limit search + QObject::connect( job, SIGNAL(result(KJob*)), q, SLOT(collectionFetchResult(KJob*)) ); +} + +void LocalFoldersBuildJob::Private::collectionFetchResult( KJob *job ) +{ + QSet cols; + + // Get the root maildir collection, and put all the other ones in cols. + { + Q_ASSERT( dynamic_cast( job ) ); + CollectionFetchJob *fjob = static_cast( job ); + Q_FOREACH( const Collection &col, fjob->collections() ) { + if( col.parent() == Collection::root().id() ) { + // This is the root maildir collection. + Q_ASSERT( !defaultFolders[ LocalFolders::Root ].isValid() ); + defaultFolders[ LocalFolders::Root ] = col; + } else { + // This is some local folder. + cols.insert( col ); + } + } + } + + // Go no further if the root maildir was not found. + if( !defaultFolders[ LocalFolders::Root ].isValid() ) { + q->setError( UserDefinedError ); + q->setErrorText( QLatin1String( "Failed to fetch root maildir collection." ) ); + q->emitResult(); + return; + } + + // Get the default folders. They must be direct children of the root maildir, + // and have appropriate names. Leave all the other folders in cols. + Q_FOREACH( const Collection &col, cols ) { + if( col.parent() == defaultFolders[ LocalFolders::Root ].id() ) { + // This is a direct child; guess its type. + LocalFolders::Type type = typeForName( col.name() ); + if( type != LocalFolders::Custom ) { + // This is one of the default folders. + Q_ASSERT( !defaultFolders[ type ].isValid() ); + defaultFolders[ type ] = col; + cols.remove( col ); + } + } + } + + // Everything left in cols is custom folders. + //customFolders = cols; + + // Some collections may still need to be created (if the evil user deleted + // them from disk, for example), and some may need to be configured (rights, + // icon, i18n'ed name). + if( canBuild ) { + createAndConfigureCollections(); + } else { + for( int type = 0; type < LocalFolders::LastDefaultType; type++ ) { + if( !defaultFolders[ type ].isValid() ) { + q->setError( UserDefinedError ); + q->setErrorText( QString::fromLatin1( "Failed to fetch %1 collection." ).arg( nameForType( type ) ) ); + q->emitResult(); + break; + } + } + + // If all collections are valid, we are done. + if( !q->error() ) { + q->commit(); + } + } +} + +void LocalFoldersBuildJob::Private::createAndConfigureCollections() +{ + Q_ASSERT( canBuild ); + + // We need the root maildir at least. + Q_ASSERT( defaultFolders[ LocalFolders::Root ].isValid() ); + + for( int type = 0; type < LocalFolders::LastDefaultType; type++ ) { + if( !defaultFolders[ type ].isValid() ) { + // This default folder needs to be created. + kDebug() << "Creating default folder" << nameForType( type ); + Q_ASSERT( type != LocalFolders::Root ); + Collection col; + col.setParent( defaultFolders[ LocalFolders::Root ].id() ); + col.setName( nameForType( type ) ); + EntityDisplayAttribute *attr = new EntityDisplayAttribute; + attr->setIconName( iconNameForType( type ) ); + attr->setDisplayName( i18nc( "local mail folder", nameForType( type ).toLatin1() ) ); + col.addAttribute( attr ); + col.setRights( Collection::Rights( Collection::AllRights ^ Collection::CanDeleteCollection ) ); + CollectionCreateJob *cjob = new CollectionCreateJob( col, q ); + QObject::connect( cjob, SIGNAL(result(KJob*)), q, SLOT(collectionCreateResult(KJob*)) ); + } else if( defaultFolders[ type ].rights() & Collection::CanDeleteCollection ) { + // This default folder needs to be modified. + kDebug() << "Modifying default folder" << nameForType( type ); + Collection &col = defaultFolders[ type ]; + EntityDisplayAttribute *attr = new EntityDisplayAttribute; + attr->setIconName( iconNameForType( type ) ); + attr->setDisplayName( i18nc( "local mail folder", nameForType( type ).toLatin1() ) ); + col.addAttribute( attr ); + col.setRights( Collection::Rights( Collection::AllRights ^ Collection::CanDeleteCollection ) ); + CollectionModifyJob *mjob = new CollectionModifyJob( col, q ); + QObject::connect( mjob, SIGNAL(result(KJob*)), q, SLOT(collectionModifyResult(KJob*)) ); + } + + // NOTE: We do not set the mime type here because the maildir resource does that. + // It sets inode/directory (for child collections) and message/rfc822 (for messages), + // which is exactly what we want. + } + + // When those subjobs are finished, we are done. + Settings::self()->writeConfig(); + q->commit(); +} + +void LocalFoldersBuildJob::Private::collectionCreateResult( KJob *job ) +{ + if( job->error() ) { + kDebug() << "CollectionCreateJob failed."; + // TransactionSequence will take care of the error. + return; + } + + Q_ASSERT( dynamic_cast( job ) ); + CollectionCreateJob *cjob = static_cast( job ); + const Collection col = cjob->collection(); + int type = typeForName( col.name() ); + Q_ASSERT( type < LocalFolders::LastDefaultType ); + Q_ASSERT( !defaultFolders[ type ].isValid() ); + defaultFolders[ type ] = col; +} + +void LocalFoldersBuildJob::Private::collectionModifyResult( KJob *job ) +{ + if( job->error() ) { + kDebug() << "CollectionModifyJob failed."; + // TransactionSequence will take care of the error. + return; + } + + Q_ASSERT( dynamic_cast( job ) ); + // Our collection in defaultFolders[...] is already modified. + // (And CollectionModifyJob does not provide collection().) +} + + +// static +QString LocalFoldersBuildJob::Private::nameForType( int type ) +{ + switch( type ) { + case LocalFolders::Root: return QLatin1String( "Local Folders" ); + case LocalFolders::Inbox: return QLatin1String( "inbox" ); + case LocalFolders::Outbox: return QLatin1String( "outbox" ); + case LocalFolders::SentMail: return QLatin1String( "sent-mail" ); + case LocalFolders::Trash: return QLatin1String( "trash" ); + case LocalFolders::Drafts: return QLatin1String( "drafts" ); + case LocalFolders::Templates: return QLatin1String( "templates" ); + default: Q_ASSERT( false ); return QString(); + } +} + +//static +QString LocalFoldersBuildJob::Private::iconNameForType( int type ) +{ + // Icons imitating KMail. + switch( type ) { + case LocalFolders::Root: return QString(); + case LocalFolders::Inbox: return QLatin1String( "mail-folder-inbox" ); + case LocalFolders::Outbox: return QLatin1String( "mail-folder-outbox" ); + case LocalFolders::SentMail: return QLatin1String( "mail-folder-sent" ); + case LocalFolders::Trash: return QLatin1String( "user-trash" ); + case LocalFolders::Drafts: return QLatin1String( "document-properties" ); + case LocalFolders::Templates: return QLatin1String( "document-new" ); + default: Q_ASSERT( false ); return QString(); + } +} + +//static +LocalFolders::Type LocalFoldersBuildJob::Private::typeForName( const QString &name ) +{ + if( name == QLatin1String( "root" ) ) { + Q_ASSERT( false ); + return LocalFolders::Root; + } else if( name == QLatin1String( "inbox" ) ) { + return LocalFolders::Inbox; + } else if( name == QLatin1String( "outbox" ) ) { + return LocalFolders::Outbox; + } else if( name == QLatin1String( "sent-mail" ) ) { + return LocalFolders::SentMail; + } else if( name == QLatin1String( "trash" ) ) { + return LocalFolders::Trash; + } else if( name == QLatin1String( "drafts" ) ) { + return LocalFolders::Drafts; + } else if( name == QLatin1String( "templates" ) ) { + return LocalFolders::Templates; + } else { + return LocalFolders::Custom; + } +} + + +#include "localfoldersbuildjob_p.moc" diff --git a/akonadi/kmime/localfoldersbuildjob_p.h b/akonadi/kmime/localfoldersbuildjob_p.h new file mode 100644 index 000000000..f58868808 --- /dev/null +++ b/akonadi/kmime/localfoldersbuildjob_p.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 AKONADI_LOCALFOLDERSBUILDJOB_P_H +#define AKONADI_LOCALFOLDERSBUILDJOB_P_H + +#include +#include + +namespace Akonadi { + +/** + A job building and fetching the local folder structure for LocalFolders. + + Whether this job is allowed to create stuff or not is determined by whether + the LocalFolders who created it is the main instance of LocalFolders or not. + (This is done to avoid race conditions.) + + Logic if main instance: + 1) if loading the resource from config fails, create the resource. + 2) if after fetching, some collections need to be created / modified, do that. + 3) if creating / modification succeeded -> success. + else -> failure. + + Logic if not main instance: + 1) if loading the resource from config fails -> failure. + 2) if after fetching, some collections need to be created / modified -> failure. + 2) if all collections were fetched ok -> success. + + @author Constantin Berzan + @since 4.4 +*/ +class LocalFoldersBuildJob : public TransactionSequence +{ + Q_OBJECT + + public: + /** + @param canBuild Whether this job is allowed to build the folder + structure (as opposed to only fetching it). + */ + explicit LocalFoldersBuildJob( bool canBuild, QObject *parent = 0 ); + ~LocalFoldersBuildJob(); + + const Collection::List &defaultFolders() const; + //const QSet &customFolders() const; + + protected: + /* reimpl */ + virtual void doStart(); + + private: + class Private; + friend class Private; + Private *const d; + + Q_PRIVATE_SLOT( d, void resourceCreateResult( KJob* ) ) + Q_PRIVATE_SLOT( d, void resourceSyncResult( KJob* ) ) + Q_PRIVATE_SLOT( d, void collectionFetchResult( KJob* ) ) + Q_PRIVATE_SLOT( d, void collectionCreateResult( KJob* ) ) + Q_PRIVATE_SLOT( d, void collectionModifyResult( KJob* ) ) + +}; + +} // namespace Akonadi + +#endif // AKONADI_LOCALFOLDERSBUILDJOB_P_H diff --git a/akonadi/kmime/localfolderssettings.kcfgc b/akonadi/kmime/localfolderssettings.kcfgc new file mode 100644 index 000000000..d630d162e --- /dev/null +++ b/akonadi/kmime/localfolderssettings.kcfgc @@ -0,0 +1,7 @@ +File=localfolders.kcfg +ClassName=LocalFoldersSettings +NameSpace=Akonadi +Singleton=true +ItemAccessors=true +Mutators=true +SetUserTextx=true diff --git a/akonadi/kmime/resourcesynchronizationjob.cpp b/akonadi/kmime/resourcesynchronizationjob.cpp new file mode 100644 index 000000000..e6a8946f2 --- /dev/null +++ b/akonadi/kmime/resourcesynchronizationjob.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2009 Volker Krause + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "resourcesynchronizationjob.h" + +#include +#include + +#include +#include + +#include +#include +#include + +namespace Akonadi +{ + +class ResourceSynchronizationJobPrivate +{ + public: + ResourceSynchronizationJobPrivate() : + interface( 0 ), + safetyTimer( 0 ), + timeoutCount( 0 ) + {} + + AgentInstance instance; + QDBusInterface* interface; + QTimer* safetyTimer; + int timeoutCount; + static int timeoutCountLimit; +}; + +int ResourceSynchronizationJobPrivate::timeoutCountLimit = 60; + +ResourceSynchronizationJob::ResourceSynchronizationJob(const AgentInstance& instance, QObject* parent) : + KJob( parent ), + d( new ResourceSynchronizationJobPrivate ) +{ + d->instance = instance; + d->safetyTimer = new QTimer( this ); + connect( d->safetyTimer, SIGNAL(timeout()), SLOT(slotTimeout()) ); + d->safetyTimer->setInterval( 10 * 1000 ); + d->safetyTimer->setSingleShot( false ); +} + +ResourceSynchronizationJob::~ResourceSynchronizationJob() +{ + delete d; +} + +void ResourceSynchronizationJob::start() +{ + if ( !d->instance.isValid() ) { + setError( UserDefinedError ); + setErrorText( i18n( "Invalid resource instance." ) ); + emitResult(); + return; + } + + d->interface = new QDBusInterface( QString::fromLatin1( "org.freedesktop.Akonadi.Resource.%1" ).arg( d->instance.identifier() ), + QString::fromLatin1( "/" ), + QString::fromLatin1( "org.freedesktop.Akonadi.Resource" ), QDBusConnection::sessionBus(), this ); + connect( d->interface, SIGNAL(synchronized()), SLOT(slotSynchronized()) ); + + if ( d->interface->isValid() ) { + d->instance.synchronize(); + d->safetyTimer->start(); + } else { + setError( UserDefinedError ); + setErrorText( i18n( "Unable to obtain D-Bus interface for resource '%1'", d->instance.identifier() ) ); + emitResult(); + return; + } +} + +void ResourceSynchronizationJob::slotSynchronized() +{ + disconnect( d->interface, SIGNAL(synchronized()), this, SLOT(slotSynchronized()) ); + d->safetyTimer->stop(); + emitResult(); +} + +void ResourceSynchronizationJob::slotTimeout() +{ + d->instance = AgentManager::self()->instance( d->instance.identifier() ); + d->timeoutCount++; + + if ( d->timeoutCount > d->timeoutCountLimit ) { + d->safetyTimer->stop(); + setError( UserDefinedError ); + setErrorText( i18n( "Resource synchronization timed out." ) ); + emitResult(); + return; + } + + if ( d->instance.status() == AgentInstance::Idle ) { + // try again, we might have lost the synchronized() signal + kDebug() << "trying again to sync resource" << d->instance.identifier(); + d->instance.synchronize(); + } +} + +} + +#include "resourcesynchronizationjob.moc" diff --git a/akonadi/kmime/resourcesynchronizationjob.h b/akonadi/kmime/resourcesynchronizationjob.h new file mode 100644 index 000000000..6ed04db2f --- /dev/null +++ b/akonadi/kmime/resourcesynchronizationjob.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2009 Volker Krause + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef AKONADI_RESOURCESYNCJOB_H +#define AKONADI_RESOURCESYNCJOB_H + +#include + +namespace Akonadi { + +class AgentInstance; +class ResourceSynchronizationJobPrivate; + +/** + Synchronizes a given resource. +*/ +class ResourceSynchronizationJob : public KJob +{ + Q_OBJECT + public: + /** + Create a new synchronization job for the given agent. + */ + ResourceSynchronizationJob( const AgentInstance &instance, QObject *parent = 0 ); + + /** + Destructor. + */ + ~ResourceSynchronizationJob(); + + /* reimpl */ + void start(); + + private slots: + void slotSynchronized(); + void slotTimeout(); + + private: + ResourceSynchronizationJobPrivate* const d; +}; + +} + +#endif diff --git a/akonadi/kmime/tests/CMakeLists.txt b/akonadi/kmime/tests/CMakeLists.txt new file mode 100644 index 000000000..8741b4c09 --- /dev/null +++ b/akonadi/kmime/tests/CMakeLists.txt @@ -0,0 +1,55 @@ +set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) + +# TODO apparently QTEST_AKONADIMAIN doesn't like NO_CASTs... +remove_definitions( -DQT_NO_CAST_FROM_ASCII ) +remove_definitions( -DQT_NO_CAST_TO_ASCII ) + +set( requester_srcs foldersrequester.cpp ) +kde4_add_executable( requester TEST ${requester_srcs} ) +target_link_librarieS( requester akonadi-kmime ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY}) +# for racetest +set( requester_exe "QLatin1String( \"${CMAKE_CURRENT_BINARY_DIR}/requester\" )" ) +add_definitions( -DREQUESTER_EXE='${requester_exe}' ) + + + + +macro(add_akonadi_isolated_test _source) + get_filename_component(_targetName ${_source} NAME_WE) + set(_srcList ${_source} ) + + kde4_add_executable(${_targetName} TEST ${_srcList}) + target_link_libraries(${_targetName} + ${QT_QTTEST_LIBRARY} + ${QT_QTGUI_LIBRARY} + ${KDE4_AKONADI_LIBS} + ${KDE4_KDECORE_LIBS} + ${KDE4_MAILTRANSPORT_LIBS} + ${KDE4_KMIME_LIBS} + ${QT_QTCORE_LIBRARY} + ${QT_QTDBUS_LIBRARY} + akonadi-kmime + ) + + # based on kde4_add_unit_test + if (WIN32) + get_target_property( _loc ${_targetName} LOCATION ) + set(_executable ${_loc}.bat) + else (WIN32) + set(_executable ${EXECUTABLE_OUTPUT_PATH}/${_targetName}) + endif (WIN32) + if (UNIX) + set(_executable ${_executable}.shell) + endif (UNIX) + + find_program(_testrunner akonaditest) + + add_test( akonadikmime-${_targetName} ${_testrunner} -c ${CMAKE_CURRENT_SOURCE_DIR}/unittestenv/config.xml ${_executable} ) +endmacro(add_akonadi_isolated_test) + + + + +add_akonadi_isolated_test( customfoldertest.cpp ) +add_akonadi_isolated_test( racetest.cpp ) + diff --git a/akonadi/kmime/tests/TODO b/akonadi/kmime/tests/TODO new file mode 100644 index 000000000..ff21324a2 --- /dev/null +++ b/akonadi/kmime/tests/TODO @@ -0,0 +1,4 @@ +LocalFolders: +* test for deletion of actual dir from local file system +* test for user creating a custom folder with a default folder name (such as 'inbox') + diff --git a/akonadi/kmime/tests/customfoldertest.cpp b/akonadi/kmime/tests/customfoldertest.cpp new file mode 100644 index 000000000..2debb5802 --- /dev/null +++ b/akonadi/kmime/tests/customfoldertest.cpp @@ -0,0 +1,246 @@ +/* + Copyright 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 "customfoldertest.h" + +#include +#include + +#include +#include +#include +#include +#include + +using namespace Akonadi; + + +void CustomFolderTest::initTestCase() +{ + QVERIFY( Control::start() ); + QTest::qWait( 1000 ); +} + +void CustomFolderTest::testDefaultFolders() +{ + LocalFolders::self()->fetch(); + QTest::kWaitForSignal( LocalFolders::self(), SIGNAL(foldersReady()) ); + for( int type = LocalFolders::Root; type < LocalFolders::LastDefaultType; type++ ) { + QVERIFY( LocalFolders::self()->folder( type ).isValid() ); + + // TODO verify icon, name, rights. + // TODO verify functions like outbox(). + } +} + +void CustomFolderTest::testCustomFoldersDontRebuild() +{ + QVERIFY( LocalFolders::self()->isReady() ); + Collection a, b; + + // Create a custom folder in root. + { + const Collection root = LocalFolders::self()->root(); + QVERIFY( root.isValid() ); + + a.setParent( root.id() ); + a.setName( "a" ); + CollectionCreateJob *cjob = new CollectionCreateJob( a ); + AKVERIFYEXEC( cjob ); + a = cjob->collection(); + QVERIFY( LocalFolders::self()->isReady() ); + } + + // Create a custom folder in a default folder (inbox). + { + const Collection inbox = LocalFolders::self()->inbox(); + QVERIFY( inbox.isValid() ); + + b.setParent( inbox.id() ); + b.setName( "b" ); + CollectionCreateJob *cjob = new CollectionCreateJob( b ); + AKVERIFYEXEC( cjob ); + b = cjob->collection(); + QVERIFY( LocalFolders::self()->isReady() ); + } + + QTest::qWait( 500 ); + + // Delete those, and make sure LocalFolders does not rebuild. + { + QVERIFY( LocalFolders::self()->isReady() ); + CollectionDeleteJob *djob = new CollectionDeleteJob( a ); + AKVERIFYEXEC( djob ); + QVERIFY( LocalFolders::self()->isReady() ); + djob = new CollectionDeleteJob( b ); + AKVERIFYEXEC( djob ); + QVERIFY( LocalFolders::self()->isReady() ); + + for( int i = 0; i < 200; i++ ) { + QVERIFY( LocalFolders::self()->isReady() ); + QTest::qWait( 10 ); + } + } + + // Check that a fetch() does not trigger a rebuild. + { + LocalFolders::self()->fetch(); + QVERIFY( LocalFolders::self()->isReady() ); + } +} + +// NOTE: This was written when I added LocalFolders::customFolders(). +// I removed that later because I'm not sure how it could be useful. +#if 0 +void CustomFolderTest::testCustomFoldersInRoot() +{ + QSet mine; + QVERIFY( LocalFolders::self()->isReady() ); + const Collection root = LocalFolders::self()->root(); + QVERIFY( root.isValid() ); + + // No custom folders yet. + QVERIFY( LocalFolders::self()->customFolders().isEmpty() ); + + // Create hierarchy of custom folders under root: + // (a/(a1,a2/a2i), b/b1) + { + Collection a; + a.setParent( root.id() ); + a.setName( "a" ); + CollectionCreateJob *cjob = new CollectionCreateJob( a ); + AKVERIFYEXEC( cjob ); + a = cjob->collection(); + mine.insert( a ); + + Collection a1; + a1.setParent( a.id() ); + a1.setName( "a1" ); + cjob = new CollectionCreateJob( a1 ); + AKVERIFYEXEC( cjob ); + a1 = cjob->collection(); + mine.insert( a1 ); + + Collection a2; + a2.setParent( a.id() ); + a2.setName( "a2" ); + cjob = new CollectionCreateJob( a2 ); + AKVERIFYEXEC( cjob ); + a2 = cjob->collection(); + mine.insert( a2 ); + + Collection a2i; + a2i.setParent( a2.id() ); + a2i.setName( "a2i" ); + cjob = new CollectionCreateJob( a2i ); + AKVERIFYEXEC( cjob ); + a2i = cjob->collection(); + mine.insert( a2i ); + + Collection b; + b.setParent( root.id() ); + b.setName( "b" ); + cjob = new CollectionCreateJob( b ); + AKVERIFYEXEC( cjob ); + b = cjob->collection(); + mine.insert( b ); + + Collection b1; + b1.setParent( root.id() ); + b1.setName( "b1" ); + cjob = new CollectionCreateJob( b1 ); + AKVERIFYEXEC( cjob ); + b1 = cjob->collection(); + mine.insert( b1 ); + } + + // Check that LocalFolders is aware of everything. + QTest::qWait( 500 ); + QSet theirs = LocalFolders::self()->customFolders(); + QCOMPARE( mine, theirs ); + + // Remove the custom folders and make sure LocalFolders does not rebuild. + foreach( const Collection &col, mine ) { + QVERIFY( LocalFolders::self()->isReady() ); + CollectionDeleteJob *djob = new CollectionDeleteJob( col ); + AKVERIFYEXEC( djob ); + + for( int i = 0; i < 50; i++ ) { + QVERIFY( LocalFolders::self()->isReady() ); + QTest::qWait( 10 ); + } + + mine.remove( col ); + theirs = LocalFolders::self()->customFolders(); + QCOMPARE( mine, theirs ); + } + + // Check that a fetch() does not trigger a rebuild. + LocalFolders::self()->fetch(); + QVERIFY( LocalFolders::self()->isReady() ); + + // No custom folders after deletion. + QVERIFY( LocalFolders::self()->customFolders().isEmpty() ); +} + +void CustomFolderTest::testCustomFoldersInDefaultFolders() +{ + QVERIFY( LocalFolders::self()->isReady() ); + const Collection inbox = LocalFolders::self()->inbox(); + QVERIFY( inbox.isValid() ); + + // No custom folders yet. + QVERIFY( LocalFolders::self()->customFolders().isEmpty() ); + + // Create a custom folder under inbox. + Collection col; + col.setParent( inbox.id() ); + col.setName( "col" ); + CollectionCreateJob *cjob = new CollectionCreateJob( col ); + AKVERIFYEXEC( cjob ); + col = cjob->collection(); + + // Verify that LocalFolders is aware of it. + QTest::qWait( 500 ); + QSet theirs = LocalFolders::self()->customFolders(); + QCOMPARE( theirs.count(), 1 ); + QVERIFY( theirs.contains( col ) ); + + // Delete it and make sure LocalFolders does not rebuild. + QVERIFY( LocalFolders::self()->isReady() ); + CollectionDeleteJob *djob = new CollectionDeleteJob( col ); + AKVERIFYEXEC( djob ); + for( int i = 0; i < 50; i++ ) { + QVERIFY( LocalFolders::self()->isReady() ); + QTest::qWait( 10 ); + } + + // Check that a fetch() does not trigger a rebuild. + LocalFolders::self()->fetch(); + QVERIFY( LocalFolders::self()->isReady() ); + + // No custom folders after deletion. + QVERIFY( LocalFolders::self()->customFolders().isEmpty() ); +} +#endif + + +QTEST_AKONADIMAIN( CustomFolderTest, NoGUI ) + +#include "customfoldertest.moc" diff --git a/mailtransport/configmodule.h b/akonadi/kmime/tests/customfoldertest.h similarity index 60% copy from mailtransport/configmodule.h copy to akonadi/kmime/tests/customfoldertest.h index 6994d37bd..684fdeb14 100644 --- a/mailtransport/configmodule.h +++ b/akonadi/kmime/tests/customfoldertest.h @@ -1,39 +1,46 @@ /* - Copyright (c) 2007 Volker Krause + Copyright 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 MAILTRANSPORT_CONFIGMODULE_H -#define MAILTRANSPORT_CONFIGMODULE_H +#ifndef CUSTOMFOLDERTEST_H +#define CUSTOMFOLDERTEST_H -#include +#include -namespace MailTransport { +#include /** - KCModule for transport management. -*/ -class ConfigModule : public KCModule + Tests the correct handling of custom (i.e. user-created, non-default) folders + in LocalFolders. + */ +class CustomFolderTest : public QObject { - public: - explicit ConfigModule( QWidget *parent = 0, - const QVariantList &args = QVariantList() ); -}; + Q_OBJECT + + private Q_SLOTS: + void initTestCase(); + void testDefaultFolders(); + void testCustomFoldersDontRebuild(); +#if 0 + void testCustomFoldersInRoot(); + void testCustomFoldersInDefaultFolders(); +#endif -} +}; #endif diff --git a/akonadi/kmime/tests/foldersrequester.cpp b/akonadi/kmime/tests/foldersrequester.cpp new file mode 100644 index 000000000..2abff4c00 --- /dev/null +++ b/akonadi/kmime/tests/foldersrequester.cpp @@ -0,0 +1,67 @@ +/* + 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 "foldersrequester.h" + +#include +#include +#include + +#include +#include +#include + +using namespace Akonadi; + + +Requester::Requester() +{ + Control::start(); + + connect( LocalFolders::self(), SIGNAL( foldersReady() ), + this, SLOT( checkFolders() ) ); + LocalFolders::self()->fetch(); +} + +void Requester::checkFolders() +{ + Collection outbox = LocalFolders::self()->outbox(); + Collection sentMail = LocalFolders::self()->sentMail(); + + kDebug() << "Got outbox" << outbox.id() << "sent-mail" << sentMail.id(); + + if( !outbox.isValid() || !sentMail.isValid() ) { + KApplication::exit( 1 ); + } else { + KApplication::exit( 2 ); + } +} + +int main( int argc, char **argv ) +{ + KCmdLineArgs::init( argc, argv, "foldersrequester", 0, + ki18n( "foldersrequester" ), "0", + ki18n( "An app that requests LocalFolders" ) ); + KApplication app; + new Requester(); + return app.exec(); +} + + +#include "foldersrequester.moc" diff --git a/mailtransport/configmodule.h b/akonadi/kmime/tests/foldersrequester.h similarity index 60% copy from mailtransport/configmodule.h copy to akonadi/kmime/tests/foldersrequester.h index 6994d37bd..cee1c7bc2 100644 --- a/mailtransport/configmodule.h +++ b/akonadi/kmime/tests/foldersrequester.h @@ -1,39 +1,46 @@ /* - Copyright (c) 2007 Volker Krause + 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 MAILTRANSPORT_CONFIGMODULE_H -#define MAILTRANSPORT_CONFIGMODULE_H +#ifndef FOLDERSREQUESTER_H +#define FOLDERSREQUESTER_H -#include - -namespace MailTransport { +#include /** - KCModule for transport management. + This class requests the LocalFolders, then exits the app with a status of 2 + if they were delivered OK, or 1 if they were not. + + NOTE: The non-standard exit status 2 in case of success is to make feel more + comfortable than checking for zero (I actually had a bug causing it to always + return zero). */ -class ConfigModule : public KCModule +class Requester : public QObject { + Q_OBJECT + public: - explicit ConfigModule( QWidget *parent = 0, - const QVariantList &args = QVariantList() ); + Requester(); + + private slots: + void checkFolders(); + }; -} #endif diff --git a/akonadi/kmime/tests/racetest.cpp b/akonadi/kmime/tests/racetest.cpp new file mode 100644 index 000000000..76c76ce10 --- /dev/null +++ b/akonadi/kmime/tests/racetest.cpp @@ -0,0 +1,164 @@ +/* + Copyright 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 "racetest.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define TIMEOUT_SECONDS 20 +#define MAXCOUNT 10 +// NOTE: REQUESTER_EXE is defined by cmake. + +using namespace Akonadi; + + +void RaceTest::initTestCase() +{ + QVERIFY( Control::start() ); + QTest::qWait( 1000 ); // give the MDA time to start so that we can kill it in peace +} + +void RaceTest::testMultipleProcesses_data() +{ + QTest::addColumn( "count" ); // how many processes to create + QTest::addColumn( "delay" ); // number of ms to wait before starting next process + + QTest::newRow( "1-nodelay" ) << 1 << 0; + QTest::newRow( "2-nodelay" ) << 2 << 0; + QTest::newRow( "5-nodelay" ) << 5 << 0; + QTest::newRow( "10-nodelay" ) << 10 << 0; + QTest::newRow( "2-shortdelay" ) << 2 << 100; + QTest::newRow( "5-shortdelay" ) << 5 << 100; + QTest::newRow( "10-shortdelay" ) << 10 << 100; + QTest::newRow( "2-longdelay" ) << 2 << 1000; + QTest::newRow( "5-longdelay" ) << 5 << 1000; + QTest::newRow( "5-verylongdelay" ) << 5 << 4000; + Q_ASSERT( 10 <= MAXCOUNT ); +} + +void RaceTest::testMultipleProcesses() +{ + QFETCH( int, count ); + QFETCH( int, delay ); + + killZombies(); + + // Remove all maildir instances (at most 1 really) and MDAs (which use LocalFolders). + // (This is to ensure that one of *our* instances is the main instance.) + AgentType::List types; + types.append( AgentManager::self()->type( QLatin1String( "akonadi_maildir_resource" ) ) ); + types.append( AgentManager::self()->type( QLatin1String( "akonadi_maildispatcher_agent" ) ) ); + AgentInstance::List instances = AgentManager::self()->instances(); + foreach( const AgentInstance &instance, instances ) { + if( types.contains( instance.type() ) ) { + kDebug() << "Removing instance of type" << instance.type().identifier(); + AgentManager::self()->removeInstance( instance ); + QTest::kWaitForSignal( AgentManager::self(), SIGNAL( instanceRemoved( const Akonadi::AgentInstance& ) ) ); + } + } + instances = AgentManager::self()->instances(); + foreach( const AgentInstance &instance, instances ) { + QVERIFY( !types.contains( instance.type() ) ); + } + + QSignalSpy *errorSpy[ MAXCOUNT ]; + QSignalSpy *finishedSpy[ MAXCOUNT ]; + for( int i = 0; i < count; i++ ) { + kDebug() << "Starting process" << i + 1 << "of" << count; + KProcess *proc = new KProcess; + procs.append( proc ); + proc->setProgram( REQUESTER_EXE ); + errorSpy[i] = new QSignalSpy( proc, SIGNAL( error( QProcess::ProcessError ) ) ); + finishedSpy[i] = new QSignalSpy( proc, SIGNAL( finished( int, QProcess::ExitStatus ) ) ); + proc->start(); + QTest::qWait( delay ); + } + kDebug() << "Launched" << count << "processes."; + + int seconds = 0; + int error, finished; + while( true ) { + seconds++; + QTest::qWait( 1000 ); + + error = 0; + finished = 0; + for( int i = 0; i < count; i++ ) { + if( errorSpy[i]->count() > 0 ) + error++; + if( finishedSpy[i]->count() > 0 ) + finished++; + } + kDebug() << seconds << "seconds elapsed." << error << "processes error'd," + << finished << "processes finished."; + + if( error + finished >= count ) + break; + +#if 0 + if( seconds >= TIMEOUT_SECONDS ) { + kDebug() << "Timeout, gdb master!"; + QTest::qWait( 1000*1000 ); + } +#endif + QVERIFY2( seconds < TIMEOUT_SECONDS, "Timeout" ); + } + + QCOMPARE( error, 0 ); + QCOMPARE( finished, count ); + for( int i = 0; i < count; i++ ) { + kDebug() << "Checking exit status of process" << i + 1 << "of" << count; + QCOMPARE( finishedSpy[i]->count(), 1 ); + QList args = finishedSpy[i]->takeFirst(); + QCOMPARE( args[0].toInt(), 2 ); + } + + while( !procs.isEmpty() ) { + KProcess *proc = procs.takeFirst(); + QCOMPARE( proc->exitStatus(), QProcess::NormalExit ); + QCOMPARE( proc->exitCode(), 2 ); + delete proc; + } + QVERIFY( procs.isEmpty() ); +} + +void RaceTest::killZombies() +{ + while( !procs.isEmpty() ) { + // These processes probably hung, and will never recover, so we need to kill them. + // (This happens if the last test failed.) + kDebug() << "Killing zombies from the past."; + KProcess *proc = procs.takeFirst(); + proc->kill(); + proc->deleteLater(); + } +} + +QTEST_AKONADIMAIN( RaceTest, NoGUI ) + +#include "racetest.moc" diff --git a/mailtransport/legacydecrypt.h b/akonadi/kmime/tests/racetest.h similarity index 55% copy from mailtransport/legacydecrypt.h copy to akonadi/kmime/tests/racetest.h index 209a3e9c1..b075af4b0 100644 --- a/mailtransport/legacydecrypt.h +++ b/akonadi/kmime/tests/racetest.h @@ -1,49 +1,51 @@ /* - Copyright (c) 2007 Volker Krause - - KNode code: - Copyright (c) 1999-2005 the KNode authors. // krazy:exclude=copyright + Copyright 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 MAILTRANSPORT_LEGACYDECRYPT_H -#define MAILTRANSPORT_LEGACYDECRYPT_H +#ifndef RACETEST_H +#define RACETEST_H + +#include +#include -#include +class KProcess; -namespace MailTransport { /** - Methods to read passwords from config files still using legacy encryption. -*/ -class Legacy + This tests the ability of LocalFolders to exist peacefully in multiple processes. + The main instance (normally the first one created) is supposed to create the + resource and collections, while the other instances are supposed to wait and + then just fetch the collections. + */ +class RaceTest : public QObject { - public: - /** - Read data encrypted using KMail's legacy encryption. - */ - static QString decryptKMail( const QString &data ); - - /** - Read data encrypted using KNode's legacy encryption. - */ - static QString decryptKNode( const QString &data ); + Q_OBJECT + + private Q_SLOTS: + void initTestCase(); + void testMultipleProcesses_data(); + void testMultipleProcesses(); + void killZombies(); + + private: + QList procs; + }; -} #endif diff --git a/akonadi/kmime/tests/unittestenv/config.xml b/akonadi/kmime/tests/unittestenv/config.xml new file mode 100644 index 000000000..47d7cb0b8 --- /dev/null +++ b/akonadi/kmime/tests/unittestenv/config.xml @@ -0,0 +1,5 @@ + + kdehome + xdgconfig + xdglocal + diff --git a/akonadi/kmime/tests/unittestenv/kdehome/share/config/akonadi-firstrunrc b/akonadi/kmime/tests/unittestenv/kdehome/share/config/akonadi-firstrunrc new file mode 100644 index 000000000..1cac492a3 --- /dev/null +++ b/akonadi/kmime/tests/unittestenv/kdehome/share/config/akonadi-firstrunrc @@ -0,0 +1,3 @@ +[ProcessedDefaults] +defaultaddressbook=done +defaultcalendar=done diff --git a/akonadi/kmime/tests/unittestenv/kdehome/share/config/kdebugrc b/akonadi/kmime/tests/unittestenv/kdehome/share/config/kdebugrc new file mode 100644 index 000000000..32317f745 --- /dev/null +++ b/akonadi/kmime/tests/unittestenv/kdehome/share/config/kdebugrc @@ -0,0 +1,110 @@ +[0] +AbortFatal=true +ErrorFilename[$e]=kdebug.dbg +ErrorOutput=2 +FatalFilename[$e]=kdebug.dbg +FatalOutput=2 +InfoFilename[$e]=kdebug.dbg +InfoOutput=2 +WarnFilename[$e]=kdebug.dbg +WarnOutput=2 + +[5250] +InfoOutput=2 + +[5251] +InfoOutput=2 + +[5252] +InfoOutput=2 + +[5253] +InfoOutput=2 + +[5254] +AbortFatal=true +ErrorFilename[$e]=kdebug.dbg +ErrorOutput=2 +FatalFilename[$e]=kdebug.dbg +FatalOutput=2 +InfoFilename[$e]=kdebug.dbg +InfoOutput=2 +WarnFilename[$e]=kdebug.dbg +WarnOutput=2 + +[5255] +InfoOutput=2 + +[5256] +InfoOutput=2 + +[5257] +InfoOutput=2 + +[5258] +InfoOutput=2 + +[5259] +InfoOutput=2 + +[5260] +InfoOutput=2 + +[5261] +InfoOutput=2 + +[5262] +InfoOutput=2 + +[5263] +InfoOutput=2 + +[5264] +InfoOutput=2 + +[5265] +AbortFatal=true +ErrorFilename[$e]=kdebug.dbg +ErrorOutput=2 +FatalFilename[$e]=kdebug.dbg +FatalOutput=2 +InfoFilename[$e]=kdebug.dbg +InfoOutput=2 +WarnFilename[$e]=kdebug.dbg +WarnOutput=2 + +[5266] +AbortFatal=true +ErrorFilename[$e]=kdebug.dbg +ErrorOutput=2 +FatalFilename[$e]=kdebug.dbg +FatalOutput=2 +InfoFilename[$e]=kdebug.dbg +InfoOutput=2 +WarnFilename[$e]=kdebug.dbg +WarnOutput=2 + +[5295] +AbortFatal=true +ErrorFilename[$e]=kdebug.dbg +ErrorOutput=2 +FatalFilename[$e]=kdebug.dbg +FatalOutput=2 +InfoFilename[$e]=kdebug.dbg +InfoOutput=2 +WarnFilename[$e]=kdebug.dbg +WarnOutput=2 + +[5324] +AbortFatal=true +ErrorFilename[$e]=kdebug.dbg +ErrorOutput=2 +FatalFilename[$e]=kdebug.dbg +FatalOutput=2 +InfoFilename[$e]=kdebug.dbg +InfoOutput=2 +WarnFilename[$e]=kdebug.dbg +WarnOutput=2 + +[7129] +InfoOutput=2 diff --git a/akonadi/kmime/tests/unittestenv/kdehome/share/config/kwalletrc b/akonadi/kmime/tests/unittestenv/kdehome/share/config/kwalletrc new file mode 100644 index 000000000..8ba29ca12 --- /dev/null +++ b/akonadi/kmime/tests/unittestenv/kdehome/share/config/kwalletrc @@ -0,0 +1,2 @@ +[Wallet] +Enabled=false diff --git a/akonadi/kmime/tests/unittestenv/kdehome/share/config/mailtransports b/akonadi/kmime/tests/unittestenv/kdehome/share/config/mailtransports new file mode 100644 index 000000000..bc9c63f07 --- /dev/null +++ b/akonadi/kmime/tests/unittestenv/kdehome/share/config/mailtransports @@ -0,0 +1,17 @@ +[$Version] +update_info=mailtransports.upd:initial-kmail-migration,mailtransports.upd:initial-knode-migration + +[General] +default-transport=549190884 + +[Transport 549190884] +auth=true +encryption=SSL +host=smtp.gmail.com +id=549190884 +name=idanoka2-stored +password=ᄒᄡᄚᄆᄒᄏᄊᆱᄎᆲᆱ +port=465 +storepass=true +user=idanoka2@gmail.com + diff --git a/akonadi/kmime/tests/unittestenv/kdehome/share/config/qttestrc b/akonadi/kmime/tests/unittestenv/kdehome/share/config/qttestrc new file mode 100644 index 000000000..2e2f28ea1 --- /dev/null +++ b/akonadi/kmime/tests/unittestenv/kdehome/share/config/qttestrc @@ -0,0 +1,2 @@ +[Notification Messages] +WalletMigrate=false diff --git a/akonadi/kmime/tests/unittestenv/xdgconfig/akonadi/akonadiserverrc b/akonadi/kmime/tests/unittestenv/xdgconfig/akonadi/akonadiserverrc new file mode 100644 index 000000000..7f738ce21 --- /dev/null +++ b/akonadi/kmime/tests/unittestenv/xdgconfig/akonadi/akonadiserverrc @@ -0,0 +1,4 @@ +[%General] + +[Search] +Manager=Dummy diff --git a/akonadi/resourcebase.h b/akonadi/resourcebase.h index 0d731f47f..6290b030c 100644 --- a/akonadi/resourcebase.h +++ b/akonadi/resourcebase.h @@ -1,469 +1,470 @@ /* This file is part of akonadiresources. Copyright (c) 2006 Till Adam Copyright (c) 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 AKONADI_RESOURCEBASE_H #define AKONADI_RESOURCEBASE_H #include "akonadi_export.h" #include #include #include class KJob; class ResourceAdaptor; namespace Akonadi { class ResourceBasePrivate; /** * @short The base class for all Akonadi resources. * * This class should be used as a base class by all resource agents, * because it encapsulates large parts of the protocol between * resource agent, agent manager and the Akonadi storage. * * It provides many convenience methods to make implementing a * new Akonadi resource agent as simple as possible. * *

How to write a resource

* * The following provides an overview of what you need to do to implement * your own Akonadi resource. In the following, the term 'backend' refers * to the entity the resource connects with Akonadi, be it a single file * or a remote server. * * @todo Complete this (online/offline state management) * *
Basic %Resource Framework
* * The following is needed to create a new resource: * - A new class deriving from Akonadi::ResourceBase, implementing at least all * pure-virtual methods, see below for further details. * - call init() in your main() function. * - a .desktop file similar to the following example * \code * [Desktop Entry] * Encoding=UTF-8 * Name=My Akonadi Resource * Type=AkonadiResource * Exec=akonadi_my_resource * Icon=my-icon * * X-Akonadi-MimeTypes= * X-Akonadi-Capabilities=Resource * X-Akonadi-Identifier=akonadi_my_resource * \endcode * *
Handling PIM Items
* * To follow item changes in the backend, the following steps are necessary: * - Implement retrieveItems() to synchronize all items in the given * collection. If the backend supports incremental retrieval, * implementing support for that is recommended to improve performance. * - Convert the items provided by the backend to Akonadi items. * This typically happens either in retrieveItems() if you retrieved * the collection synchronously (not recommended for network backends) or * in the result slot of the asynchronous retrieval job. * Converting means to create Akonadi::Item objects for every retrieved * item. It's very important that every object has its remote identifier set. * - Call itemsRetrieved() or itemsRetrievedIncremental() respectively * with the item objects created above. The Akonadi storage will then be * updated automatically. Note that it is usually not necessary to manipulate * any item in the Akonadi storage manually. * * To fetch item data on demand, the method retrieveItem() needs to be * reimplemented. Fetch the requested data there and call itemRetrieved() * with the result item. * * To write local changes back to the backend, you need to re-implement * the following three methods: * - itemAdded() * - itemChanged() * - itemRemoved() * Note that these three functions don't get the full payload of the items by default, * you need to change the item fetch scope of the change recorder to fetch the full * payload. This can be expensive with big payloads, though.
* Once you have handled changes in these methods call changeCommitted(). * These methods are called whenever a local item related to this resource is * added, modified or deleted. They are only called if the resource is online, otherwise * all changes are recorded and replayed as soon the resource is online again. * *
Handling Collections
* * To follow collection changes in the backend, the following steps are necessary: * - Implement retrieveCollections() to retrieve collections from the backend. * If the backend supports incremental collections updates, implementing * support for that is recommended to improve performance. * - Convert the collections of the backend to Akonadi collections. * This typically happens either in retrieveCollections() if you retrieved * the collection synchronously (not recommended for network backends) or * in the result slot of the asynchronous retrieval job. * Converting means to create Akonadi::Collection objects for every retrieved * collection. It's very important that every object has its remote identifier * and its parent remote identifier set. * - Call collectionsRetrieved() or collectionsRetrievedIncremental() respectively * with the collection objects created above. The Akonadi storage will then be * updated automatically. Note that it is usually not necessary to manipulate * any collection in the Akonadi storage manually. * * * To write local collection changes back to the backend, you need to re-implement * the following three methods: * - collectionAdded() * - collectionChanged() * - collectionRemoved() * Once you have handled changes in these methods call changeCommitted(). * These methods are called whenever a local collection related to this resource is * added, modified or deleted. They are only called if the resource is online, otherwise * all changes are recorded and replayed as soon the resource is online again. * * @todo Convenience base class for collection-less resources */ // FIXME_API: API dox need to be updated for Observer approach (kevin) class AKONADI_EXPORT ResourceBase : public AgentBase { Q_OBJECT public: /** * Use this method in the main function of your resource * application to initialize your resource subclass. * This method also takes care of creating a KApplication * object and parsing command line arguments. * * @note In case the given class is also derived from AgentBase::Observer * it gets registered as its own observer (see AgentBase::Observer), e.g. * resourceInstance->registerObserver( resourceInstance ); * * @code * * class MyResource : public ResourceBase * { * ... * }; * * int main( int argc, char **argv ) * { * return ResourceBase::init( argc, argv ); * } * * @endcode */ template static int init( int argc, char **argv ) { const QString id = parseArguments( argc, argv ); KApplication app; T* r = new T( id ); // check if T also inherits AgentBase::Observer and // if it does, automatically register it on itself Observer *observer = dynamic_cast( r ); if ( observer != 0 ) r->registerObserver( observer ); + return init( r ); } /** * This method is used to set the name of the resource. */ //FIXME_API: make sure location is renamed to this by resourcebase void setName( const QString &name ); /** * Returns the name of the resource. */ QString name() const; Q_SIGNALS: /** * This signal is emitted whenever the name of the resource has changed. * * @param name The new name of the resource. */ void nameChanged( const QString &name ); /** * Emitted when a full synchronization has been completed. */ void synchronized(); protected Q_SLOTS: /** * Retrieve the collection tree from the remote server and supply it via * collectionsRetrieved() or collectionsRetrievedIncremental(). * @see collectionsRetrieved(), collectionsRetrievedIncremental() */ virtual void retrieveCollections() = 0; /** * Retrieve all (new/changed) items in collection @p collection. * It is recommended to use incremental retrieval if the backend supports that * and provide the result by calling itemsRetrievedIncremental(). * If incremental retrieval is not possible, provide the full listing by calling * itemsRetrieved( const Item::List& ). * In any case, ensure that all items have a correctly set remote identifier - * to allow synchronizing with already locally existing items. - * In case you don't want to use the built-in item syncing code, store the retrived + * to allow synchronizing with items already existing locally. + * In case you don't want to use the built-in item syncing code, store the retrieved * items manually and call itemsRetrieved() once you are done. - * @param collection The collection to sync. - * @see itemsRetrieved( const Item::List &), itemsRetrievedIncremental(), itemsRetrieved(), currentCollection() + * @param collection The collection whose items to retrieve. + * @see itemsRetrieved( const Item::List& ), itemsRetrievedIncremental(), itemsRetrieved(), currentCollection() */ virtual void retrieveItems( const Akonadi::Collection &collection ) = 0; /** * Retrieve a single item from the backend. The item to retrieve is provided as @p item. * Add the requested payload parts and call itemRetrieved() when done. - * @param item The empty item which payload should be retrieved. Use this object when delivering - * the result instead of creating a new item to ensure conflict detection to work. + * @param item The empty item whose payload should be retrieved. Use this object when delivering + * the result instead of creating a new item to ensure conflict detection will work. * @param parts The item parts that should be retrieved. * @return false if there is an immediate error when retrieving the item. * @see itemRetrieved() */ virtual bool retrieveItem( const Akonadi::Item &item, const QSet &parts ) = 0; protected: /** * Creates a base resource. * * @param id The instance id of the resource. */ ResourceBase( const QString & id ); /** * Destroys the base resource. */ ~ResourceBase(); /** * Call this method from retrieveItem() once the result is available. * * @param item The retrieved item. */ void itemRetrieved( const Item &item ); /** * Resets the dirty flag of the given item and updates the remote id. * * Call whenever you have successfully written changes back to the server. * This implicitly calls changeProcessed(). * @param item The changed item. */ void changeCommitted( const Item &item ); /** * Call whenever you have successfully handled or ignored a collection * change notification. * * This will update the remote identifier of @p collection if necessary, * as well as any other collection attributes. * This implicitly calls changeProcessed(). * @param collection The collection which changes have been handled. */ void changeCommitted( const Collection &collection ); /** * Call this to supply the full folder tree retrieved from the remote server. * * @param collections A list of collections. * @see collectionsRetrievedIncremental() */ void collectionsRetrieved( const Collection::List &collections ); /** * Call this to supply incrementally retrieved collections from the remote server. * * @param changedCollections Collections that have been added or changed. * @param removedCollections Collections that have been deleted. * @see collectionsRetrieved() */ void collectionsRetrievedIncremental( const Collection::List &changedCollections, const Collection::List &removedCollections ); /** * Enable collection streaming, that is collections don't have to be delivered at once * as result of a retrieveCollections() call but can be delivered by multiple calls * to collectionsRetrieved() or collectionsRetrievedIncremental(). When all collections * have been retrieved, call collectionsRetrievalDone(). * @param enable @c true if collection streaming should be enabled, @c false by default */ void setCollectionStreamingEnabled( bool enable ); /** * Call this method to indicate you finished synchronizing the collection tree. * * This is not needed if you use the built in syncing without collection streaming * and call collectionsRetrieved() or collectionRetrievedIncremental() instead. * If collection streaming is enabled, call this method once all collections have been delivered * using collectionsRetrieved() or collectionsRetrievedIncremental(). */ void collectionsRetrievalDone(); /** * Call this method to supply the full collection listing from the remote server. * * If the remote server supports incremental listing, it's strongly * recommended to use itemsRetrievedIncremental() instead. * @param items A list of items. * @see itemsRetrievedIncremental(). */ void itemsRetrieved( const Item::List &items ); /** * Call this method when you want to use the itemsRetrieved() method * in streaming mode and indicate the amount of items that will arrive * that way. * @deprecated Use setItemStreamingEnabled( true ) + itemsRetrieved[Incremental]() * + itemsRetrieved() instead. */ void setTotalItems( int amount ); /** * Enable item streaming. * Item streaming is disabled by default. * @param enable @c true if items are delivered in chunks rather in one big block. */ void setItemStreamingEnabled( bool enable ); /** * Call this method to supply incrementally retrieved items from the remote server. * * @param changedItems Items changed in the backend. * @param removedItems Items removed from the backend. */ void itemsRetrievedIncremental( const Item::List &changedItems, const Item::List &removedItems ); /** * Call this method to indicate you finished synchronizing the current collection. * * This is not needed if you use the built in syncing without item streaming * and call itemsRetrieved() or itemsRetrievedIncremental() instead. * If item streaming is enabled, call this method once all items have been delivered * using itemsRetrieved() or itemsRetrievedIncremental(). * @see retrieveItems() */ void itemsRetrievalDone(); /** * Call this method to remove all items and collections of the resource from the * server cache. * * The method should be used whenever the configuration of the resource has changed * and therefor the cached items might not be valid any longer. * * @since 4.3 */ void clearCache(); /** * Returns the collection that is currently synchronized. */ Collection currentCollection() const; /** * Returns the item that is currently retrieved. */ Item currentItem() const; /** * This method is called whenever the resource should start synchronize all data. */ void synchronize(); /** * This method is called whenever the collection with the given @p id * shall be synchronized. */ void synchronizeCollection( qint64 id ); /** * Refetches the Collections. */ void synchronizeCollectionTree(); /** * Stops the execution of the current task and continues with the next one. */ void cancelTask(); /** * Stops the execution of the current task and continues with the next one. * Additionally an error message is emitted. */ void cancelTask( const QString &error ); /** * Stops the execution of the current task and continues with the next one. * The current task will be tried again later. * * @since 4.3 */ void deferTask(); /** * Inherited from AgentBase. */ void doSetOnline( bool online ); private: static QString parseArguments( int, char** ); static int init( ResourceBase *r ); // dbus resource interface friend class ::ResourceAdaptor; bool requestItemDelivery( qint64 uid, const QString &remoteId, const QString &mimeType, const QStringList &parts ); private: Q_DECLARE_PRIVATE( ResourceBase ) Q_PRIVATE_SLOT( d_func(), void slotDeliveryDone( KJob* ) ) Q_PRIVATE_SLOT( d_func(), void slotCollectionSyncDone( KJob* ) ) Q_PRIVATE_SLOT( d_func(), void slotDeleteResourceCollection() ) Q_PRIVATE_SLOT( d_func(), void slotDeleteResourceCollectionDone( KJob* ) ) Q_PRIVATE_SLOT( d_func(), void slotCollectionDeletionDone( KJob* ) ) Q_PRIVATE_SLOT( d_func(), void slotLocalListDone( KJob* ) ) Q_PRIVATE_SLOT( d_func(), void slotSynchronizeCollection( const Akonadi::Collection& ) ) Q_PRIVATE_SLOT( d_func(), void slotCollectionListDone( KJob* ) ) Q_PRIVATE_SLOT( d_func(), void slotItemSyncDone( KJob* ) ) Q_PRIVATE_SLOT( d_func(), void slotPercent( KJob*, unsigned long ) ) Q_PRIVATE_SLOT( d_func(), void slotPrepareItemRetrieval( const Akonadi::Item& item ) ) Q_PRIVATE_SLOT( d_func(), void slotPrepareItemRetrievalResult( KJob* ) ) }; } #ifndef AKONADI_RESOURCE_MAIN /** * Convenience Macro for the most common main() function for Akonadi resources. */ #define AKONADI_RESOURCE_MAIN( resourceClass ) \ int main( int argc, char **argv ) \ { \ return Akonadi::ResourceBase::init( argc, argv ); \ } #endif #endif diff --git a/akonadi/tests/CMakeLists.txt b/akonadi/tests/CMakeLists.txt index a7f5dcd10..2d7576566 100644 --- a/akonadi/tests/CMakeLists.txt +++ b/akonadi/tests/CMakeLists.txt @@ -1,128 +1,129 @@ if(${EXECUTABLE_OUTPUT_PATH}) set( PREVIOUS_EXEC_OUTPUT_PATH ${EXECUTABLE_OUTPUT_PATH} ) else(${EXECUTABLE_OUTPUT_PATH}) set( PREVIOUS_EXEC_OUTPUT_PATH . ) endif(${EXECUTABLE_OUTPUT_PATH}) set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}" ) include_directories( ${CMAKE_SOURCE_DIR}/akonadi ${CMAKE_CURRENT_SOURCE_DIR}/../ ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/../ ${Boost_INCLUDE_DIR} ${AKONADI_INCLUDE_DIR} ${AKONADI_INCLUDE_DIR}/akonadi/private ) # add testrunner (application for managing a self-contained test # environment) add_subdirectory(testrunner) # add benchmarker add_subdirectory(benchmarker) # convenience macro to add akonadi demo application macro(add_akonadi_demo _source) set(_test ${_source}) get_filename_component(_name ${_source} NAME_WE) kde4_add_executable(${_name} TEST ${_test}) target_link_libraries(${_name} akonadi-kde akonadi-kmime ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${KDE4_KDECORE_LIBS} ${KDE4_KDEUI_LIBS}) endmacro(add_akonadi_demo) # convenience macro to add akonadi qtestlib unit-tests macro(add_akonadi_test _source) set(_test ${_source}) get_filename_component(_name ${_source} NAME_WE) kde4_add_unit_test(${_name} TESTNAME akonadi-${_name} ${_test} fakesession.cpp fakemonitor.cpp fakeserver.cpp) target_link_libraries(${_name} akonadi-kde akonadi-kmime ${QT_QTTEST_LIBRARY} ${QT_QTCORE_LIBRARY} ${QT_QTNETWORK_LIBRARY} ${QT_QTGUI_LIBRARY} ${KDE4_KDECORE_LIBS} ${AKONADI_COMMON_LIBRARIES}) endmacro(add_akonadi_test) # convenience macro to add akonadi testrunner unit-tests macro(add_akonadi_isolated_test _source) set(_test ${_source}) get_filename_component(_name ${_source} NAME_WE) kde4_add_executable(${_name} TEST ${_test}) target_link_libraries(${_name} akonadi-kde akonadi-kmime ${QT_QTTEST_LIBRARY} ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${KDE4_KDECORE_LIBS} ${AKONADI_COMMON_LIBRARIES}) # based on kde4_add_unit_test if (WIN32) get_target_property( _loc ${_name} LOCATION ) set(_executable ${_loc}.bat) set(_testrunner ${PREVIOUS_EXEC_OUTPUT_PATH}/akonaditest.bat) else (WIN32) set(_executable ${EXECUTABLE_OUTPUT_PATH}/${_name}) set(_testrunner ${PREVIOUS_EXEC_OUTPUT_PATH}/akonaditest) endif (WIN32) if (UNIX) set(_executable ${_executable}.shell) set(_testrunner ${_testrunner}.shell) endif (UNIX) add_test( akonadi-mysql-db-${_name} ${_testrunner} -c ${CMAKE_CURRENT_SOURCE_DIR}/unittestenv/config-mysql-db.xml ${_executable} ) add_test( akonadi-mysql-fs-${_name} ${_testrunner} -c ${CMAKE_CURRENT_SOURCE_DIR}/unittestenv/config-mysql-fs.xml ${_executable} ) #add_test( akonadi-postgresql-fs-${_name} ${_testrunner} -c ${CMAKE_CURRENT_SOURCE_DIR}/unittestenv/config-postgresql-fs.xml ${_executable} ) #add_test( akonadi-postgresql-fs-${_name} ${_testrunner} -c ${CMAKE_CURRENT_SOURCE_DIR}/unittestenv/config-postgresql-fs.xml ${_executable} ) #add_test( akonadi-sqlite-${_name} ${_testrunner} -c ${CMAKE_CURRENT_SOURCE_DIR}/unittestenv/config-sqlite.xml ${_executable} ) endmacro(add_akonadi_isolated_test) # demo applications add_akonadi_demo(itemdumper.cpp) add_akonadi_demo(subscriber.cpp) add_akonadi_demo(headfetcher.cpp) add_akonadi_demo(agentinstancewidgettest.cpp) add_akonadi_demo(agenttypewidgettest.cpp) add_akonadi_demo(pluginloadertest.cpp) add_akonadi_demo(selftester.cpp) kde4_add_executable( akonadi-firstrun TEST ../firstrun.cpp firstrunner.cpp ) target_link_libraries( akonadi-firstrun akonadi-kde ${KDE4_KDEUI_LIBS} ) # qtestlib unit tests add_akonadi_test(imapparsertest.cpp) add_akonadi_test(imapsettest.cpp) add_akonadi_test(itemhydratest.cpp) add_akonadi_test(itemtest.cpp) add_akonadi_test(itemserializertest.cpp) add_akonadi_test(mimetypecheckertest.cpp) add_akonadi_test(protocolhelpertest.cpp) add_akonadi_test(entitytreemodeltest.cpp) # qtestlib tests that need non-exported stuff from akonadi-kde kde4_add_unit_test(resourceschedulertest TESTNAME akonadi-resourceschedulertest resourceschedulertest.cpp ../resourcescheduler.cpp) target_link_libraries(resourceschedulertest akonadi-kde ${QT_QTTEST_LIBRARY} ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${KDE4_KDECORE_LIBS} ${AKONADI_COMMON_LIBRARIES}) # testrunner tests add_akonadi_isolated_test(testenvironmenttest.cpp) add_akonadi_isolated_test(autoincrementtest.cpp) add_akonadi_isolated_test(attributefactorytest.cpp) add_akonadi_isolated_test(collectionjobtest.cpp) add_akonadi_isolated_test(collectionpathresolvertest.cpp) add_akonadi_isolated_test(collectionattributetest.cpp) add_akonadi_isolated_test(itemfetchtest.cpp) add_akonadi_isolated_test(itemappendtest.cpp) add_akonadi_isolated_test(itemstoretest.cpp) add_akonadi_isolated_test(itemdeletetest.cpp) add_akonadi_isolated_test(entitycachetest.cpp) add_akonadi_isolated_test(monitortest.cpp) add_akonadi_isolated_test(searchjobtest.cpp) add_akonadi_isolated_test(changerecordertest.cpp) add_akonadi_isolated_test(resourcetest.cpp) add_akonadi_isolated_test(subscriptiontest.cpp) add_akonadi_isolated_test(transactiontest.cpp) +add_akonadi_isolated_test(filteractiontest.cpp) add_akonadi_isolated_test(itemcopytest.cpp) add_akonadi_isolated_test(itemmovetest.cpp) add_akonadi_isolated_test(collectioncopytest.cpp) add_akonadi_isolated_test(collectionmovetest.cpp) add_akonadi_isolated_test(collectionsynctest.cpp) add_akonadi_isolated_test(itemsynctest.cpp) add_akonadi_isolated_test(linktest.cpp) add_akonadi_isolated_test(cachetest.cpp) add_akonadi_isolated_test(servermanagertest.cpp) add_akonadi_isolated_test(collectioncreator.cpp) add_akonadi_isolated_test(itembenchmark.cpp) diff --git a/akonadi/tests/filteractiontest.cpp b/akonadi/tests/filteractiontest.cpp new file mode 100644 index 000000000..41b3f09e5 --- /dev/null +++ b/akonadi/tests/filteractiontest.cpp @@ -0,0 +1,206 @@ +/* + 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 "filteractiontest.h" +#include "collectionpathresolver_p.h" +#include "testattribute.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Akonadi; + +QTEST_AKONADIMAIN( FilterActionTest, NoGUI ) + +static const QByteArray acceptable = "acceptable"; +static const QByteArray unacceptable = "unacceptable"; +static const QByteArray modified = "modified"; +static Collection res1; + +class MyFunctor : public FilterAction +{ + virtual Akonadi::ItemFetchScope fetchScope() const + { + ItemFetchScope scope; + scope.fetchAttribute(); + return scope; + } + + virtual bool itemAccepted( const Akonadi::Item &item ) const + { + if( !item.hasAttribute() ) { + return false; + } + return ( item.attribute()->data == acceptable ); + } + + virtual Akonadi::Job *itemAction( const Akonadi::Item &item ) const + { + Item cp( item ); + TestAttribute *newa = new TestAttribute; + newa->data = modified; + cp.addAttribute( newa ); + return new ItemModifyJob( cp ); + } +}; + +void FilterActionTest::initTestCase() +{ + AttributeFactory::registerAttribute(); + + CollectionPathResolver *resolver = new CollectionPathResolver( "res1", this ); + QVERIFY( resolver->exec() ); + res1 = Collection( resolver->collection() ); +} + +void FilterActionTest::testMassModifyItem() +{ + Collection col = createCollection( "testMassModifyItem" ); + + // Test acceptable item. + Item item = createItem( col, true ); + FilterActionJob *mjob = new FilterActionJob( item, new MyFunctor, this ); + AKVERIFYEXEC( mjob ); + ItemFetchJob *fjob = new ItemFetchJob( item, this ); + fjob->fetchScope().fetchAllAttributes(); + AKVERIFYEXEC( fjob ); + QCOMPARE( fjob->items().count(), 1 ); + item = fjob->items().first(); + QVERIFY( item.hasAttribute() ); + TestAttribute *attr = item.attribute(); + QCOMPARE( attr->data, modified ); + + // Test unacceptable item. + item = createItem( col, false ); + mjob = new FilterActionJob( item, new MyFunctor, this ); + AKVERIFYEXEC( mjob ); + fjob = new ItemFetchJob( item, this ); + fjob->fetchScope().fetchAllAttributes(); + AKVERIFYEXEC( fjob ); + QCOMPARE( fjob->items().count(), 1 ); + item = fjob->items().first(); + QVERIFY( item.hasAttribute() ); + attr = item.attribute(); + QCOMPARE( attr->data, unacceptable ); +} + +void FilterActionTest::testMassModifyItems() +{ + Collection col = createCollection( "testMassModifyItems" ); + + // Test a bunch of acceptable and unacceptable items. + Item::List acc, unacc; + for( int i = 0; i < 5; i++ ) { + acc.append( createItem( col, true ) ); + unacc.append( createItem( col, false ) ); + } + Item::List all = acc + unacc; + QCOMPARE( all.count(), 10 ); + FilterActionJob *mjob = new FilterActionJob( all, new MyFunctor, this ); + AKVERIFYEXEC( mjob ); + ItemFetchJob *fjob = new ItemFetchJob( col, this ); + fjob->fetchScope().fetchAllAttributes(); + AKVERIFYEXEC( fjob ); + QCOMPARE( fjob->items().count(), 10 ); + foreach( const Item &item, fjob->items() ) { + QVERIFY( item.hasAttribute() ); + const QByteArray data = item.attribute()->data; + if( data == unacceptable ) { + QVERIFY( unacc.contains( item ) ); + unacc.removeAll( item ); + } else if( data == modified ) { + QVERIFY( acc.contains( item ) ); + acc.removeAll( item ); + } else { + QVERIFY2( false, "Got bad data \"" + data + '\"' ); + } + } + QCOMPARE( acc.count(), 0 ); + QCOMPARE( unacc.count(), 0 ); +} + +void FilterActionTest::testMassModifyCollection() +{ + Collection col = createCollection( "testMassModifyCollection" ); + + // Test a bunch of acceptable and unacceptable items. + Item::List acc, unacc; + for( int i = 0; i < 5; i++ ) { + acc.append( createItem( col, true ) ); + unacc.append( createItem( col, false ) ); + } + FilterActionJob *mjob = new FilterActionJob( col, new MyFunctor, this ); + kDebug() << "Executing FilterActionJob."; + AKVERIFYEXEC( mjob ); + ItemFetchJob *fjob = new ItemFetchJob( col, this ); + fjob->fetchScope().fetchAllAttributes(); + AKVERIFYEXEC( fjob ); + QCOMPARE( fjob->items().count(), 10 ); + foreach( const Item &item, fjob->items() ) { + QVERIFY( item.hasAttribute() ); + const QByteArray data = item.attribute()->data; + if( data == unacceptable ) { + QVERIFY( unacc.contains( item ) ); + unacc.removeAll( item ); + } else if( data == modified ) { + QVERIFY( acc.contains( item ) ); + acc.removeAll( item ); + } else { + QVERIFY2( false, "Got bad data \"" + data + '\"' ); + } + } + QCOMPARE( acc.count(), 0 ); + QCOMPARE( unacc.count(), 0 ); +} + +Collection FilterActionTest::createCollection( const QString &name ) +{ + Collection col; + col.setParent( res1 ); + col.setName( name ); + CollectionCreateJob *ccjob = new CollectionCreateJob( col, this ); + Q_ASSERT( ccjob->exec() ); + return ccjob->collection(); +} + +Item FilterActionTest::createItem( const Collection &col, bool accept ) +{ + Q_ASSERT( col.isValid() ); + + Item item; + item.setMimeType( "text/directory" ); + TestAttribute *attr = new TestAttribute; + if( accept ) { + attr->data = acceptable; + } else { + attr->data = unacceptable; + } + item.addAttribute( attr ); + ItemCreateJob *cjob = new ItemCreateJob( item, col, this ); + Q_ASSERT( cjob->exec() ); + return cjob->item(); +} + +#include "filteractiontest.moc" diff --git a/mailtransport/configmodule.h b/akonadi/tests/filteractiontest.h similarity index 57% copy from mailtransport/configmodule.h copy to akonadi/tests/filteractiontest.h index 6994d37bd..82d041508 100644 --- a/mailtransport/configmodule.h +++ b/akonadi/tests/filteractiontest.h @@ -1,39 +1,48 @@ /* - Copyright (c) 2007 Volker Krause + 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 MAILTRANSPORT_CONFIGMODULE_H -#define MAILTRANSPORT_CONFIGMODULE_H +#ifndef FILTERACTIONTEST_H +#define FILTERACTIONTEST_H -#include +#include +#include -namespace MailTransport { +#include +#include -/** - KCModule for transport management. -*/ -class ConfigModule : public KCModule +class KJob; + +class FilterActionTest : public QObject { - public: - explicit ConfigModule( QWidget *parent = 0, - const QVariantList &args = QVariantList() ); + Q_OBJECT + + private slots: + void initTestCase(); + void testMassModifyItem(); + void testMassModifyItems(); + void testMassModifyCollection(); + + private: + Akonadi::Collection createCollection( const QString &name ); + Akonadi::Item createItem( const Akonadi::Collection &col, bool accept ); + }; -} #endif diff --git a/akonadi/transportresourcebase.cpp b/akonadi/transportresourcebase.cpp new file mode 100644 index 000000000..299e76b3e --- /dev/null +++ b/akonadi/transportresourcebase.cpp @@ -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. +*/ + +#include "transportresourcebase.h" +#include "transportresourcebase_p.h" + +#include "transportadaptor.h" + +#include + +using namespace Akonadi; + +TransportResourceBasePrivate::TransportResourceBasePrivate( TransportResourceBase *qq ) + : QObject(), q( qq ) +{ + new TransportAdaptor( this ); + QDBusConnection::sessionBus().registerObject( QLatin1String( "/Transport" ), + this, QDBusConnection::ExportAdaptors ); +} + +void TransportResourceBasePrivate::send( Item::Id message ) +{ + q->sendItem( message ); +} + +TransportResourceBase::TransportResourceBase() + : d( new TransportResourceBasePrivate( this ) ) +{ +} + +TransportResourceBase::~TransportResourceBase() +{ + delete d; +} + +void TransportResourceBase::emitTransportResult( Item::Id &item, bool success, + const QString &message ) +{ + emit d->transportResult( item, success, message ); +} + +#include "transportresourcebase_p.moc" diff --git a/akonadi/transportresourcebase.h b/akonadi/transportresourcebase.h new file mode 100644 index 000000000..2b08532e4 --- /dev/null +++ b/akonadi/transportresourcebase.h @@ -0,0 +1,81 @@ +/* + 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 AKONADI_TRANSPORTRESOURCEBASE_H +#define AKONADI_TRANSPORTRESOURCEBASE_H + +#include "akonadi_export.h" + +#include + +#include + +class KJob; + +namespace Akonadi { + +class TransportResourceBasePrivate; + +/** + * @short Resource implementing mail transport capability. + * + * To implement a transport-enabled resource, inherit from both + * ResourceBase and TransportResourceBase, implement the virtual method + * sendItem(), and call emitTransportResult() when finished sending. + * The resource must also have the "MailTransport" capability flag. + * + * For an example of a transport-enabled resource, see + * kdepim/akonadi/resources/mailtransport_dummy. + * + * @author Constantin Berzan + * @since 4.4 + */ +class AKONADI_EXPORT TransportResourceBase +{ + public: + TransportResourceBase(); + virtual ~TransportResourceBase(); + + /** + Reimplement in your resource, to begin the actual sending operation. + Call emitTransportResult() when finished. + @param message The ID of the message to be sent. + @see emitTransportResult. + */ + virtual void sendItem( Akonadi::Item::Id message ) = 0; + + // TODO add void emitSendProgress( int percent ); + + /** + * Emits the transportResult() DBus signal with the given arguments. + * @param item The id of the item that was sent. + * @param success True if the sending operation succeeded. + * @param message An optional textual explanation of the result. + * @see Transport. + */ + void emitTransportResult( Akonadi::Item::Id &item, bool success, + const QString &message = QString() ); + + private: + TransportResourceBasePrivate *const d; +}; + +} // namespace Akonadi + +#endif // AKONADI_TRANSPORTRESOURCEBASE_H diff --git a/akonadi/transportresourcebase_p.h b/akonadi/transportresourcebase_p.h new file mode 100644 index 000000000..eb7c05978 --- /dev/null +++ b/akonadi/transportresourcebase_p.h @@ -0,0 +1,64 @@ +/* + 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 AKONADI_TRANSPORTRESOURCEBASE_P_H +#define AKONADI_TRANSPORTRESOURCEBASE_P_H + +#include "transportresourcebase.h" + +#include + +class TransportAdaptor; + +namespace Akonadi { + +class TransportResourceBase; + +/** + @internal + This class hosts the D-Bus adaptor for TransportResourceBase. +*/ +class TransportResourceBasePrivate : public QObject +{ + Q_OBJECT + public: + TransportResourceBasePrivate( TransportResourceBase *qq ); + + signals: + /** + * Emitted when an item has been sent. + * @param item The id of the item that was sent. + * @param success The success of the sending operation. + * @param message An optional textual explanation of the result. + * @since 4.4 + */ + void transportResult( qlonglong item, bool success, const QString &message ); // D-Bus signal + + private: + friend class TransportResourceBase; + friend class ::TransportAdaptor; + + void send( Akonadi::Item::Id message ); // D-Bus call + + TransportResourceBase *const q; +}; + +} // namespace Akonadi + +#endif // AKONADI_TRANSPORTRESOURCEBASE_P_H diff --git a/includes/Akonadi/TransportResourceBase b/includes/Akonadi/TransportResourceBase new file mode 100644 index 000000000..cfd76bba8 --- /dev/null +++ b/includes/Akonadi/TransportResourceBase @@ -0,0 +1 @@ +#include "../../akonadi/transportresourcebase.h" diff --git a/mailtransport/CMakeLists.txt b/mailtransport/CMakeLists.txt index 2103f998f..27cef2ac7 100644 --- a/mailtransport/CMakeLists.txt +++ b/mailtransport/CMakeLists.txt @@ -1,57 +1,101 @@ +set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}" ) + +include_directories( + ${Boost_INCLUDE_DIR} +) add_subdirectory( kconf_update ) add_subdirectory( tests ) add_definitions("-DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII") add_definitions( -DKDE_DEFAULT_DEBUG_AREA=5324 ) +add_definitions( -DUSES_DEPRECATED_MAILTRANSPORT_API ) # for transportmanager set(mailtransport_lib_srcs transport.cpp + transportmanager.cpp + transporttype.cpp + transportcombobox.cpp + transportlistview.cpp + transportmanagementwidget.cpp + + addtransportdialog.cpp transportconfigdialog.cpp + transportconfigwidget.cpp + sendmailconfigwidget.cpp + smtpconfigwidget.cpp + transportjob.cpp - transportmanager.cpp - transportmanagementwidget.cpp + resourcesendjob.cpp sendmailjob.cpp smtpjob.cpp precommandjob.cpp + legacydecrypt.cpp socket.cpp servertest.cpp + + dispatcherinterface.cpp + messagequeuejob.cpp + outboxactions.cpp + + attributeregistrar.cpp + dispatchmodeattribute.cpp + errorattribute.cpp + sentbehaviourattribute.cpp + transportattribute.cpp ) kde4_add_ui_files(mailtransport_lib_srcs - smtpsettings.ui sendmailsettings.ui + smtpsettings.ui + + addtransportdialog.ui transportmanagementwidget.ui ) kde4_add_kcfg_files(mailtransport_lib_srcs transportbase.kcfgc) kde4_add_library(mailtransport SHARED ${mailtransport_lib_srcs}) -target_link_libraries(mailtransport ${KDE4_KIO_LIBS}) +target_link_libraries(mailtransport ${KDE4_KIO_LIBS} akonadi-kde akonadi-kmime kmime ) set_target_properties(mailtransport PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION} ) install(TARGETS mailtransport EXPORT kdepimlibsLibraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES mailtransport.kcfg DESTINATION ${KCFG_INSTALL_DIR}) set(mailtransport_kcm_srcs configmodule.cpp) kde4_add_plugin(kcm_mailtransport ${mailtransport_kcm_srcs}) target_link_libraries(kcm_mailtransport ${KDE4_KDEUI_LIBS} mailtransport) install(TARGETS kcm_mailtransport DESTINATION ${PLUGIN_INSTALL_DIR}) install(FILES kcm_mailtransport.desktop DESTINATION ${SERVICES_INSTALL_DIR}) install( FILES mailtransport_export.h + + transportjob.h + resourcesendjob.h sendmailjob.h smtpjob.h - transport.h + ${CMAKE_CURRENT_BINARY_DIR}/transportbase.h + transport.h + transportmanager.h + transporttype.h + servertest.h + transportcombobox.h transportconfigdialog.h - transportjob.h transportmanagementwidget.h - transportmanager.h - servertest.h + + dispatcherinterface.h + messagequeuejob.h + outboxactions.h + + dispatchmodeattribute.h + errorattribute.h + sentbehaviourattribute.h + transportattribute.h + DESTINATION ${INCLUDE_INSTALL_DIR}/mailtransport COMPONENT Devel) diff --git a/mailtransport/DESIGN b/mailtransport/DESIGN new file mode 100644 index 000000000..e00f5299c --- /dev/null +++ b/mailtransport/DESIGN @@ -0,0 +1,22 @@ +Glossary: +New apps == apps using MessageQueueJob. +Old apps == apps using the MailTransport jobs directly. +Traditional transports == SMTP and Sendmail, which are handled by MailTransport. +Resource-based transports == Akonadi-based transports, which are handled by the MDA. +MDA == Mail Dispatcher Agent. + +Current situation: +* New apps, traditional transports: + App's composer -> MailTransport (MessageQueueJob) -> MDA -> MailTransport (SmtpJob or SendmailJob). +* New apps, resource-based transports: + App's composer -> MailTransport (MessageQueueJob) -> MDA -> specific resource. +* Old apps, traditional transports: + App's composer -> MailTransport (SmtpJob or SendmailJob). +* Old apps, resource-based transports: + App's composer -> MailTransport (ResourceSendJob) -> MailTransport (MessageQueueJob) -> MDA -> specific resource. + +Ideal situation (KDE5): +* Move SmtpJob and SendmailJob to the MDA, and let MailTransport handle only config stuff and putting things in the outbox. +* All apps: + App's composer -> MailTransport (MessageQueueJob) -> MDA (SMTP, Sendmail, or specific resource) + diff --git a/mailtransport/TODO b/mailtransport/TODO index a2e5cffdd..e2b12e33e 100644 --- a/mailtransport/TODO +++ b/mailtransport/TODO @@ -1,36 +1,35 @@ Mail Transport TODO ~~~~~~~~~~~~~~~~~~~ Migration --------- - password migration within kwallet (for kmail and knode), requires KWallet to be fixed first TransportManager ---------------- - load passwords if another instance opens the wallet - load passwords if application opens wallet - add D-Bus interface for sending mails - test to see if there is always a default transport, by adding / deleting accounts +- it would be nice to make showNewTransportDialog, + promptCreateTransportIfNoneExists, and configureTransport visible on D-Bus, + but how to handle QWidget *parent? Transport --------- - password is not reloaded from wallet on remote change TransportJob ------------ - use QByteArray for addresses instead of QString SMTPJob ------- - get rid of kmail specific stuff in start() Precommand ---------- - test conversion from kprocess to qprocess (TA) -TransportManagementWidget -------------------------- -- support inline editing of transport names - diff --git a/mailtransport/addtransportdialog.cpp b/mailtransport/addtransportdialog.cpp new file mode 100644 index 000000000..ae6d98273 --- /dev/null +++ b/mailtransport/addtransportdialog.cpp @@ -0,0 +1,144 @@ +/* + 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 "addtransportdialog.h" +#include "transport.h" +#include "transportconfigwidget.h" +#include "transportmanager.h" +#include "transporttype.h" +#include "ui_addtransportdialog.h" + +#include + +#include +#include + +using namespace MailTransport; + +/** + @internal +*/ +class AddTransportDialog::Private +{ + public: + Private( AddTransportDialog *qq ) + : q( qq ) + { + } + + /** + Returns the currently selected type in the type selection widget, or + an invalid type if none is selected. + */ + TransportType selectedType() const; + + /** + Enables the OK button if a type is selected. + */ + void typeListClicked(); // slot + + AddTransportDialog *const q; + Ui::AddTransportDialog ui; +}; + +TransportType AddTransportDialog::Private::selectedType() const +{ + QList sel = ui.typeListView->selectedItems(); + if ( !sel.empty() ) { + return sel.first()->data( 0, Qt::UserRole ).value(); + } + return TransportType(); +} + +void AddTransportDialog::Private::typeListClicked() +{ + // Make sure a type is selected before allowing the user to continue. + q->enableButtonOk( selectedType().isValid() ); +} + +AddTransportDialog::AddTransportDialog( QWidget *parent ) + : KDialog( parent ), d( new Private( this ) ) +{ + // Setup UI. + { + QWidget *widget = new QWidget( this ); + d->ui.setupUi( widget ); + setMainWidget( widget ); + setCaption( i18n( "Create Outgoing Account" ) ); + setButtons( Ok|Cancel ); + enableButtonOk( false ); + setButtonText( Ok, i18nc( "create and configure a mail transport", "Create and Configure" ) ); + } + + // Populate type list. + foreach ( const TransportType &type, TransportManager::self()->types() ) { + QTreeWidgetItem *treeItem = new QTreeWidgetItem( d->ui.typeListView ); + treeItem->setText( 0, type.name() ); + treeItem->setText( 1, type.description() ); + treeItem->setData( 0, Qt::UserRole, QVariant::fromValue( type ) ); // the transport type + } + d->ui.typeListView->resizeColumnToContents( 0 ); + updateGeometry(); + d->ui.typeListView->setFocus(); + + // Connect user input. + connect( d->ui.typeListView, SIGNAL(itemClicked(QTreeWidgetItem*,int)), + this, SLOT(typeListClicked()) ); + connect( d->ui.typeListView, SIGNAL(itemSelectionChanged()), + this, SLOT(typeListClicked()) ); +} + +AddTransportDialog::~AddTransportDialog() +{ + delete d; +} + +void AddTransportDialog::accept() +{ + if( !d->selectedType().isValid() ) { + return; + } + + // Create a new transport and configure it. + Transport *transport = TransportManager::self()->createTransport(); + transport->setTransportType( d->selectedType() ); + if( d->selectedType().type() == Transport::EnumType::Akonadi ) { + // Create a resource instance if Akonadi-type transport. + using namespace Akonadi; + AgentInstanceCreateJob *cjob = new AgentInstanceCreateJob( d->selectedType().agentType() ); + if( !cjob->exec() ) { + kWarning() << "Failed to create agent instance of type" + << d->selectedType().agentType().identifier(); + return; + } + transport->setHost( cjob->instance().identifier() ); + } + transport->setName( d->ui.name->text() ); + transport->forceUniqueName(); + if( TransportManager::self()->configureTransport( transport, this ) ) { + // The user clicked OK and the transport settings were saved. + TransportManager::self()->addTransport( transport ); + if( d->ui.setDefault->isChecked() ) { + TransportManager::self()->setDefaultTransport( transport->id() ); + } + KDialog::accept(); + } +} + +#include "addtransportdialog.moc" diff --git a/mailtransport/transportmanagementwidget.h b/mailtransport/addtransportdialog.h similarity index 50% copy from mailtransport/transportmanagementwidget.h copy to mailtransport/addtransportdialog.h index 3b10d22ed..14f5cd07a 100644 --- a/mailtransport/transportmanagementwidget.h +++ b/mailtransport/addtransportdialog.h @@ -1,66 +1,67 @@ /* - Copyright (c) 2006 - 2007 Volker Krause - - Based on KMail code by: - Copyright (C) 2001-2003 Marc Mutz + 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 MAILTRANSPORT_TRANSPORTMANAGEMENTWIDGET_H -#define MAILTRANSPORT_TRANSPORTMANAGEMENTWIDGET_H +#ifndef MAILTRANSPORT_ADDTRANSPORTDIALOG_H +#define MAILTRANSPORT_ADDTRANSPORTDIALOG_H -#include -#include +#include namespace MailTransport { /** - A widget to manage mail transports. + @internal + + A dialog for creating a new transport. It asks the user for the transport + type and name, and then proceeds to configure the new transport. + + To create a new transport from applications, use + TransportManager::showNewTransportDialog(). + + @author Constantin Berzan + @since 4.4 */ -class MAILTRANSPORT_EXPORT TransportManagementWidget : public QWidget +class AddTransportDialog : public KDialog { Q_OBJECT public: /** - Creates a new TransportManagementWidget. - @param parent The parent widget. + Creates a new AddTransportDialog. */ - TransportManagementWidget( QWidget *parent = 0 ); + explicit AddTransportDialog( QWidget *parent = 0 ); /** - Destroys the widget. + Destroys the AddTransportDialog. */ - virtual ~TransportManagementWidget(); + virtual ~AddTransportDialog(); - private Q_SLOTS: - void fillTransportList(); - void updateButtonState(); - void addClicked(); - void editClicked(); - void removeClicked(); - void defaultClicked(); - void slotSendmail(); + /* reimpl */ + virtual void accept(); private: class Private; - Private * const d; + Private *const d; + + Q_PRIVATE_SLOT( d, void typeListClicked() ) + }; -} +} // namespace MailTransport -#endif +#endif // MAILTRANSPORT_ADDTRANSPORTDIALOG_H diff --git a/mailtransport/addtransportdialog.ui b/mailtransport/addtransportdialog.ui new file mode 100644 index 000000000..a5f19d5ea --- /dev/null +++ b/mailtransport/addtransportdialog.ui @@ -0,0 +1,90 @@ + + + AddTransportDialog + + + + 0 + 0 + 482 + 353 + + + + + 0 + 0 + + + + Step One: Select Transport Type + + + + + + + 0 + 0 + + + + Select an account type from the list below: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + true + + + false + + + + Type + + + + + Description + + + + + + + + Name: + + + + + + + + + + Make this the default outgoing account. + + + + + + + + KLineEdit + QLineEdit +
klineedit.h
+
+
+ + +
diff --git a/mailtransport/legacydecrypt.h b/mailtransport/attributeregistrar.cpp similarity index 52% copy from mailtransport/legacydecrypt.h copy to mailtransport/attributeregistrar.cpp index 209a3e9c1..b198074f9 100644 --- a/mailtransport/legacydecrypt.h +++ b/mailtransport/attributeregistrar.cpp @@ -1,49 +1,44 @@ /* - Copyright (c) 2007 Volker Krause - - KNode code: - Copyright (c) 1999-2005 the KNode authors. // krazy:exclude=copyright + 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 MAILTRANSPORT_LEGACYDECRYPT_H -#define MAILTRANSPORT_LEGACYDECRYPT_H +#include "dispatchmodeattribute.h" +#include "errorattribute.h" +#include "sentbehaviourattribute.h" +#include "transportattribute.h" -#include +#include -namespace MailTransport { +namespace { -/** - Methods to read passwords from config files still using legacy encryption. -*/ -class Legacy +// Anonymous namespace; function is invisible outside this file. +bool dummy() { - public: - /** - Read data encrypted using KMail's legacy encryption. - */ - static QString decryptKMail( const QString &data ); - - /** - Read data encrypted using KNode's legacy encryption. - */ - static QString decryptKNode( const QString &data ); -}; - + using namespace Akonadi; + using namespace MailTransport; + AttributeFactory::registerAttribute(); + AttributeFactory::registerAttribute(); + AttributeFactory::registerAttribute(); + AttributeFactory::registerAttribute(); + return true; } -#endif +// Called when this library is loaded. +const bool registered = dummy(); + +} // namespace diff --git a/mailtransport/configmodule.cpp b/mailtransport/configmodule.cpp index 0db3b9fac..b73fa98f3 100644 --- a/mailtransport/configmodule.cpp +++ b/mailtransport/configmodule.cpp @@ -1,40 +1,41 @@ /* Copyright (c) 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 "configmodule.h" #include "transportmanagementwidget.h" -#include -#include -#include +#include + +#include +#include using namespace MailTransport; K_PLUGIN_FACTORY( MailTransportConfigFactory, registerPlugin(); ) K_EXPORT_PLUGIN( MailTransportConfigFactory( "mailtransport", "libmailtransport" ) ) ConfigModule::ConfigModule( QWidget * parent, const QVariantList & args ) : KCModule( MailTransportConfigFactory::componentData(), parent, args ) { setButtons( 0 ); QVBoxLayout *l = new QVBoxLayout( this ); l->setMargin( 0 ); TransportManagementWidget *tmw = new TransportManagementWidget( this ); l->addWidget( tmw ); } diff --git a/mailtransport/configmodule.h b/mailtransport/configmodule.h index 6994d37bd..8a678bbfc 100644 --- a/mailtransport/configmodule.h +++ b/mailtransport/configmodule.h @@ -1,39 +1,39 @@ /* Copyright (c) 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 MAILTRANSPORT_CONFIGMODULE_H #define MAILTRANSPORT_CONFIGMODULE_H -#include +#include namespace MailTransport { /** KCModule for transport management. */ class ConfigModule : public KCModule { public: explicit ConfigModule( QWidget *parent = 0, const QVariantList &args = QVariantList() ); }; -} +} // namespace MailTransport -#endif +#endif // MAILTRANSPORT_CONFIGMODULE_H diff --git a/mailtransport/dispatcherinterface.cpp b/mailtransport/dispatcherinterface.cpp new file mode 100644 index 000000000..2965a8c4c --- /dev/null +++ b/mailtransport/dispatcherinterface.cpp @@ -0,0 +1,118 @@ +/* + 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 "dispatcherinterface.h" + +#include "outboxactions.h" + +#include +#include +#include + +#include +#include +#include +#include + +using namespace Akonadi; +using namespace MailTransport; + +/** + @internal +*/ +class MailTransport::DispatcherInterfacePrivate +{ + public: + DispatcherInterfacePrivate(); + ~DispatcherInterfacePrivate(); + + DispatcherInterface *instance; + + // slots + void massModifyResult( KJob *job ); + +}; + +K_GLOBAL_STATIC( DispatcherInterfacePrivate, sInstance ) + +DispatcherInterfacePrivate::DispatcherInterfacePrivate() + : instance( new DispatcherInterface( this ) ) +{ +} + +DispatcherInterfacePrivate::~DispatcherInterfacePrivate() +{ + delete instance; +} + +void DispatcherInterfacePrivate::massModifyResult( KJob *job ) +{ + // Nothing to do here, really. If the job fails, the user can retry it. + if( job->error() ) { + kDebug() << "failed" << job->errorString(); + } else { + kDebug() << "succeeded."; + } +} + + + +DispatcherInterface::DispatcherInterface( DispatcherInterfacePrivate *dd ) + : QObject() + , d( dd ) +{ +} + +DispatcherInterface *DispatcherInterface::self() +{ + return sInstance->instance; +} + +AgentInstance DispatcherInterface::dispatcherInstance() const +{ + AgentInstance a = AgentManager::self()->instance( QLatin1String( "akonadi_maildispatcher_agent" ) ); + if( !a.isValid() ) { + kWarning() << "Could not get MDA instance."; + } + return a; +} + +void DispatcherInterface::dispatchManually() +{ + if( !LocalFolders::self()->isReady() ) { + kWarning() << "LocalFolders not ready."; + return; + } + + FilterActionJob *mjob = new FilterActionJob( LocalFolders::self()->outbox(), new SendQueuedAction, this ); + connect( mjob, SIGNAL(result(KJob*)), this, SLOT(massModifyResult(KJob*)) ); +} + +void DispatcherInterface::retryDispatching() +{ + if( !LocalFolders::self()->isReady() ) { + kWarning() << "LocalFolders not ready."; + return; + } + + FilterActionJob *mjob = new FilterActionJob( LocalFolders::self()->outbox(), new ClearErrorAction, this ); + connect( mjob, SIGNAL(result(KJob*)), this, SLOT(massModifyResult(KJob*)) ); +} + +#include "dispatcherinterface.moc" diff --git a/mailtransport/dispatcherinterface.h b/mailtransport/dispatcherinterface.h new file mode 100644 index 000000000..6b01dabbf --- /dev/null +++ b/mailtransport/dispatcherinterface.h @@ -0,0 +1,87 @@ +/* + 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 MAILTRANSPORT_DISPATCHERINTERFACE_H +#define MAILTRANSPORT_DISPATCHERINTERFACE_H + +#include + +#include + +#include + +namespace MailTransport { + +class DispatcherInterfacePrivate; + +/** + @short An interface for applications to interact with the dispatcher agent. + + This class provides methods such as send queued messages (@see + dispatchManually) and retry sending (@see retryDispatching). + + This class also takes care of registering the attributes that the MDA and + MailTransport use. The attributes are registered the first time you call + self(), so do that early in your application. + + @author Constantin Berzan + @since 4.4 +*/ +class MAILTRANSPORT_EXPORT DispatcherInterface : public QObject +{ + Q_OBJECT + + public: + /** + Returns the DispatcherInterface instance. + */ + static DispatcherInterface *self(); + + /** + Returns the current instance of the MDA. May return an invalid + AgentInstance in case it cannot find the MDA. + */ + Akonadi::AgentInstance dispatcherInstance() const; + + /** + Looks for messages in the outbox with DispatchMode::Never and marks them + DispatchMode::Immediately for sending. + */ + void dispatchManually(); + + /** + Looks for messages in the outbox with ErrorAttribute, and clears them and + queues them again for sending. + */ + void retryDispatching(); + + private: + friend class DispatcherInterfacePrivate; + DispatcherInterfacePrivate *const d; + + // singleton class; the only instance resides in sInstance->instance + DispatcherInterface( DispatcherInterfacePrivate *dd ); + + Q_PRIVATE_SLOT( d, void massModifyResult( KJob* ) ) + +}; + +} // namespace MailTransport + +#endif // MAILTRANSPORT_DISPATCHERINTERFACE_H diff --git a/mailtransport/dispatchmodeattribute.cpp b/mailtransport/dispatchmodeattribute.cpp new file mode 100644 index 000000000..e7320a268 --- /dev/null +++ b/mailtransport/dispatchmodeattribute.cpp @@ -0,0 +1,106 @@ +/* + Copyright 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 "dispatchmodeattribute.h" + +#include + +#include "akonadi/attributefactory.h" + +using namespace Akonadi; +using namespace MailTransport; + +class DispatchModeAttribute::Private +{ + public: + DispatchMode mMode; + QDateTime mDueDate; +}; + +DispatchModeAttribute::DispatchModeAttribute( DispatchMode mode, const QDateTime &date ) + : d( new Private ) +{ + d->mMode = mode; + d->mDueDate = date; +} + +DispatchModeAttribute::~DispatchModeAttribute() +{ + delete d; +} + +DispatchModeAttribute* DispatchModeAttribute::clone() const +{ + return new DispatchModeAttribute( d->mMode, d->mDueDate ); +} + +QByteArray DispatchModeAttribute::type() const +{ + static const QByteArray sType( "DispatchModeAttribute" ); + return sType; +} + +QByteArray DispatchModeAttribute::serialized() const +{ + switch( d->mMode ) { + case Immediately: return "immediately"; + case AfterDueDate: return "after" + d->mDueDate.toString(Qt::ISODate).toLatin1(); + case Never: return "never"; + } + + Q_ASSERT( false ); + return QByteArray(); // suppress control-reaches-end-of-non-void-function warning +} + +void DispatchModeAttribute::deserialize( const QByteArray &data ) +{ + d->mDueDate = QDateTime(); + if ( data == "immediately" ) { + d->mMode = Immediately; + } else if ( data == "never" ) { + d->mMode = Never; + } else if ( data.startsWith( QByteArray( "after" ) ) ) { + d->mMode = AfterDueDate; + d->mDueDate = QDateTime::fromString( QString::fromLatin1( data.mid(5) ), Qt::ISODate ); + // NOTE: 5 is the strlen of "after". + } else { + kWarning() << "Failed to deserialize data [" << data << "]"; + } +} + +DispatchModeAttribute::DispatchMode DispatchModeAttribute::dispatchMode() const +{ + return d->mMode; +} + +void DispatchModeAttribute::setDispatchMode( DispatchMode mode ) +{ + d->mMode = mode; +} + +QDateTime DispatchModeAttribute::dueDate() const +{ + return d->mDueDate; +} + +void DispatchModeAttribute::setDueDate( const QDateTime &date ) +{ + d->mDueDate = date; +} + diff --git a/mailtransport/dispatchmodeattribute.h b/mailtransport/dispatchmodeattribute.h new file mode 100644 index 000000000..6bd9e636e --- /dev/null +++ b/mailtransport/dispatchmodeattribute.h @@ -0,0 +1,101 @@ +/* + Copyright 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 MAILTRANSPORT_DISPATCHMODEATTRIBUTE_H +#define MAILTRANSPORT_DISPATCHMODEATTRIBUTE_H + +#include + +#include + +#include + +namespace MailTransport { + +/** + Attribute determining how and when a message from the outbox should be + dispatched. Messages can be sent immediately, sent only when the user + explicitly requests it, or sent automatically at a certain date and time. + + @author Constantin Berzan + @since 4.4 +*/ +class MAILTRANSPORT_EXPORT DispatchModeAttribute : public Akonadi::Attribute +{ + public: + /** + Determines how the message is sent. + */ + enum DispatchMode + { + Immediately, ///< Send message as soon as possible. + AfterDueDate, ///< Send message at a certain date/time. + Never ///< Send message only when the user requests so. + }; + + /** + Creates a new DispatchModeAttribute. + */ + explicit DispatchModeAttribute( DispatchMode mode = Immediately, const QDateTime &date = QDateTime() ); + + /** + Destroys the DispatchModeAttribute. + */ + virtual ~DispatchModeAttribute(); + + /* reimpl */ + virtual DispatchModeAttribute* clone() const; + virtual QByteArray type() const; + virtual QByteArray serialized() const; + virtual void deserialize( const QByteArray &data ); + + /** + Returns the dispatch mode for the message. + @see DispatchMode. + */ + DispatchMode dispatchMode() const; + + /** + Sets the dispatch mode for the message. + @see DispatchMode. + */ + void setDispatchMode( DispatchMode mode ); + + /** + Returns the date and time when the message should be sent. + Only valid if dispatchMode() is AfterDueDate. + */ + QDateTime dueDate() const; + + /** + Sets the date and time when the message should be sent. + Make sure you set the DispatchMode to AfterDueDate first. + @see setDispatchMode. + */ + void setDueDate( const QDateTime &date ); + + private: + class Private; + Private *const d; + +}; + +} // namespace MailTransport + +#endif // MAILTRANSPORT_DISPATCHMODEATTRIBUTE_H diff --git a/mailtransport/errorattribute.cpp b/mailtransport/errorattribute.cpp new file mode 100644 index 000000000..e2393cd4d --- /dev/null +++ b/mailtransport/errorattribute.cpp @@ -0,0 +1,76 @@ +/* + Copyright 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 "errorattribute.h" + +#include + +#include + +using namespace Akonadi; +using namespace MailTransport; + +class ErrorAttribute::Private +{ + public: + QString mMessage; +}; + +ErrorAttribute::ErrorAttribute( const QString &msg ) + : d( new Private ) +{ + d->mMessage = msg; +} + +ErrorAttribute::~ErrorAttribute() +{ + delete d; +} + +ErrorAttribute* ErrorAttribute::clone() const +{ + return new ErrorAttribute( d->mMessage ); +} + +QByteArray ErrorAttribute::type() const +{ + static const QByteArray sType( "ErrorAttribute" ); + return sType; +} + +QByteArray ErrorAttribute::serialized() const +{ + return d->mMessage.toUtf8(); +} + +void ErrorAttribute::deserialize( const QByteArray &data ) +{ + d->mMessage = QString::fromUtf8( data ); +} + +QString ErrorAttribute::message() const +{ + return d->mMessage; +} + +void ErrorAttribute::setMessage( const QString &msg ) +{ + d->mMessage = msg; +} + diff --git a/mailtransport/errorattribute.h b/mailtransport/errorattribute.h new file mode 100644 index 000000000..26e42c510 --- /dev/null +++ b/mailtransport/errorattribute.h @@ -0,0 +1,75 @@ +/* + Copyright 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 MAILTRANSPORT_ERRORATTRIBUTE_H +#define MAILTRANSPORT_ERRORATTRIBUTE_H + +#include + +#include + +#include + +namespace MailTransport { + +/** + Attribute given to the messages that failed to be sent. Contains the error + message encountered. + + @author Constantin Berzan + @since 4.4 +*/ +class MAILTRANSPORT_EXPORT ErrorAttribute : public Akonadi::Attribute +{ + public: + /** + Creates a new ErrorAttribute. + */ + ErrorAttribute( const QString &msg = QString() ); + + /** + Destroys this ErrorAttribute. + */ + virtual ~ErrorAttribute(); + + /* reimpl */ + virtual ErrorAttribute* clone() const; + virtual QByteArray type() const; + virtual QByteArray serialized() const; + virtual void deserialize( const QByteArray &data ); + + /** + Returns the i18n'ed error message. + */ + QString message() const; + + /** + Sets the error message. + */ + void setMessage( const QString &msg ); + + private: + class Private; + Private *const d; + +}; + +} // namespace MailTransport + +#endif // MAILTRANSPORT_ERRORATTRIBUTE_H diff --git a/mailtransport/legacydecrypt.cpp b/mailtransport/legacydecrypt.cpp index 3cf6c8284..9da525774 100644 --- a/mailtransport/legacydecrypt.cpp +++ b/mailtransport/legacydecrypt.cpp @@ -1,47 +1,47 @@ /* Copyright (c) 2007 Volker Krause KNode code: Copyright (c) 1999-2005 the KNode authors. // krazy:exclude=copyright This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 "legacydecrypt.h" -#include +#include using namespace MailTransport; QString Legacy::decryptKMail( const QString &data ) { return KStringHandler::obscure( data ); } QString Legacy::decryptKNode( const QString &data ) { uint i, val, len = data.length(); QString result; for ( i = 0; i < len; ++i ) { val = data[i].toLatin1(); val -= ' '; val = ( 255 - ' ' ) - val; result += QLatin1Char( (char)( val + ' ' ) ); } return result; } diff --git a/mailtransport/legacydecrypt.h b/mailtransport/legacydecrypt.h index 209a3e9c1..a7ded7296 100644 --- a/mailtransport/legacydecrypt.h +++ b/mailtransport/legacydecrypt.h @@ -1,49 +1,49 @@ /* Copyright (c) 2007 Volker Krause KNode code: Copyright (c) 1999-2005 the KNode authors. // krazy:exclude=copyright This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 MAILTRANSPORT_LEGACYDECRYPT_H #define MAILTRANSPORT_LEGACYDECRYPT_H -#include +#include namespace MailTransport { /** Methods to read passwords from config files still using legacy encryption. */ class Legacy { public: /** Read data encrypted using KMail's legacy encryption. */ static QString decryptKMail( const QString &data ); /** Read data encrypted using KNode's legacy encryption. */ static QString decryptKNode( const QString &data ); }; -} +} // namespace MailTransport -#endif +#endif // MAILTRANSPORT_LEGACYDECRYPT_H diff --git a/mailtransport/mailtransport.kcfg b/mailtransport/mailtransport.kcfg index d4bad38ed..c1a71f331 100644 --- a/mailtransport/mailtransport.kcfg +++ b/mailtransport/mailtransport.kcfg @@ -1,112 +1,115 @@ 0 The name that will be used when referring to this server. i18n("Unnamed") + + + SMTP The domain name or numerical address of the SMTP server. The port number that the SMTP server is listening on. The default port is 25. 25 The user name to send to the server for authorization. A command to run locally, prior to sending email. This can be used to set up SSH tunnels, for example. Leave it empty if no command should be run. Check this option if your SMTP server requires authentication before accepting mail. This is known as 'Authenticated SMTP' or simply ASMTP. false Check this option to have your password stored. If KWallet is available the password will be stored there which is considered safe. However, if KWallet is not available, the password will be stored in the configuration file. The password is stored in an obfuscated format, but should not be considered secure from decryption efforts if access to the configuration file is obtained. false PLAIN Check this option to use a custom hostname when identifying to the mail server. This is useful when your system's hostname may not be set correctly or to mask your system's true hostname. false Enter the hostname that should be used when identifying to the server. diff --git a/mailtransport/mailtransport_defs.h b/mailtransport/mailtransport_defs.h index 3245e1ece..a4125bb5d 100644 --- a/mailtransport/mailtransport_defs.h +++ b/mailtransport/mailtransport_defs.h @@ -1,57 +1,57 @@ /* Copyright (c) 2006 - 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 MAILTRANSPORT_MAILTRANSPORT_DEFS_H #define MAILTRANSPORT_MAILTRANSPORT_DEFS_H /** @file mailtransport_defs.h Internal file containing constant definitions etc. */ #define WALLET_FOLDER QLatin1String("mailtransports") #define KMAIL_WALLET_FOLDER QLatin1String("kmail") #define DBUS_SERVICE_NAME QLatin1String("org.kde.pim.TransportManager") #define DBUS_INTERFACE_NAME QLatin1String("org.kde.pim.TransportManager") #define DBUS_OBJECT_PATH QLatin1String("/TransportManager") #define DBUS_CHANGE_SIGNAL QLatin1String("changesCommitted") #define SMTP_PROTOCOL QLatin1String("smtp") #define SMTPS_PROTOCOL QLatin1String("smtps") #define SMTP_PORT 25 #define SMTPS_PORT 465 -/* Because ServerTest is also capable of testing IMAP, - * some addition defines. */ +// Because ServerTest is also capable of testing IMAP, +// some additional defines: #define IMAP_PROTOCOL QLatin1String("imap") #define IMAPS_PROTOCOL QLatin1String("imaps") #define POP_PROTOCOL QLatin1String("pop") #define POPS_PROTOCOL QLatin1String("pops") #define IMAP_PORT 143 #define IMAPS_PORT 993 #define POP_PORT 110 #define POPS_PORT 995 #endif diff --git a/mailtransport/mailtransport_export.h b/mailtransport/mailtransport_export.h index 83968b468..49c366f58 100644 --- a/mailtransport/mailtransport_export.h +++ b/mailtransport/mailtransport_export.h @@ -1,35 +1,51 @@ /* Copyright (c) 2006 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 MAILTRANSPORT_MAILTRANSPORT_EXPORT_H #define MAILTRANSPORT_MAILTRANSPORT_EXPORT_H #include #ifndef MAILTRANSPORT_EXPORT # if defined(MAKE_MAILTRANSPORT_LIB) /* We are building this library */ # define MAILTRANSPORT_EXPORT KDE_EXPORT # else /* We are using this library */ # define MAILTRANSPORT_EXPORT KDE_IMPORT # endif #endif +// TODO KDE5: Get rid of all this. +#ifndef MAILTRANSPORT_DEPRECATED +# if defined( USES_DEPRECATED_MAILTRANSPORT_API ) + /* Avoid deprecated warnings from ourselves and the MDA. */ +# define MAILTRANSPORT_DEPRECATED +# else + /* Show deprecated warnings for anyone else. */ +# define MAILTRANSPORT_DEPRECATED KDE_DEPRECATED +# endif +#endif + +#ifndef MAILTRANSPORT_EXPORT_DEPRECATED +# define MAILTRANSPORT_EXPORT_DEPRECATED MAILTRANSPORT_DEPRECATED MAILTRANSPORT_EXPORT +#endif + + #endif diff --git a/mailtransport/messagequeuejob.cpp b/mailtransport/messagequeuejob.cpp new file mode 100644 index 000000000..0e4c5f733 --- /dev/null +++ b/mailtransport/messagequeuejob.cpp @@ -0,0 +1,290 @@ +/* + 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 "messagequeuejob.h" + +#include "transport.h" +#include "transportattribute.h" +#include "transportmanager.h" + +#include +#include + +#include +#include +#include +#include +#include + +using namespace Akonadi; +using namespace KMime; +using namespace MailTransport; + +/** + @internal +*/ +class MailTransport::MessageQueueJob::Private +{ + public: + Private( MessageQueueJob *qq ) + : q( qq ) + { + transport = -1; + dispatchMode = DispatchModeAttribute::Immediately; + sentBehaviour = SentBehaviourAttribute::MoveToDefaultSentCollection; + moveToCollection = -1; + started = false; + } + + MessageQueueJob *const q; + + Message::Ptr message; + int transport; + DispatchModeAttribute::DispatchMode dispatchMode; + QDateTime dueDate; + SentBehaviourAttribute::SentBehaviour sentBehaviour; + Collection::Id moveToCollection; + QString from; + QStringList to; + QStringList cc; + QStringList bcc; + bool started; + + /** + Returns true if this message has everything it needs and is ready to be + sent. + */ + bool validate(); + + // slot + void doStart(); + +}; + +bool MessageQueueJob::Private::validate() +{ + if( !message ) { + q->setError( UserDefinedError ); + q->setErrorText( i18n( "Empty message." ) ); + q->emitResult(); + return false; + } + + if( to.count() + cc.count() + bcc.count() == 0 ) { + q->setError( UserDefinedError ); + q->setErrorText( i18n( "Message has no recipients." ) ); + q->emitResult(); + return false; + } + + if( dispatchMode == DispatchModeAttribute::AfterDueDate && !dueDate.isValid() ) { + q->setError( UserDefinedError ); + q->setErrorText( i18n( "Message has invalid due date." ) ); + q->emitResult(); + return false; + } + + if( TransportManager::self()->transportById( transport, false ) == 0 ) { + q->setError( UserDefinedError ); + q->setErrorText( i18n( "Message has invalid transport." ) ); + q->emitResult(); + return false; + } + + if( sentBehaviour == SentBehaviourAttribute::MoveToCollection && moveToCollection < 0 ) { + q->setError( UserDefinedError ); + q->setErrorText( i18n( "Message has invalid sent-mail folder." ) ); + q->emitResult(); + return false; + } else if( sentBehaviour == SentBehaviourAttribute::MoveToDefaultSentCollection ) { + Q_ASSERT( LocalFolders::self()->isReady() ); + Q_ASSERT( LocalFolders::self()->sentMail().isValid() ); + } + + return true; // all ok +} + +void MessageQueueJob::Private::doStart() +{ + LocalFolders::self()->disconnect( q ); + Q_ASSERT( !started ); + started = true; + + if( !validate() ) { + // The error has been set; the result has been emitted. + return; + } + + // Create item. + Item item; + item.setMimeType( QLatin1String( "message/rfc822" ) ); + item.setPayload( message ); + + // Set attributes. + AddressAttribute *addrA = new AddressAttribute( from, to, cc, bcc ); + DispatchModeAttribute *dmA = new DispatchModeAttribute( dispatchMode, dueDate ); + SentBehaviourAttribute *sA = new SentBehaviourAttribute( sentBehaviour, moveToCollection ); + TransportAttribute *tA = new TransportAttribute( transport ); + item.addAttribute( addrA ); + item.addAttribute( dmA ); + item.addAttribute( sA ); + item.addAttribute( tA ); + + // Set flags. + item.setFlag( "queued" ); + + // Store the item in the outbox. + Q_ASSERT( LocalFolders::self()->isReady() ); + Collection col = LocalFolders::self()->outbox(); + ItemCreateJob *job = new ItemCreateJob( item, col ); // job autostarts + q->addSubjob( job ); +} + + + +MessageQueueJob::MessageQueueJob( QObject *parent ) + : KCompositeJob( parent ) + , d( new Private( this ) ) +{ +} + +MessageQueueJob::~MessageQueueJob() +{ + delete d; +} + +Message::Ptr MessageQueueJob::message() const +{ + return d->message; +} + +int MessageQueueJob::transportId() const +{ + return d->transport; +} + +DispatchModeAttribute::DispatchMode MessageQueueJob::dispatchMode() const +{ + return d->dispatchMode; +} + +QDateTime MessageQueueJob::sendDueDate() const +{ + if( d->dispatchMode != DispatchModeAttribute::AfterDueDate ) { + kWarning() << "Called when dispatchMode is not AfterDueDate."; + } + return d->dueDate; +} + +Collection::Id MessageQueueJob::moveToCollection() const +{ + if( d->sentBehaviour != SentBehaviourAttribute::MoveToCollection ) { + kWarning() << "Called when sentBehaviour is not MoveToCollection."; + } + return d->moveToCollection; +} + +QString MessageQueueJob::from() const +{ + return d->from; +} + +QStringList MessageQueueJob::to() const +{ + return d->to; +} + +QStringList MessageQueueJob::cc() const +{ + return d->cc; +} + +QStringList MessageQueueJob::bcc() const +{ + return d->bcc; +} + +void MessageQueueJob::setMessage( Message::Ptr message ) +{ + d->message = message; +} + +void MessageQueueJob::setTransportId( int id ) +{ + d->transport = id; +} + +void MessageQueueJob::setDispatchMode( DispatchModeAttribute::DispatchMode mode ) +{ + d->dispatchMode = mode; +} + +void MessageQueueJob::setDueDate( const QDateTime &date ) +{ + d->dueDate = date; +} + +void MessageQueueJob::setSentBehaviour( SentBehaviourAttribute::SentBehaviour beh ) +{ + d->sentBehaviour = beh; +} + +void MessageQueueJob::setMoveToCollection( Collection::Id cid ) +{ + d->moveToCollection = cid; +} + +void MessageQueueJob::setFrom( const QString &from ) +{ + d->from = from; +} + +void MessageQueueJob::setTo( const QStringList &to ) +{ + d->to = to; +} + +void MessageQueueJob::setCc( const QStringList &cc ) +{ + d->cc = cc; +} + +void MessageQueueJob::setBcc( const QStringList &bcc ) +{ + d->bcc = bcc; +} + +void MessageQueueJob::start() +{ + LocalFolders *folders = LocalFolders::self(); + connect( folders, SIGNAL( foldersReady() ), this, SLOT( doStart() ) ); + folders->fetch(); // will emit foldersReady() +} + +void MessageQueueJob::slotResult( KJob *job ) +{ + // error handling + KCompositeJob::slotResult( job ); + + if( !error() ) { + emitResult(); + } +} + +#include "messagequeuejob.moc" diff --git a/mailtransport/messagequeuejob.h b/mailtransport/messagequeuejob.h new file mode 100644 index 000000000..ee337a44d --- /dev/null +++ b/mailtransport/messagequeuejob.h @@ -0,0 +1,255 @@ +/* + 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 MAILTRANSPORT_MESSAGEQUEUEJOB_H +#define MAILTRANSPORT_MESSAGEQUEUEJOB_H + +#include + +#include "dispatchmodeattribute.h" +#include "sentbehaviourattribute.h" + +#include +#include +#include + +#include + +#include + +#include +#include + +namespace MailTransport { + +/** + @short Provides an interface for sending email. + + This class takes a KMime::Message and some related info such as sender and + recipient addresses, and places the message in the outbox. The mail + dispatcher agent will then take it from there and send it. + + This is the preferred way for applications to send email. + + This job requires some options to be set before being started. These are + setMessage, setTransportId, setFrom, and one of setTo, setCc, or setBcc. + Other settings are optional: setDispatchMode, setSentBehaviour. + + Example: + @code + + MessageQueueJob *job = new MessageQueueJob( this ); + job->setMessage( msg ); // msg is a Message::Ptr + job->setTransportId( TransportManager::self()->defaultTransportId() ); + // Use the default dispatch mode. + // Use the default sent-behaviour. + job->setFrom( from ); // from is a QString + job->setTo( to ); // to is a QStringList + connect( job, SIGNAL(result(KJob*)), this, SLOT(jobResult(KJob*)) ); + job->start(); + + @endcode + + @see DispatchModeAttribute + @see SentBehaviourAttribute + + @author Constantin Berzan + @since 4.4 +*/ +class MAILTRANSPORT_EXPORT MessageQueueJob : public KCompositeJob +{ + Q_OBJECT + + public: + /** + Creates a new MessageQueueJob. + This is not an autostarting job; you need to call start() yourself. + */ + explicit MessageQueueJob( QObject *parent = 0 ); + + /** + Destroys the MessageQueueJob. + This job deletes itself after finishing. + */ + virtual ~MessageQueueJob(); + + /** + Returns the message to be sent. + */ + KMime::Message::Ptr message() const; + + /** + Returns the transport id to use for sending the message. + @see TransportManager. + */ + int transportId() const; + + /** + Returns the dispatch mode for this message. + @see DispatchModeAttribute. + */ + DispatchModeAttribute::DispatchMode dispatchMode() const; + + /** + Returns the date and time when this message should be sent. + Only valid if dispatchMode() is AfterDueDate. + @see DispatchModeAttribute. + */ + QDateTime sendDueDate() const; + + /** + Returns the sent-behaviour of this message. + This determines what will happen to the message after it is sent. + @see SentBehaviourAttribute. + */ + SentBehaviourAttribute::SentBehaviour sentBehaviour() const; + + /** + Returns the collection to which the message will be moved after it is + sent. + Only valid if sentBehaviour() is MoveToCollection. + @see SentBehaviourAttribute. + */ + Akonadi::Collection::Id moveToCollection() const; + + /** + Returns the address of the sender. + */ + QString from() const; + + /** + Returns the addresses of the "To:" receivers. + */ + QStringList to() const; + + /** + Returns the addresses of the "Cc:" receivers. + */ + QStringList cc() const; + + /** + Returns the addresses of the "Bcc:" receivers. + */ + QStringList bcc() const; + + /** + Sets the message to be sent. + */ + void setMessage( KMime::Message::Ptr message ); + + /** + Sets the transport id to use for sending the message. If you want to + use the default transport, you must specify so explicitly: + + @code + job->setTransportId( TransportManager::self()->defaultTransportId() ); + @endcode + + @see TransportManager. + */ + void setTransportId( int id ); + + /** + Sets the dispatch mode for this message. + The default dispatch mode is Immediately (meaning the message will be + sent as soon as possible). + @see DispatchModeAttribute. + */ + void setDispatchMode( DispatchModeAttribute::DispatchMode mode ); + + /** + Sets the date and time when this message should be sent. + + @code + job->setDispatchMode( DispatchModeAttribute::AfterDueDate ); + job->setDueDate( ... ); + @endcode + + @see DispatchModeAttribute. + */ + void setDueDate( const QDateTime &date ); + + /** + Sets the sent-behaviour of this message. + This determines what will happen to the message after it is sent. + The default sent-behaviour is MoveToDefaultSentCollection, which moves + the message to the default sent-mail collection. + @see SentBehaviourAttribute. + */ + void setSentBehaviour( SentBehaviourAttribute::SentBehaviour beh ); + + /** + Sets the collection to which the message will be moved after it is + sent. + + @code + job->setSentBehaviour( SentBehaviourAttribute::MoveToCollection ); + job->setMoveToCollection( ... ); + @endcode + + @see SentBehaviourAttribute. + */ + void setMoveToCollection( Akonadi::Collection::Id cid ); + + /** + Sets the address of the sender. + */ + void setFrom( const QString &from ); + + /** + Sets the addresses of the "To:" receivers." + */ + void setTo( const QStringList &to ); + + /** + Sets the addresses of the "Cc:" receivers." + */ + void setCc( const QStringList &cc ); + + /** + Sets the addresses of the "Bcc:" receivers." + */ + void setBcc( const QStringList &bcc ); + + /** + Creates the item and places it in the outbox. + It is now queued for sending by the mail dispatcher agent. + */ + virtual void start(); + + protected Q_SLOTS: + /** + Called when the ItemCreateJob subjob finishes. + + (reimplemented from KCompositeJob) + */ + virtual void slotResult( KJob * ); + + private: + class Private; + friend class Private; + Private *const d; + + Q_PRIVATE_SLOT( d, void doStart() ) + +}; + +} // namespace MailTransport + +#endif // MAILTRANSPORT_MESSAGEQUEUEJOB_H diff --git a/mailtransport/outboxactions.cpp b/mailtransport/outboxactions.cpp new file mode 100644 index 000000000..a5240acd8 --- /dev/null +++ b/mailtransport/outboxactions.cpp @@ -0,0 +1,78 @@ +/* + 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 "outboxactions.h" + +#include "dispatchmodeattribute.h" +#include "errorattribute.h" + +#include + +using namespace Akonadi; +using namespace MailTransport; + +ItemFetchScope SendQueuedAction::fetchScope() const +{ + ItemFetchScope scope; + scope.fetchFullPayload( false ); + scope.fetchAttribute(); + return scope; +} + +bool SendQueuedAction::itemAccepted( const Item &item ) const +{ + if( !item.hasAttribute() ) { + kWarning() << "Item doesn't have DispatchModeAttribute."; + return false; + } + + return item.attribute()->dispatchMode() == DispatchModeAttribute::Never; +} + +Job *SendQueuedAction::itemAction( const Item &item ) const +{ + Item cp = item; + cp.addAttribute( new DispatchModeAttribute ); // defaults to Immediately + return new ItemModifyJob( cp ); +} + + + +ItemFetchScope ClearErrorAction::fetchScope() const +{ + ItemFetchScope scope; + scope.fetchFullPayload( false ); + scope.fetchAttribute(); + return scope; +} + +bool ClearErrorAction::itemAccepted( const Item &item ) const +{ + return item.hasAttribute(); +} + +Job *ClearErrorAction::itemAction( const Item &item ) const +{ + Item cp = item; + cp.removeAttribute(); + cp.clearFlag( "error" ); + cp.setFlag( "queued" ); + return new ItemModifyJob( cp ); +} + diff --git a/mailtransport/outboxactions.h b/mailtransport/outboxactions.h new file mode 100644 index 000000000..a852b072d --- /dev/null +++ b/mailtransport/outboxactions.h @@ -0,0 +1,74 @@ +/* + 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 MAILTRANSPORT_OUTBOXACTIONS_H +#define MAILTRANSPORT_OUTBOXACTIONS_H + +#include + +#include +#include +#include + +namespace MailTransport { + +/** + FilterAction that finds all messages with a DispatchMode of Never + and assigns them a DispatchMode of Immediately. + + This is used to send "queued" messages on demand. + + @see FilterActionJob + + @author Constantin Berzan + @since 4.4 +*/ +class MAILTRANSPORT_EXPORT SendQueuedAction : public Akonadi::FilterAction +{ + public: + /* reimpl */ + virtual Akonadi::ItemFetchScope fetchScope() const; + virtual bool itemAccepted( const Akonadi::Item &item ) const; + virtual Akonadi::Job *itemAction( const Akonadi::Item &item ) const; +}; + + +/** + FilterAction that finds all messages with an ErrorAttribute, + removes the attribute, and sets the "queued" flag. + + This is used to retry sending messages that failed. + + @see FilterActionJob + + @author Constantin Berzan + @since 4.4 +*/ +class MAILTRANSPORT_EXPORT ClearErrorAction : public Akonadi::FilterAction +{ + public: + /* reimpl */ + virtual Akonadi::ItemFetchScope fetchScope() const; + virtual bool itemAccepted( const Akonadi::Item &item ) const; + virtual Akonadi::Job *itemAction( const Akonadi::Item &item ) const; +}; + +} // namespace MailTransport + +#endif // MAILTRANSPORT_OUTBOXACTIONS_H diff --git a/mailtransport/precommandjob.cpp b/mailtransport/precommandjob.cpp index cef89c10d..9c75dfb54 100644 --- a/mailtransport/precommandjob.cpp +++ b/mailtransport/precommandjob.cpp @@ -1,100 +1,100 @@ /* Copyright (c) 2007 Volker Krause Based on KMail code by: Copyright (c) 1996-1998 Stefan Taferner Copyright (c) 2000-2002 Michael Haeckel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 "precommandjob.h" -#include -#include +#include +#include #include using namespace MailTransport; /** * Private class that helps to provide binary compatibility between releases. * @internal */ class PreCommandJobPrivate { public: KProcess *process; QString precommand; }; PrecommandJob::PrecommandJob( const QString &precommand, QObject *parent ) : KJob( parent ), d( new PreCommandJobPrivate ) { d->precommand = precommand; d->process = new KProcess( this ); connect( d->process, SIGNAL(started()), SLOT(slotStarted()) ); connect( d->process, SIGNAL(error(QProcess::ProcessError error)), SLOT(slotError(QProcess::ProcessError error))); connect( d->process, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(slotFinished(int, QProcess::ExitStatus)) ); } PrecommandJob::~ PrecommandJob() { delete d; } void PrecommandJob::start() { d->process->setShellCommand( d->precommand ); d->process->start(); } void PrecommandJob::slotStarted() { emit infoMessage( this, i18n( "Executing precommand" ), i18n( "Executing precommand '%1'.", d->precommand ) ); } void PrecommandJob::slotError( QProcess::ProcessError error ) { setError( UserDefinedError ); setErrorText( i18n( "Could not execute precommand '%1'.", d->precommand ) ); kDebug() << "Execution precommand has failed:" << error; emitResult(); } bool PrecommandJob::doKill() { delete d->process; d->process = 0; return true; } void PrecommandJob::slotFinished( int exitCode, QProcess::ExitStatus exitStatus ) { if ( exitStatus == QProcess::CrashExit ) { setError( UserDefinedError ); setErrorText( i18n( "The precommand crashed." ) ); } else if ( exitCode != 0 ) { setError( UserDefinedError ); setErrorText( i18n( "The precommand exited with code %1.", d->process->exitStatus() ) ); } emitResult(); } #include "precommandjob.moc" diff --git a/mailtransport/precommandjob.h b/mailtransport/precommandjob.h index 440cb9ffc..2ed02d5e4 100644 --- a/mailtransport/precommandjob.h +++ b/mailtransport/precommandjob.h @@ -1,74 +1,74 @@ /* Copyright (c) 2007 Volker Krause Based on KMail code by: Copyright (c) 1996-1998 Stefan Taferner Copyright (c) 2000-2002 Michael Haeckel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 MAILTRANSPORT_PRECOMMANDJOB_H #define MAILTRANSPORT_PRECOMMANDJOB_H -#include +#include -#include +#include class PreCommandJobPrivate; namespace MailTransport { /** Job to execute commands before connecting to an account. */ class PrecommandJob : public KJob { Q_OBJECT public: /** Creates a new precommand job. @param precommand The command to run. @param parent The parent object. */ explicit PrecommandJob( const QString &precommand, QObject *parent = 0 ); /** Destroys this job. */ virtual ~PrecommandJob(); /** Executes the precommand. */ virtual void start(); protected: virtual bool doKill(); private slots: void slotFinished( int, QProcess::ExitStatus ); void slotStarted(); void slotError( QProcess::ProcessError error ); private: PreCommandJobPrivate *const d; }; -} +} // namespace MailTransport -#endif +#endif // MAILTRANSPORT_PRECOMMANDJOB_H diff --git a/mailtransport/resourcesendjob.cpp b/mailtransport/resourcesendjob.cpp new file mode 100644 index 000000000..192b8c77f --- /dev/null +++ b/mailtransport/resourcesendjob.cpp @@ -0,0 +1,96 @@ +/* + 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 "resourcesendjob.h" +#include "messagequeuejob.h" +#include "transport.h" + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + + +using namespace Akonadi; +using namespace KMime; +using namespace MailTransport; + +/** + * Private class that helps to provide binary compatibility between releases. + * @internal + */ +class MailTransport::ResourceSendJobPrivate +{ + public: + ResourceSendJobPrivate( ResourceSendJob *qq ) + : q( qq ) + { + } + + void slotEmitResult(); // slot + + ResourceSendJob *const q; +}; + +void ResourceSendJobPrivate::slotEmitResult() +{ + // KCompositeJob took care of the error. + q->emitResult(); +} + +ResourceSendJob::ResourceSendJob( Transport *transport, QObject *parent ) + : TransportJob( transport, parent ), d( new ResourceSendJobPrivate( this ) ) +{ +} + +ResourceSendJob::~ResourceSendJob() +{ + delete d; +} + +void ResourceSendJob::doStart() +{ + Message::Ptr msg = Message::Ptr( new Message ); + msg->setContent( data() ); + MessageQueueJob *job = new MessageQueueJob; + job->setMessage( msg ); + job->setTransportId( transport()->id() ); + // Default dispatch mode (send now). + // Move to default sent-mail collection. + job->setFrom( sender() ); + job->setTo( to() ); + job->setCc( cc() ); + job->setBcc( bcc() ); + addSubjob( job ); + // Once the item is in the outbox, there is nothing more we can do. + connect( job, SIGNAL(result(KJob*)), this, SLOT(slotEmitResult()) ); + job->start(); +} + +#include "resourcesendjob.moc" diff --git a/mailtransport/resourcesendjob.h b/mailtransport/resourcesendjob.h new file mode 100644 index 000000000..d1dcbe60e --- /dev/null +++ b/mailtransport/resourcesendjob.h @@ -0,0 +1,74 @@ +/* + 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 MAILTRANSPORT_RESOURCESENDJOB_H +#define MAILTRANSPORT_RESOURCESENDJOB_H + +#include + +#include + +namespace MailTransport { + +class ResourceSendJobPrivate; + +/** + Mail transport job for an Akonadi resource-based transport. + + This is a wrapper job that makes old applications work with resource-based + transports. It calls the appropriate methods in MessageQueueJob, and emits + result() as soon as the item is placed in the outbox, since there is no way + of monitoring the progress from here. + + @deprecated Use MessageQueueJob for placing messages in the outbox. + + @author Constantin Berzan + @since 4.4 +*/ +class MAILTRANSPORT_EXPORT_DEPRECATED ResourceSendJob : public TransportJob +{ + Q_OBJECT + public: + /** + Creates an ResourceSendJob. + @param transport The transport object to use. + @param parent The parent object. + */ + explicit ResourceSendJob( Transport *transport, QObject *parent = 0 ); + + /** + Destroys this job. + */ + virtual ~ResourceSendJob(); + + protected: + /** reimpl */ + virtual void doStart(); + + private: + friend class ResourceSendJobPrivate; + ResourceSendJobPrivate *const d; + + Q_PRIVATE_SLOT( d, void slotEmitResult() ) + +}; + +} // namespace MailTransport + +#endif // MAILTRANSPORT_RESOURCESENDJOB_H diff --git a/mailtransport/sendmailconfigwidget.cpp b/mailtransport/sendmailconfigwidget.cpp new file mode 100644 index 000000000..229fcda44 --- /dev/null +++ b/mailtransport/sendmailconfigwidget.cpp @@ -0,0 +1,72 @@ +/* + Copyright (c) 2009 Constantin Berzan + + Based on MailTransport code by: + Copyright (c) 2006 - 2007 Volker Krause + Copyright (c) 2007 KovoKs + + Based on KMail code by: + Copyright (c) 2001-2002 Michael Haeckel + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; 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 "sendmailconfigwidget.h" +#include "transportconfigwidget_p.h" +#include "ui_sendmailsettings.h" + +#include + +using namespace MailTransport; + +class MailTransport::SendmailConfigWidgetPrivate : public TransportConfigWidgetPrivate +{ + public: + Ui::SendmailSettings ui; + +}; + +SendmailConfigWidget::SendmailConfigWidget( Transport *transport, QWidget *parent ) + : TransportConfigWidget( *new SendmailConfigWidgetPrivate, transport, parent ) +{ + init(); +} + +SendmailConfigWidget::SendmailConfigWidget( SendmailConfigWidgetPrivate &dd, + Transport *transport, QWidget *parent ) + : TransportConfigWidget( dd, transport, parent ) +{ + init(); +} + +void SendmailConfigWidget::init() +{ + Q_D( SendmailConfigWidget ); + + d->ui.setupUi( this ); + d->ui.kcfg_host->setMode( KFile::File|KFile::ExistingOnly|KFile::LocalOnly ); + d->manager->addWidget( this ); // otherwise it doesn't find out about these widgets + d->manager->updateWidgets(); + + if( d->ui.kcfg_host->url().isEmpty() ) { + // Locate sendmail. + // This is imperfect, because it shows the standard path if an empty path + // is saved in the config. + d->ui.kcfg_host->setText( KStandardDirs::findExe( QLatin1String( "sendmail" ) ) ); + } +} + +#include "sendmailconfigwidget.moc" diff --git a/mailtransport/transportmanagementwidget.h b/mailtransport/sendmailconfigwidget.h similarity index 52% copy from mailtransport/transportmanagementwidget.h copy to mailtransport/sendmailconfigwidget.h index 3b10d22ed..62667515c 100644 --- a/mailtransport/transportmanagementwidget.h +++ b/mailtransport/sendmailconfigwidget.h @@ -1,66 +1,64 @@ /* + Copyright (c) 2009 Constantin Berzan + + Based on MailTransport code by: Copyright (c) 2006 - 2007 Volker Krause Based on KMail code by: - Copyright (C) 2001-2003 Marc Mutz + Copyright (c) 2001-2002 Michael Haeckel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 MAILTRANSPORT_TRANSPORTMANAGEMENTWIDGET_H -#define MAILTRANSPORT_TRANSPORTMANAGEMENTWIDGET_H +#ifndef MAILTRANSPORT_SENDMAILCONFIGWIDGET_H +#define MAILTRANSPORT_SENDMAILCONFIGWIDGET_H -#include -#include +#include "transportconfigwidget.h" namespace MailTransport { +class Transport; + +/** + @internal +*/ +class SendmailConfigWidgetPrivate; + /** - A widget to manage mail transports. + @internal + Configuration widget for a Sendmail transport. */ -class MAILTRANSPORT_EXPORT TransportManagementWidget : public QWidget +class SendmailConfigWidget : public TransportConfigWidget { Q_OBJECT public: - /** - Creates a new TransportManagementWidget. - @param parent The parent widget. - */ - TransportManagementWidget( QWidget *parent = 0 ); - - /** - Destroys the widget. - */ - virtual ~TransportManagementWidget(); - - private Q_SLOTS: - void fillTransportList(); - void updateButtonState(); - void addClicked(); - void editClicked(); - void removeClicked(); - void defaultClicked(); - void slotSendmail(); + explicit SendmailConfigWidget( Transport *transport, QWidget *parent = 0 ); + //virtual ~SendmailConfigWidget(); + + protected: + SendmailConfigWidget( SendmailConfigWidgetPrivate &dd, Transport *transport, QWidget *parent ); private: - class Private; - Private * const d; + Q_DECLARE_PRIVATE( SendmailConfigWidget ) + + void init(); + }; -} +} // namespace MailTransport -#endif +#endif // MAILTRANSPORT_SENDMAILCONFIGWIDGET_H diff --git a/mailtransport/sendmailjob.cpp b/mailtransport/sendmailjob.cpp index d0551d416..5257bf821 100644 --- a/mailtransport/sendmailjob.cpp +++ b/mailtransport/sendmailjob.cpp @@ -1,110 +1,110 @@ /* Copyright (c) 2007 Volker Krause Copyright (c) 2007 KovoKs Based on KMail code by: Copyright (c) 1996-1998 Stefan Taferner This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 "sendmailjob.h" #include "transport.h" -#include +#include #include #include using namespace MailTransport; /** * Private class that helps to provide binary compatibility between releases. * @internal */ class SendMailJobPrivate { public: QProcess *process; QString lastError; }; SendmailJob::SendmailJob( Transport *transport, QObject *parent ) : TransportJob( transport, parent ), d( new SendMailJobPrivate ) { d->process = new QProcess( this ); connect( d->process, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(sendmailExited(int, QProcess::ExitStatus)) ); connect( d->process, SIGNAL(error(QProcess::ProcessError)), SLOT(receivedError()) ); connect( d->process, SIGNAL(readyReadStandardError()), SLOT(receivedStdErr()) ); } SendmailJob::~ SendmailJob() { delete d; } void SendmailJob::doStart() { QStringList arguments; arguments << QLatin1String( "-i" ) << QLatin1String( "-f" ) << sender() << to() << cc() << bcc(); d->process->start( transport()->host(), arguments ); if ( !d->process->waitForStarted() ) { setError( UserDefinedError ); setErrorText( i18n( "Failed to execute mailer program %1", transport()->host() ) ); emitResult(); } else { d->process->write( buffer()->readAll() ); d->process->closeWriteChannel(); } } void SendmailJob::sendmailExited( int exitCode, QProcess::ExitStatus exitStatus ) { if ( exitStatus != 0 || exitCode != 0 ) { setError( UserDefinedError ); if ( d->lastError.isEmpty() ) { setErrorText( i18n( "Sendmail exited abnormally." ) ); } else { setErrorText( i18n( "Sendmail exited abnormally: %1", d->lastError ) ); } } emitResult(); } void SendmailJob::receivedError() { d->lastError += d->process->errorString(); } void SendmailJob::receivedStdErr() { d->lastError += QLatin1String( d->process->readAllStandardError() ); } bool SendmailJob::doKill() { delete d->process; d->process = 0; return true; } #include "sendmailjob.moc" diff --git a/mailtransport/sendmailjob.h b/mailtransport/sendmailjob.h index 261e681fe..0c967bf2e 100644 --- a/mailtransport/sendmailjob.h +++ b/mailtransport/sendmailjob.h @@ -1,68 +1,71 @@ /* Copyright (c) 2007 Volker Krause Copyright (c) 2007 KovoKs Based on KMail code by: Copyright (c) 1996-1998 Stefan Taferner This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 MAILTRANSPORT_SENDMAILJOB_H #define MAILTRANSPORT_SENDMAILJOB_H #include #include + class SendMailJobPrivate; namespace MailTransport { /** Mail transport job for sendmail. + + @deprecated Use MessageQueueJob for sending e-mail. */ -class MAILTRANSPORT_EXPORT SendmailJob : public TransportJob +class MAILTRANSPORT_EXPORT_DEPRECATED SendmailJob : public TransportJob { Q_OBJECT public: /** Creates a SendmailJob. @param transport The transport settings. @param parent The parent object. */ explicit SendmailJob( Transport *transport, QObject *parent = 0 ); /** Destroys this job. */ virtual ~SendmailJob(); protected: virtual void doStart(); virtual bool doKill(); private Q_SLOTS: void sendmailExited( int, QProcess::ExitStatus ); void receivedError(); void receivedStdErr(); private: SendMailJobPrivate *const d; }; -} +} // namespace MailTransport -#endif +#endif // MAILTRANSPORT_SENDMAILJOB_H diff --git a/mailtransport/sendmailsettings.ui b/mailtransport/sendmailsettings.ui index 480f1144e..fee1cca7e 100644 --- a/mailtransport/sendmailsettings.ui +++ b/mailtransport/sendmailsettings.ui @@ -1,97 +1,43 @@ - - Volker Krause <vkrause@kde.org> + + + Volker Krause <vkrause@kde.org> SendmailSettings - - + + 0 0 400 159 - - - - - Qt::Vertical + + + + + Sendmail &Location: - - - 20 - 21 - - - - - - - - - - - - 75 - true - - - - Transport: Sendmail - - - - - - - &Location: - - + kcfg_host - - - - &Name: - - - kcfg_name - - - - - - - Choos&e... + + + + text - - - - - - - KSeparator + KUrlRequester QFrame -
kseparator.h
-
- - KPushButton - QPushButton -
kpushbutton.h
-
- - KLineEdit - QLineEdit -
klineedit.h
+
kurlrequester.h
diff --git a/mailtransport/sentbehaviourattribute.cpp b/mailtransport/sentbehaviourattribute.cpp new file mode 100644 index 000000000..42e35e7de --- /dev/null +++ b/mailtransport/sentbehaviourattribute.cpp @@ -0,0 +1,106 @@ +/* + Copyright 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 "sentbehaviourattribute.h" + +#include + +#include + +using namespace Akonadi; +using namespace MailTransport; + +class SentBehaviourAttribute::Private +{ + public: + SentBehaviour mBehaviour; + Akonadi::Collection::Id mMoveToCollection; +}; + +SentBehaviourAttribute::SentBehaviourAttribute( SentBehaviour beh, Collection::Id moveToCollection ) + : d( new Private ) +{ + d->mBehaviour = beh; + d->mMoveToCollection = moveToCollection; +} + +SentBehaviourAttribute::~SentBehaviourAttribute() +{ + delete d; +} + +SentBehaviourAttribute* SentBehaviourAttribute::clone() const +{ + return new SentBehaviourAttribute( d->mBehaviour, d->mMoveToCollection ); +} + +QByteArray SentBehaviourAttribute::type() const +{ + static const QByteArray sType( "SentBehaviourAttribute" ); + return sType; +} + +QByteArray SentBehaviourAttribute::serialized() const +{ + switch( d->mBehaviour ) { + case Delete: return "delete"; + case MoveToCollection: return "moveTo" + QByteArray::number( d->mMoveToCollection ); + case MoveToDefaultSentCollection: return "moveToDefault"; + } + + Q_ASSERT( false ); + return QByteArray(); +} + +void SentBehaviourAttribute::deserialize( const QByteArray &data ) +{ + d->mMoveToCollection = -1; + if ( data == "delete" ) { + d->mBehaviour = Delete; + } else if ( data == "moveToDefault" ) { + d->mBehaviour = MoveToDefaultSentCollection; + } else if ( data.startsWith( QByteArray( "moveTo" ) ) ) { + d->mBehaviour = MoveToCollection; + d->mMoveToCollection = data.mid(6).toLongLong(); + // NOTE: 6 is the strlen of "moveTo". + } else { + Q_ASSERT( false ); + } +} + +SentBehaviourAttribute::SentBehaviour SentBehaviourAttribute::sentBehaviour() const +{ + return d->mBehaviour; +} + +void SentBehaviourAttribute::setSentBehaviour( SentBehaviour beh ) +{ + d->mBehaviour = beh; +} + +Collection::Id SentBehaviourAttribute::moveToCollection() const +{ + return d->mMoveToCollection; +} + +void SentBehaviourAttribute::setMoveToCollection( Collection::Id moveToCollection ) +{ + d->mMoveToCollection = moveToCollection; +} + diff --git a/mailtransport/sentbehaviourattribute.h b/mailtransport/sentbehaviourattribute.h new file mode 100644 index 000000000..3f784774d --- /dev/null +++ b/mailtransport/sentbehaviourattribute.h @@ -0,0 +1,101 @@ +/* + Copyright 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 MAILTRANSPORT_SENTBEHAVIOURATTRIBUTE_H +#define MAILTRANSPORT_SENTBEHAVIOURATTRIBUTE_H + +#include + +#include +#include + +namespace MailTransport { + +/** + Attribute determining what will happen to a message after it is sent. The + message can be deleted from the Outbox, moved to the default sent-mail + collection, or moved to a custom collection. + + @author Constantin Berzan + @since 4.4 +*/ +class MAILTRANSPORT_EXPORT SentBehaviourAttribute : public Akonadi::Attribute +{ + public: + /** + What to do with the item in the outbox after it has been sent successfully. + */ + enum SentBehaviour + { + Delete, ///< Delete the item from the outbox. + MoveToCollection, ///< Move the item to the default sent-mail collection. + MoveToDefaultSentCollection ///< Move the item to a custom collection. + }; + + /** + Creates a new SentBehaviourAttribute. + */ + explicit SentBehaviourAttribute( SentBehaviour beh = MoveToDefaultSentCollection, + Akonadi::Collection::Id moveToCollection = -1 ); + + /** + Destroys the SentBehaviourAttribute. + */ + virtual ~SentBehaviourAttribute(); + + /* reimpl */ + virtual SentBehaviourAttribute* clone() const; + virtual QByteArray type() const; + virtual QByteArray serialized() const; + virtual void deserialize( const QByteArray &data ); + + /** + Returns the sent-behaviour of the message. + @see SentBehaviour. + */ + SentBehaviour sentBehaviour() const; + + /** + Sets the sent-behaviour of the message. + @see SentBehaviour. + */ + void setSentBehaviour( SentBehaviour beh ); + + /** + Returns the collection to which the item should be moved after it is sent. + Only valid if sentBehaviour() is MoveToCollection. + */ + Akonadi::Collection::Id moveToCollection() const; + + /** + Sets the collection to which the item should be moved after it is sent. + Make sure you set the SentBehaviour to MoveToCollection first. + @see setSentBehaviour. + */ + void setMoveToCollection( Akonadi::Collection::Id moveToCollection ); + + private: + class Private; + Private *const d; + +}; + +} // namespace MailTransport + +#endif // MAILTRANSPORT_SENTBEHAVIOURATTRIBUTE_H diff --git a/mailtransport/servertest.cpp b/mailtransport/servertest.cpp index 9ee3e9be8..6361ec2c5 100644 --- a/mailtransport/servertest.cpp +++ b/mailtransport/servertest.cpp @@ -1,599 +1,599 @@ /* Copyright (c) 2006 - 2007 Volker Krause Copyright (C) 2007 KovoKs Copyright (c) 2008 Thomas McGuire This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // Own #include "servertest.h" #include "socket.h" #include #include // Qt #include #include #include // KDE -#include -#include +#include +#include using namespace MailTransport; namespace MailTransport { class ServerTestPrivate { public: ServerTestPrivate( ServerTest *test ); ServerTest *const q; QString server; QString fakeHostname; QString testProtocol; MailTransport::Socket *normalSocket; MailTransport::Socket *secureSocket; QSet< int > connectionResults; QHash< int, QList > authenticationResults; QSet< ServerTest::Capability > capabilityResults; QHash< int, uint > customPorts; QTimer *normalSocketTimer; QTimer *secureSocketTimer; QTimer *progressTimer; QProgressBar *testProgress; bool secureSocketFinished; bool normalSocketFinished; bool tlsFinished; bool popSupportsTLS; int normalStage; int secureStage; int encryptionMode; void finalResult(); void handleSMTPIMAPResponse( int type, const QString &text ); void sendInitialCapabilityQuery( MailTransport::Socket *socket ); bool handlePopConversation( MailTransport::Socket *socket, int type, int stage, const QString &response, bool *shouldStartTLS ); QList< int > parseAuthenticationList( const QStringList &authentications ); // slots void slotNormalPossible(); void slotNormalNotPossible(); void slotSslPossible(); void slotSslNotPossible(); void slotTlsDone(); void slotReadNormal( const QString &text ); void slotReadSecure( const QString &text ); void slotUpdateProgress(); }; } ServerTestPrivate::ServerTestPrivate( ServerTest *test ) : q( test ), testProgress( 0 ), secureSocketFinished( false ), normalSocketFinished( false ), tlsFinished( false ) { } void ServerTestPrivate::finalResult() { if ( !secureSocketFinished || !normalSocketFinished || !tlsFinished ) { return; } kDebug() << "Modes:" << connectionResults; kDebug() << "Capabilities:" << capabilityResults; kDebug() << "Normal:" << q->normalProtocols(); kDebug() << "SSL:" << q->secureProtocols(); kDebug() << "TLS:" << q->tlsProtocols(); if ( testProgress ) { testProgress->hide(); } progressTimer->stop(); secureSocketFinished = false; normalSocketFinished = false; tlsFinished = false ; emit q->finished( connectionResults.toList() ); } QList< int > ServerTestPrivate::parseAuthenticationList( const QStringList &authentications ) { QList< int > result; for ( QStringList::ConstIterator it = authentications.begin(); it != authentications.end(); ++it ) { QString current = (*it).toUpper(); if ( current == QLatin1String( "LOGIN" ) ) { result << Transport::EnumAuthenticationType::LOGIN; } else if ( current == QLatin1String( "PLAIN" ) ) { result << Transport::EnumAuthenticationType::PLAIN; } else if ( current == QLatin1String( "CRAM-MD5" ) ) { result << Transport::EnumAuthenticationType::CRAM_MD5; } else if ( current == QLatin1String( "DIGEST-MD5" ) ) { result << Transport::EnumAuthenticationType::DIGEST_MD5; } else if ( current == QLatin1String( "NTLM" ) ) { result << Transport::EnumAuthenticationType::NTLM; } else if ( current == QLatin1String( "GSSAPI" ) ) { result << Transport::EnumAuthenticationType::GSSAPI; } else if ( current == QLatin1String( "ANONYMOUS" ) ) { result << Transport::EnumAuthenticationType::ANONYMOUS; } // APOP is handled by handlePopConversation() } kDebug() << authentications << result; // LOGIN doesn't offer anything over PLAIN, requires more server // roundtrips and is not an official SASL mechanism, but a MS-ism, // so only enable it if PLAIN isn't available: if ( result.contains( Transport::EnumAuthenticationType::PLAIN ) ) { result.removeAll( Transport::EnumAuthenticationType::LOGIN ); } return result; } void ServerTestPrivate::handleSMTPIMAPResponse( int type, const QString &text ) { if ( !text.contains( QLatin1String( "AUTH" ), Qt::CaseInsensitive ) ) { kDebug() << "No authentication possible"; return; } QStringList protocols; protocols << QLatin1String( "LOGIN" ) << QLatin1String( "PLAIN" ) << QLatin1String( "CRAM-MD5" ) << QLatin1String( "DIGEST-MD5" ) << QLatin1String( "NTLM" ) << QLatin1String( "GSSAPI" ) << QLatin1String( "ANONYMOUS" ); QStringList results; for ( int i = 0; i < protocols.count(); ++i ) { if ( text.contains( protocols.at( i ), Qt::CaseInsensitive ) ) { results.append( protocols.at( i ) ); } } authenticationResults[type] = parseAuthenticationList( results ); kDebug() << "For type" << type << ", we have:" << authenticationResults[type]; } void ServerTestPrivate::slotNormalPossible() { normalSocketTimer->stop(); connectionResults << Transport::EnumEncryption::None; } void ServerTestPrivate::sendInitialCapabilityQuery( MailTransport::Socket *socket ) { kDebug(); if ( testProtocol == IMAP_PROTOCOL ) { socket->write( QLatin1String( "1 CAPABILITY" ) ); } else if ( testProtocol == SMTP_PROTOCOL ) { // Detect the hostname which we send with the EHLO command. // If there is a fake one set, use that, otherwise use the // local host name (and make sure it contains a domain, so the // server thinks it is valid). QString hostname; if ( !fakeHostname.isNull() ) { hostname = fakeHostname; } else { hostname = QHostInfo::localHostName(); if( hostname.isEmpty() ) { hostname = QLatin1String( "localhost.invalid" ); } else if ( !hostname.contains( QChar::fromAscii( '.' ) ) ) { hostname += QLatin1String( ".localnet" ); } } kDebug() << "Hostname for EHLO is" << hostname; socket->write( QLatin1String( "EHLO " ) + hostname ); } } void ServerTestPrivate::slotTlsDone() { kDebug(); // The server will not send a response after starting TLS. Therefore, we have to manually // call slotReadNormal(), because this is not triggered by a data received signal this time. slotReadNormal( QString() ); } bool ServerTestPrivate::handlePopConversation( MailTransport::Socket *socket, int type, int stage, const QString &response, bool *shouldStartTLS ) { Q_ASSERT( shouldStartTLS != 0 ); // Initial Greeting if ( stage == 0 ) { //Regexp taken from POP3 ioslave QString responseWithoutCRLF = response; responseWithoutCRLF.chop( 2 ); QRegExp re( QLatin1String( "<[A-Za-z0-9\\.\\-_]+@[A-Za-z0-9\\.\\-_]+>$" ), Qt::CaseInsensitive ); if ( responseWithoutCRLF.indexOf( re ) != -1 ) { authenticationResults[type] << Transport::EnumAuthenticationType::APOP; } //Each server is supposed to support clear text login authenticationResults[type] << Transport::EnumAuthenticationType::CLEAR; // If we are in TLS stage, the server does not send the initial greeting. // Assume that the APOP availability is the same as with an unsecured connection. if ( type == Transport::EnumEncryption::TLS && authenticationResults[Transport::EnumEncryption::None]. contains( Transport::EnumAuthenticationType::APOP ) ) { authenticationResults[Transport::EnumEncryption::TLS] << Transport::EnumAuthenticationType::APOP; } socket->write( QLatin1String( "CAPA" ) ); return true; } // CAPA result else if( stage == 1 ) { // Example: // CAPA // +OK // TOP // USER // SASL LOGIN CRAM-MD5 // UIDL // RESP-CODES // . if ( response.contains( QLatin1String( "TOP" ) ) ) { capabilityResults += ServerTest::Top; } if ( response.contains( QLatin1String( "PIPELINING" ) ) ) { capabilityResults += ServerTest::Pipelining; } if ( response.contains( QLatin1String( "UIDL" ) ) ) { capabilityResults += ServerTest::UIDL; } if ( response.contains( QLatin1String( "STLS" ) ) ) { connectionResults << Transport::EnumEncryption::TLS; popSupportsTLS = true; } socket->write( QLatin1String( "AUTH" ) ); return true; } // AUTH response else if( stage == 2 ) { // Example: // C: AUTH // S: +OK List of supported authentication methods follows // S: LOGIN // S: CRAM-MD5 // S:. QString formattedReply = response; // Get rid of trailling ".CRLF" formattedReply.chop( 3 ); // Get rid of the first +OK line formattedReply = formattedReply.right( formattedReply.size() - formattedReply.indexOf( QLatin1Char( '\n' ) ) - 1 ); formattedReply = formattedReply.replace( QLatin1Char( ' ' ), QLatin1Char( '-' ) ). replace( QLatin1String( "\r\n" ), QLatin1String( " " ) ); authenticationResults[type] += parseAuthenticationList( formattedReply.split( QLatin1Char( ' ' ) ) ); } *shouldStartTLS = popSupportsTLS; return false; } // slotReadNormal() handles normal (no) encryption and TLS encryption. // At first, the communication is not encrypted, but if the server supports // the STARTTLS/STLS keyword, the same authentication query is done again // with TLS. void ServerTestPrivate::slotReadNormal( const QString &text ) { Q_ASSERT( encryptionMode != Transport::EnumEncryption::SSL ); static const int tlsHandshakeStage = 42; kDebug() << "Stage" << normalStage + 1 << ", Mode" << encryptionMode; // If we are in stage 42, we just do the handshake for TLS encryption and // then reset the stage to -1, so that all authentication modes and // capabilities are queried again for TLS encryption (some servers have // different authentication methods in normal and in TLS mode). if ( normalStage == tlsHandshakeStage ) { Q_ASSERT( encryptionMode == Transport::EnumEncryption::TLS ); normalStage = -1; normalSocket->startTLS(); return; } bool shouldStartTLS = false; normalStage++; // Handle the whole POP converstation separatly, it is very different from // IMAP and SMTP if ( testProtocol == POP_PROTOCOL ) { if ( handlePopConversation( normalSocket, encryptionMode, normalStage, text, &shouldStartTLS ) ) { return; } } else { // Handle the SMTP/IMAP conversation here. We just send the EHLO command in // sendInitialCapabilityQuery. if ( normalStage == 0 ) { sendInitialCapabilityQuery( normalSocket ); return; } if ( text.contains( QLatin1String( "STARTTLS" ), Qt::CaseInsensitive ) ) { connectionResults << Transport::EnumEncryption::TLS; shouldStartTLS = true; } handleSMTPIMAPResponse( encryptionMode, text ); } // If we reach here, the normal authentication/capabilities query is completed. // Now do the same for TLS. normalSocketFinished = true; // If the server announced that STARTTLS/STLS is available, we'll add TLS to the // connection result, do the command and set the stage to 42 to start the handshake. if ( shouldStartTLS && encryptionMode == Transport::EnumEncryption::None ) { kDebug() << "Trying TLS..."; connectionResults << Transport::EnumEncryption::TLS; if ( testProtocol == POP_PROTOCOL ) { normalSocket->write( QLatin1String( "STLS" ) ); } else if ( testProtocol == IMAP_PROTOCOL ) { normalSocket->write( QLatin1String( "2 STARTTLS" ) ); } else { normalSocket->write( QLatin1String( "STARTTLS" ) ); } encryptionMode = Transport::EnumEncryption::TLS; normalStage = tlsHandshakeStage; return; } // If we reach here, either the TLS authentication/capabilities query is finished // or the server does not support the STARTTLS/STLS command. tlsFinished = true; finalResult(); } void ServerTestPrivate::slotReadSecure( const QString &text ) { secureStage++; if ( testProtocol == POP_PROTOCOL ) { bool dummy; if ( handlePopConversation( secureSocket, Transport::EnumEncryption::SSL, secureStage, text, &dummy ) ) { return; } } else { if ( secureStage == 0 ) { sendInitialCapabilityQuery( secureSocket ); return; } handleSMTPIMAPResponse( Transport::EnumEncryption::SSL, text ); } secureSocketFinished = true; finalResult(); } void ServerTestPrivate::slotNormalNotPossible() { normalSocketFinished = true; tlsFinished = true; finalResult(); } void ServerTestPrivate::slotSslPossible() { secureSocketTimer->stop(); connectionResults << Transport::EnumEncryption::SSL; } void ServerTestPrivate::slotSslNotPossible() { secureSocketFinished = true; finalResult(); } void ServerTestPrivate::slotUpdateProgress() { if ( testProgress ) { testProgress->setValue( testProgress->value() + 1 ); } } //---------------------- end private class -----------------------// ServerTest::ServerTest( QWidget *parent ) : QWidget( parent ), d( new ServerTestPrivate( this ) ) { d->normalSocketTimer = new QTimer( this ); d->normalSocketTimer->setSingleShot( true ); connect( d->normalSocketTimer, SIGNAL( timeout() ), SLOT( slotNormalNotPossible() ) ); d->secureSocketTimer = new QTimer( this ); d->secureSocketTimer->setSingleShot( true ); connect( d->secureSocketTimer, SIGNAL( timeout() ), SLOT( slotSslNotPossible() ) ); d->progressTimer = new QTimer( this ); connect( d->progressTimer, SIGNAL( timeout() ), SLOT( slotUpdateProgress() ) ); } ServerTest::~ServerTest() { delete d; } void ServerTest::start() { kDebug() << d; d->connectionResults.clear(); d->authenticationResults.clear(); d->capabilityResults.clear(); d->popSupportsTLS = false; d->normalStage = -1; d->secureStage = -1; d->encryptionMode = Transport::EnumEncryption::None; if ( d->testProgress ) { d->testProgress->setMaximum( 20 ); d->testProgress->setValue( 0 ); d->testProgress->setTextVisible( true ); d->testProgress->show(); d->progressTimer->start( 1000 ); } d->normalSocket = new MailTransport::Socket( this ); d->secureSocket = new MailTransport::Socket( this ); d->normalSocket->setObjectName( QLatin1String( "normal" ) ); d->normalSocket->setServer( d->server ); d->normalSocket->setProtocol( d->testProtocol ); if ( d->testProtocol == IMAP_PROTOCOL ) { d->normalSocket->setPort( IMAP_PORT ); d->secureSocket->setPort( IMAPS_PORT ); } else if ( d->testProtocol == SMTP_PROTOCOL ) { d->normalSocket->setPort( SMTP_PORT ); d->secureSocket->setPort( SMTPS_PORT ); } else if ( d->testProtocol == POP_PROTOCOL ) { d->normalSocket->setPort( POP_PORT ); d->secureSocket->setPort( POPS_PORT ); } if ( d->customPorts.contains( Transport::EnumEncryption::None ) ) { d->normalSocket->setPort( d->customPorts.value( Transport::EnumEncryption::None ) ); } if ( d->customPorts.contains( Transport::EnumEncryption::SSL ) ) { d->secureSocket->setPort( d->customPorts.value( Transport::EnumEncryption::SSL ) ); } connect( d->normalSocket, SIGNAL(connected()), SLOT(slotNormalPossible()) ); connect( d->normalSocket, SIGNAL(failed()), SLOT(slotNormalNotPossible()) ); connect( d->normalSocket, SIGNAL(data(const QString&)), SLOT(slotReadNormal(const QString&)) ); connect( d->normalSocket, SIGNAL(tlsDone()), SLOT(slotTlsDone())); d->normalSocket->reconnect(); d->normalSocketTimer->start( 10000 ); d->secureSocket->setObjectName( QLatin1String( "secure" ) ); d->secureSocket->setServer( d->server ); d->secureSocket->setProtocol( d->testProtocol + QLatin1Char( 's' ) ); d->secureSocket->setSecure( true ); connect( d->secureSocket, SIGNAL(connected()), SLOT(slotSslPossible()) ); connect( d->secureSocket, SIGNAL(failed()), SLOT(slotSslNotPossible()) ); connect( d->secureSocket, SIGNAL(data(const QString&) ), SLOT(slotReadSecure(const QString&)) ); d->secureSocket->reconnect(); d->secureSocketTimer->start( 10000 ); } void ServerTest::setFakeHostname( const QString &fakeHostname ) { d->fakeHostname = fakeHostname; } QString ServerTest::fakeHostname() { return d->fakeHostname; } void ServerTest::setServer( const QString &server ) { d->server = server; } void ServerTest::setPort( Transport::EnumEncryption::type encryptionMode, uint port ) { Q_ASSERT( encryptionMode == Transport::EnumEncryption::None || encryptionMode == Transport::EnumEncryption::SSL ); d->customPorts.insert( encryptionMode, port ); } void ServerTest::setProgressBar( QProgressBar *pb ) { d->testProgress = pb; } void ServerTest::setProtocol( const QString &protocol ) { d->testProtocol = protocol; } QString ServerTest::protocol() { return d->testProtocol; } QString ServerTest::server() { return d->server; } int ServerTest::port( Transport::EnumEncryption::type encryptionMode ) { Q_ASSERT( encryptionMode == Transport::EnumEncryption::None || encryptionMode == Transport::EnumEncryption::SSL ); if ( d->customPorts.contains( encryptionMode ) ) { return d->customPorts.value( static_cast( encryptionMode ) ); } else { return -1; } } QProgressBar *ServerTest::progressBar() { return d->testProgress; } QList< int > ServerTest::normalProtocols() { return d->authenticationResults[TransportBase::EnumEncryption::None]; } QList< int > ServerTest::tlsProtocols() { return d->authenticationResults[TransportBase::EnumEncryption::TLS]; } QList< int > ServerTest::secureProtocols() { return d->authenticationResults[Transport::EnumEncryption::SSL]; } QList< ServerTest::Capability > ServerTest::capabilities() const { return d->capabilityResults.toList(); } #include "servertest.moc" diff --git a/mailtransport/servertest.h b/mailtransport/servertest.h index 99ef116ec..664d8660b 100644 --- a/mailtransport/servertest.h +++ b/mailtransport/servertest.h @@ -1,214 +1,214 @@ /* Copyright (C) 2007 KovoKs Copyright (c) 2008 Thomas McGuire This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 MAILTRANSPORT_SERVERTEST_H #define MAILTRANSPORT_SERVERTEST_H #include #include #include #include class QProgressBar; namespace MailTransport { class ServerTestPrivate; /** * @class ServerTest * This class can be used to test certain server to see if they support stuff. * @author Tom Albers */ class MAILTRANSPORT_EXPORT ServerTest : public QWidget { Q_OBJECT Q_PROPERTY( QString server READ server WRITE setServer ) Q_PROPERTY( QString protocol READ protocol WRITE setProtocol ) Q_PROPERTY( QProgressBar *progressBar READ progressBar WRITE setProgressBar ) public: /** * This enumeration has the special capabilities a server might * support. This covers only capabilities not related to authentication. * @since 4.1 */ enum Capability { Pipelining, ///< POP3 only. The server supports pipeplining of commands Top, ///< POP3 only. The server supports fetching only the headers UIDL ///< POP3 only. The server has support for unique identifiers }; /** * Constructor * @param parent Parent Widget */ ServerTest( QWidget *parent = 0 ); /** * Destructor */ ~ServerTest(); /** * Set the server to test. */ void setServer( const QString &server ); /** * Get the server to test. */ QString server(); /** * Set a custom port to use. * * Each encryption mode (no encryption or SSL) has a different port. * TLS uses the same port as no encryption, because TLS is invoked during * a normal session. * * If this function is never called, the default port is used, which is: * (normal first, then SSL) * SMTP: 25, 465 * POP: 110, 995 * IMAP: 143, 993 * * @param encryptionMode the port will only be used in this encryption mode. * Valid values for this are only 'None' and 'SSL'. * @param port the port to use * * @since 4.1 */ void setPort( Transport::EnumEncryption::type encryptionMode, uint port ); /** * @param encryptionMode the port of this encryption mode is returned. * Can only be 'None' and 'SSL' * * @return the port set by @ref setPort or -1 if @ref setPort() was never * called for this encryption mode. * * @since 4.1 */ int port( Transport::EnumEncryption::type encryptionMode ); /** * Sets a fake hostname for the test. This is currently only used when * testing a SMTP server; there, the command for testing the capabilities * (called EHLO) needs to have the hostname of the client included. * The user can however choose to send a fake hostname instead of the * local hostname to work around various problems. This fake hostname needs * to be set here. * * @param fakeHostname the fake hostname to send */ void setFakeHostname( const QString &fakeHostname ); /** * @return the fake hostname, as set before with @ref setFakeHostname */ QString fakeHostname(); /** * Makes @p pb the progressbar to use. This class will call show() * and hide() and will count down. It does not take ownership of * the progressbar. */ void setProgressBar( QProgressBar *pb ); /** * returns the used progressBar */ QProgressBar *progressBar(); /** * Set @p protocol the protocol to test, currently supported are * "smtp", "pop" and "imap". */ void setProtocol( const QString &protocol ); /** * returns the protocol */ QString protocol(); /** * Starts the test. Will emit finished() when done. */ void start(); /** * Get the protocols for the normal connections.. Call this only * after the finished() signals has been sent. * @return an enum of the type Transport::EnumAuthenticationType */ QList< int > normalProtocols(); /** * Get the protocols for the TLS connections. Call this only * after the finished() signals has been sent. * @return an enum of the type Transport::EnumAuthenticationType * @since 4.1 */ QList< int > tlsProtocols(); /** * Get the protocols for the SSL connections. Call this only * after the finished() signals has been sent. * @return an enum of the type Transport::EnumAuthenticationType */ QList< int > secureProtocols(); /** * Get the special capabilities of the server. * Call this only after the finished() signals has been sent. * * @return the list of special capabilities of the server. * @since 4.1 */ QList< Capability > capabilities() const; Q_SIGNALS: /** * This will be emitted when the test is done. It will contain * the values from the enum EnumEncryption which are possible. */ void finished( QList< int > ); private: Q_DECLARE_PRIVATE( ServerTest ) ServerTestPrivate *const d; Q_PRIVATE_SLOT( d, void slotNormalPossible() ) Q_PRIVATE_SLOT( d, void slotTlsDone() ) Q_PRIVATE_SLOT( d, void slotSslPossible() ) Q_PRIVATE_SLOT( d, void slotReadNormal( const QString &text ) ) Q_PRIVATE_SLOT( d, void slotReadSecure( const QString &text ) ) Q_PRIVATE_SLOT( d, void slotNormalNotPossible() ) Q_PRIVATE_SLOT( d, void slotSslNotPossible() ) Q_PRIVATE_SLOT( d, void slotUpdateProgress() ) }; -} +} // namespace MailTransport -#endif +#endif // MAILTRANSPORT_SERVERTEST_H diff --git a/mailtransport/smtpconfigwidget.cpp b/mailtransport/smtpconfigwidget.cpp new file mode 100644 index 000000000..a280fcb21 --- /dev/null +++ b/mailtransport/smtpconfigwidget.cpp @@ -0,0 +1,327 @@ +/* + Copyright (c) 2009 Constantin Berzan + + Based on MailTransport code by: + Copyright (c) 2006 - 2007 Volker Krause + Copyright (c) 2007 KovoKs + + Based on KMail code by: + Copyright (c) 2001-2002 Michael Haeckel + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; 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 "smtpconfigwidget.h" +#include "transportconfigwidget_p.h" +#include "transport.h" +#include "transportmanager.h" +#include "servertest.h" +#include "mailtransport_defs.h" + +#include "ui_smtpsettings.h" + +#include +#include + +#include + +namespace { + +// TODO: is this really necessary? +class BusyCursorHelper : public QObject +{ + public: + inline BusyCursorHelper( QObject *parent ) : QObject( parent ) + { + qApp->setOverrideCursor( Qt::BusyCursor ); + } + + inline ~BusyCursorHelper() + { + qApp->restoreOverrideCursor(); + } +}; + +} + +using namespace MailTransport; + +class MailTransport::SMTPConfigWidgetPrivate : public TransportConfigWidgetPrivate +{ + public: + Ui::SMTPSettings ui; + + ServerTest *serverTest; + QButtonGroup *encryptionGroup; + QButtonGroup *authGroup; + + // detected authentication capabilities + QList noEncCapa, sslCapa, tlsCapa; + + bool serverTestFailed; + + void resetAuthCapabilities() + { + noEncCapa.clear(); + noEncCapa << Transport::EnumAuthenticationType::LOGIN + << Transport::EnumAuthenticationType::PLAIN + << Transport::EnumAuthenticationType::CRAM_MD5 + << Transport::EnumAuthenticationType::DIGEST_MD5 + << Transport::EnumAuthenticationType::NTLM + << Transport::EnumAuthenticationType::GSSAPI; + sslCapa = tlsCapa = noEncCapa; + if ( authGroup ) { + updateAuthCapbilities(); + } + } + + void updateAuthCapbilities() + { + if ( serverTestFailed ) { + return; + } + + QList capa = noEncCapa; + if ( ui.ssl->isChecked() ) { + capa = sslCapa; + } else if ( ui.tls->isChecked() ) { + capa = tlsCapa; + } + + for ( int i = 0; i < authGroup->buttons().count(); ++i ) { + authGroup->buttons().at( i )->setEnabled( capa.contains( i ) ); + } + + if ( capa.count() == 0 ) { + ui.noAuthPossible->setVisible( true ); + ui.kcfg_requiresAuthentication->setChecked( false ); + ui.kcfg_requiresAuthentication->setEnabled( false ); + } else { + ui.noAuthPossible->setVisible( false ); + ui.kcfg_requiresAuthentication->setEnabled( true ); + } + } +}; + +SMTPConfigWidget::SMTPConfigWidget( Transport *transport, QWidget *parent ) + : TransportConfigWidget( *new SMTPConfigWidgetPrivate, transport, parent ) +{ + init(); +} + +SMTPConfigWidget::SMTPConfigWidget( SMTPConfigWidgetPrivate &dd, + Transport *transport, QWidget *parent ) + : TransportConfigWidget( dd, transport, parent ) +{ + init(); +} + +void SMTPConfigWidget::init() +{ + Q_D( SMTPConfigWidget ); + d->serverTest = 0; + + connect( TransportManager::self(), SIGNAL(passwordsChanged()), + SLOT(passwordsLoaded()) ); + + d->ui.setupUi( this ); + d->manager->addWidget( this ); // otherwise it doesn't find out about these widgets + d->manager->updateWidgets(); + + d->encryptionGroup = new QButtonGroup( this ); + d->encryptionGroup->addButton( d->ui.none ); + d->encryptionGroup->addButton( d->ui.ssl ); + d->encryptionGroup->addButton( d->ui.tls ); + + d->authGroup = new QButtonGroup( this ); + d->authGroup->addButton( d->ui.login ); + d->authGroup->addButton( d->ui.plain ); + d->authGroup->addButton( d->ui.crammd5 ); + d->authGroup->addButton( d->ui.digestmd5 ); + d->authGroup->addButton( d->ui.gssapi ); + d->authGroup->addButton( d->ui.ntlm ); + d->resetAuthCapabilities(); + + if ( KProtocolInfo::capabilities( SMTP_PROTOCOL ).contains( QLatin1String( "SASL" ) ) == 0 ) { + d->ui.ntlm->hide(); + d->ui.gssapi->hide(); + } + + connect( d->ui.checkCapabilities, SIGNAL( clicked() ), + SLOT( checkSmtpCapabilities() ) ); + connect( d->ui.kcfg_host, SIGNAL( textChanged(QString) ), + SLOT( hostNameChanged(QString) ) ); + connect( d->ui.kcfg_encryption, SIGNAL( clicked(int) ), + SLOT( encryptionChanged(int) ) ); + connect( d->ui.kcfg_requiresAuthentication, SIGNAL( toggled(bool) ), + SLOT( ensureValidAuthSelection() ) ); + + // load the password + d->transport->updatePasswordState(); + if ( d->transport->isComplete() ) { + d->ui.password->setText( d->transport->password() ); + } else { + if ( d->transport->requiresAuthentication() ) { + TransportManager::self()->loadPasswordsAsync(); + } + } + + hostNameChanged( d->transport->host() ); +} + +void SMTPConfigWidget::checkSmtpCapabilities() +{ + Q_D( SMTPConfigWidget ); + + d->serverTest = new ServerTest( this ); + d->serverTest->setProtocol( SMTP_PROTOCOL ); + d->serverTest->setServer( d->ui.kcfg_host->text().trimmed() ); + if ( d->ui.kcfg_specifyHostname->isChecked() ) { + d->serverTest->setFakeHostname( d->ui.kcfg_localHostname->text() ); + } + d->serverTest->setProgressBar( d->ui.checkCapabilitiesProgress ); + BusyCursorHelper *busyCursorHelper = new BusyCursorHelper( d->serverTest ); + + connect( d->serverTest, SIGNAL( finished( QList ) ), + SLOT(slotFinished( QList ))); + connect( d->serverTest, SIGNAL( finished( QList ) ), + busyCursorHelper, SLOT( deleteLater() ) ); + d->ui.checkCapabilities->setEnabled( false ); + d->serverTest->start(); + d->serverTestFailed = false; +} + +void SMTPConfigWidget::apply() +{ + Q_D( SMTPConfigWidget ); + + Q_ASSERT( d->manager ); + d->manager->updateSettings(); + d->transport->setPassword( d->ui.password->text() ); + + TransportConfigWidget::apply(); +} + +void SMTPConfigWidget::passwordsLoaded() +{ + Q_D( SMTPConfigWidget ); + + // Load the password from the original to our cloned copy + d->transport->updatePasswordState(); + + if ( d->ui.password->text().isEmpty() ) { + d->ui.password->setText( d->transport->password() ); + } +} + +static void checkHighestEnabledButton( QButtonGroup *group ) +{ + Q_ASSERT( group ); + + for ( int i = group->buttons().count() - 1; i >= 0; --i ) { + QAbstractButton *b = group->buttons().at( i ); + if ( b && b->isEnabled() ) { + b->animateClick(); + return; + } + } +} + +// TODO rename +void SMTPConfigWidget::slotFinished( QList results ) +{ + Q_D( SMTPConfigWidget ); + + d->ui.checkCapabilities->setEnabled( true ); + d->serverTest->deleteLater(); + + // If the servertest did not find any useable authentication modes, assume the + // connection failed and don't disable any of the radioboxes. + if ( results.isEmpty() ) { + d->serverTestFailed = true; + return; + } + + // encryption method + d->ui.none->setEnabled( results.contains( Transport::EnumEncryption::None ) ); + d->ui.ssl->setEnabled( results.contains( Transport::EnumEncryption::SSL ) ); + d->ui.tls->setEnabled( results.contains( Transport::EnumEncryption::TLS ) ); + checkHighestEnabledButton( d->encryptionGroup ); + + d->noEncCapa = d->serverTest->normalProtocols(); + if ( d->ui.tls->isEnabled() ) { + d->tlsCapa = d->serverTest->tlsProtocols(); + } else { + d->tlsCapa.clear(); + } + d->sslCapa = d->serverTest->secureProtocols(); + d->updateAuthCapbilities(); + checkHighestEnabledButton( d->authGroup ); +} + +void SMTPConfigWidget::hostNameChanged( const QString &text ) +{ + // TODO: really? is this done at every change? wtf + + Q_D( SMTPConfigWidget ); + + // sanitize hostname... + int pos = d->ui.kcfg_host->cursorPosition(); + d->ui.kcfg_host->blockSignals( true ); + d->ui.kcfg_host->setText( text.trimmed() ); + d->ui.kcfg_host->blockSignals( false ); + d->ui.kcfg_host->setCursorPosition( pos ); + + d->resetAuthCapabilities(); + for ( int i = 0; d->encryptionGroup && i < d->encryptionGroup->buttons().count(); i++ ) { + d->encryptionGroup->buttons().at( i )->setEnabled( true ); + } +} + +void SMTPConfigWidget::ensureValidAuthSelection() +{ + Q_D( SMTPConfigWidget ); + + // adjust available authentication methods + d->updateAuthCapbilities(); + foreach ( QAbstractButton *b, d->authGroup->buttons() ) { + if ( b->isChecked() && !b->isEnabled() ) { + checkHighestEnabledButton( d->authGroup ); + break; + } + } +} + +void SMTPConfigWidget::encryptionChanged( int enc ) +{ + Q_D( SMTPConfigWidget ); + kDebug() << enc; + + // adjust port + if ( enc == Transport::EnumEncryption::SSL ) { + if ( d->ui.kcfg_port->value() == SMTP_PORT ) { + d->ui.kcfg_port->setValue( SMTPS_PORT ); + } + } else { + if ( d->ui.kcfg_port->value() == SMTPS_PORT ) { + d->ui.kcfg_port->setValue( SMTP_PORT ); + } + } + + ensureValidAuthSelection(); +} + +#include "smtpconfigwidget.moc" diff --git a/mailtransport/transportconfigdialog.h b/mailtransport/smtpconfigwidget.h similarity index 58% copy from mailtransport/transportconfigdialog.h copy to mailtransport/smtpconfigwidget.h index f0cc949d6..2d0f0cc13 100644 --- a/mailtransport/transportconfigdialog.h +++ b/mailtransport/smtpconfigwidget.h @@ -1,77 +1,77 @@ /* + Copyright (c) 2009 Constantin Berzan + + Based on MailTransport code by: Copyright (c) 2006 - 2007 Volker Krause Based on KMail code by: Copyright (c) 2001-2002 Michael Haeckel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 MAILTRANSPORT_TRANSPORTCONFIGDIALOG_H -#define MAILTRANSPORT_TRANSPORTCONFIGDIALOG_H +#ifndef MAILTRANSPORT_SMTPCONFIGWIDGET_H +#define MAILTRANSPORT_SMTPCONFIGWIDGET_H -#include -#include +#include "transportconfigwidget.h" namespace MailTransport { class Transport; /** - Configuration dialog for a mail transport. + @internal +*/ +class SMTPConfigWidgetPrivate; + +/** + @internal + Configuration widget for a SMTP transport. */ -class MAILTRANSPORT_EXPORT TransportConfigDialog : public KDialog +class SMTPConfigWidget : public TransportConfigWidget { Q_OBJECT public: - /** - Creates a new mail transport configuration dialog for the given - Transport object. - @param transport The Transport object to configure. This must be a deep - copy of a Transport object or a newly created one, which hasn't been - added to the TransportManager yet. - @param parent The parent widget. - */ - explicit TransportConfigDialog( Transport *transport, QWidget *parent = 0 ); - - /** - Destroys the dialog. - */ - virtual ~TransportConfigDialog(); + explicit SMTPConfigWidget( Transport *transport, QWidget *parent = 0 ); + //virtual ~SMTPConfigWidget(); + + public Q_SLOTS: + /** reimpl */ + virtual void apply(); + + protected: + // TODO probably not needed since no one will inherit from us + SMTPConfigWidget( SMTPConfigWidgetPrivate &dd, Transport *transport, QWidget *parent ); private Q_SLOTS: void checkSmtpCapabilities(); - void chooseSendmail(); void passwordsLoaded(); - void save(); - void slotUser3(); void slotFinished( QList results ); void hostNameChanged( const QString &text ); void encryptionChanged( int enc ); void ensureValidAuthSelection(); private: - class Private; - Private *const d; + Q_DECLARE_PRIVATE( SMTPConfigWidget ) + + void init(); - Q_SIGNALS: - void sendmailClicked(); }; -} +} // namespace MailTransport -#endif +#endif // MAILTRANSPORT_SMTPCONFIGWIDGET_H diff --git a/mailtransport/smtpjob.cpp b/mailtransport/smtpjob.cpp index 8c8204be8..b5f979edb 100644 --- a/mailtransport/smtpjob.cpp +++ b/mailtransport/smtpjob.cpp @@ -1,333 +1,333 @@ /* Copyright (c) 2007 Volker Krause Based on KMail code by: Copyright (c) 1996-1998 Stefan Taferner This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 "smtpjob.h" #include "transport.h" #include "mailtransport_defs.h" #include "precommandjob.h" -#include -#include -#include -#include -#include - #include #include +#include +#include +#include +#include +#include + using namespace MailTransport; class SlavePool { public: SlavePool() : ref( 0 ) {} int ref; QHash slaves; void removeSlave( KIO::Slave *slave, bool disconnect = false ) { kDebug() << "Removing slave" << slave << "from pool"; const int slaveKey = slaves.key( slave ); if ( slaveKey > 0 ) { slaves.remove( slaveKey ); if ( disconnect ) { KIO::Scheduler::disconnectSlave( slave ); } } } }; K_GLOBAL_STATIC( SlavePool, s_slavePool ) /** * Private class that helps to provide binary compatibility between releases. * @internal */ class SmtpJobPrivate { public: KIO::Slave *slave; enum State { Idle, Precommand, Smtp } currentState; bool finished; }; SmtpJob::SmtpJob( Transport *transport, QObject *parent ) : TransportJob( transport, parent ), d( new SmtpJobPrivate ) { d->currentState = SmtpJobPrivate::Idle; d->slave = 0; d->finished = false; if ( !s_slavePool.isDestroyed() ) { s_slavePool->ref++; } KIO::Scheduler::connect( SIGNAL(slaveError(KIO::Slave*,int,QString)), this, SLOT(slaveError(KIO::Slave*,int,QString)) ); } SmtpJob::~SmtpJob() { if ( !s_slavePool.isDestroyed() ) { s_slavePool->ref--; if ( s_slavePool->ref == 0 ) { kDebug() << "clearing SMTP slave pool" << s_slavePool->slaves.count(); foreach ( KIO::Slave *slave, s_slavePool->slaves ) { if ( slave ) { KIO::Scheduler::disconnectSlave( slave ); } } s_slavePool->slaves.clear(); } } delete d; } void SmtpJob::doStart() { if ( s_slavePool.isDestroyed() ) { return; } if ( s_slavePool->slaves.contains( transport()->id() ) || transport()->precommand().isEmpty() ) { d->currentState = SmtpJobPrivate::Smtp; startSmtpJob(); } else { d->currentState = SmtpJobPrivate::Precommand; PrecommandJob *job = new PrecommandJob( transport()->precommand(), this ); addSubjob( job ); job->start(); } } void SmtpJob::startSmtpJob() { if ( s_slavePool.isDestroyed() ) { return; } KUrl destination; destination.setProtocol( ( transport()->encryption() == Transport::EnumEncryption::SSL ) ? SMTPS_PROTOCOL : SMTP_PROTOCOL ); destination.setHost( transport()->host().trimmed() ); destination.setPort( transport()->port() ); destination.addQueryItem( QLatin1String( "headers" ), QLatin1String( "0" ) ); destination.addQueryItem( QLatin1String( "from" ), sender() ); foreach ( const QString &str, to() ) { destination.addQueryItem( QLatin1String( "to" ), str ); } foreach ( const QString &str, cc() ) { destination.addQueryItem( QLatin1String( "cc" ), str ); } foreach ( const QString &str, bcc() ) { destination.addQueryItem( QLatin1String( "bcc" ), str ); } if ( transport()->specifyHostname() ) { destination.addQueryItem( QLatin1String( "hostname" ), transport()->localHostname() ); } #ifdef __GNUC__ #warning Argh! #endif // if ( !kmkernel->msgSender()->sendQuotedPrintable() ) // query += "&body=8bit"; if ( transport()->requiresAuthentication() ) { if( ( transport()->userName().isEmpty() || transport()->password().isEmpty() ) && transport()->authenticationType() != Transport::EnumAuthenticationType::GSSAPI ) { QString user = transport()->userName(); QString passwd = transport()->password(); int result; #ifdef __GNUC__ #warning yet another KMail specific thing #endif // KCursorSaver idle( KBusyPtr::idle() ); bool keep = transport()->storePassword(); result = KIO::PasswordDialog::getNameAndPassword( user, passwd, &keep, i18n( "You need to supply a username and a password to use this SMTP server." ), false, QString(), transport()->name(), QString() ); if ( result != QDialog::Accepted ) { setError( KilledJobError ); emitResult(); return; } transport()->setUserName( user ); transport()->setPassword( passwd ); transport()->setStorePassword( keep ); transport()->writeConfig(); } destination.setUser( transport()->userName() ); destination.setPass( transport()->password() ); } // dotstuffing is now done by the slave (see setting of metadata) if ( !data().isEmpty() ) { // allow +5% for subsequent LF->CRLF and dotstuffing (an average // over 2G-lines gives an average line length of 42-43): destination.addQueryItem( QLatin1String( "size" ), QString::number( qRound( data().length() * 1.05 ) ) ); } destination.setPath( QLatin1String( "/send" ) ); d->slave = s_slavePool->slaves.value( transport()->id() ); if ( !d->slave ) { KIO::MetaData slaveConfig; slaveConfig.insert( QLatin1String( "tls" ), ( transport()->encryption() == Transport::EnumEncryption::TLS ) ? QLatin1String( "on" ) : QLatin1String( "off" ) ); if ( transport()->requiresAuthentication() ) { slaveConfig.insert( QLatin1String( "sasl" ), transport()->authenticationTypeString() ); } d->slave = KIO::Scheduler::getConnectedSlave( destination, slaveConfig ); kDebug() << "Created new SMTP slave" << d->slave; s_slavePool->slaves.insert( transport()->id(), d->slave ); } else { kDebug() << "Re-using existing slave" << d->slave; } KIO::TransferJob *job = KIO::put( destination, -1, KIO::HideProgressInfo ); if ( !d->slave || !job ) { setError( UserDefinedError ); setErrorText( i18n( "Unable to create SMTP job." ) ); emitResult(); return; } job->addMetaData( QLatin1String( "lf2crlf+dotstuff" ), QLatin1String( "slave" ) ); connect( job, SIGNAL(dataReq(KIO::Job*,QByteArray&)), SLOT(dataRequest(KIO::Job*,QByteArray&)) ); addSubjob( job ); KIO::Scheduler::assignJobToSlave( d->slave, job ); setTotalAmount( KJob::Bytes, data().length() ); } bool SmtpJob::doKill() { if ( s_slavePool.isDestroyed() ) { return false; } if ( !hasSubjobs() ) { return true; } if ( d->currentState == SmtpJobPrivate::Precommand ) { return subjobs().first()->kill(); } else if ( d->currentState == SmtpJobPrivate::Smtp ) { KIO::SimpleJob *job = static_cast( subjobs().first() ); clearSubjobs(); KIO::Scheduler::cancelJob( job ); s_slavePool->removeSlave( d->slave ); return true; } return false; } void SmtpJob::slotResult( KJob *job ) { if ( s_slavePool.isDestroyed() ) { return; } // The job has finished, so we don't care about any further errors. Set // d->finished to true, so slaveError() knows about this and doesn't call // emitResult() anymore. // Sometimes, the SMTP slave emits more than one error // // The first error causes slotResult() to be called, but not slaveError(), since // the scheduler doesn't emit errors for connected slaves. // // The second error then causes slaveError() to be called (as the slave is no // longer connected), which does emitResult() a second time, which is invalid // (and triggers an assert in KMail). d->finished = true; // Normally, calling TransportJob::slotResult() whould set the proper error code // for error() via KComposite::slotResult(). However, we can't call that here, // since that also emits the result signal. // In KMail, when there are multiple mails in the outbox, KMail tries to send // the next mail when it gets the result signal, which then would reuse the // old broken slave from the slave pool if there was an error. // To prevent that, we call TransportJob::slotResult() only after removing the // slave from the pool and calculate the error code ourselves. int errorCode = error(); if ( !errorCode ) { errorCode = job->error(); } if ( errorCode && d->currentState == SmtpJobPrivate::Smtp ) { s_slavePool->removeSlave( d->slave, errorCode != KIO::ERR_SLAVE_DIED ); TransportJob::slotResult( job ); return; } TransportJob::slotResult( job ); if ( !error() && d->currentState == SmtpJobPrivate::Precommand ) { d->currentState = SmtpJobPrivate::Smtp; startSmtpJob(); return; } if ( !error() ) { emitResult(); } } void SmtpJob::dataRequest( KIO::Job *job, QByteArray &data ) { if ( s_slavePool.isDestroyed() ) { return; } Q_ASSERT( job ); if ( buffer()->atEnd() ) { data.clear(); } else { Q_ASSERT( buffer()->isOpen() ); data = buffer()->read( 32 * 1024 ); } setProcessedAmount( KJob::Bytes, buffer()->pos() ); } void SmtpJob::slaveError( KIO::Slave *slave, int errorCode, const QString &errorMsg ) { if ( s_slavePool.isDestroyed() ) { return; } s_slavePool->removeSlave( slave, errorCode != KIO::ERR_SLAVE_DIED ); if ( d->slave == slave && !d->finished ) { setError( errorCode ); setErrorText( KIO::buildErrorString( errorCode, errorMsg ) ); emitResult(); } } #include "smtpjob.moc" diff --git a/mailtransport/smtpjob.h b/mailtransport/smtpjob.h index d6eacd508..f4c6e4e5b 100644 --- a/mailtransport/smtpjob.h +++ b/mailtransport/smtpjob.h @@ -1,83 +1,85 @@ /* Copyright (c) 2007 Volker Krause Based on KMail code by: Copyright (c) 1996-1998 Stefan Taferner This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 MAILTRANSPORT_SMTPJOB_H #define MAILTRANSPORT_SMTPJOB_H #include namespace KIO { -class Job; -class Slave; + class Job; + class Slave; } class SmtpJobPrivate; namespace MailTransport { /** Mail transport job for SMTP. Internally, all jobs for a specific transport are queued to use the same KIO::Slave. This avoids multiple simultaneous connections to the server, which is not always allowed. Also, re-using an already existing connection avoids the login overhead and can improve performance. Precommands are automatically executed, once per opening a connection to the server (not necessarily once per message). + + @deprecated Use MessageQueueJob for sending e-mail. */ -class MAILTRANSPORT_EXPORT SmtpJob : public TransportJob +class MAILTRANSPORT_EXPORT_DEPRECATED SmtpJob : public TransportJob { Q_OBJECT public: /** - Creates a SendmailJob. + Creates a SmtpJob. @param transport The transport settings. @param parent The parent object. */ explicit SmtpJob( Transport *transport, QObject *parent = 0 ); /** Deletes this job. */ virtual ~SmtpJob(); protected: virtual void doStart(); virtual bool doKill(); protected Q_SLOTS: virtual void slotResult( KJob *job ); void slaveError( KIO::Slave *slave, int errorCode, const QString &errorMsg ); private: void startSmtpJob(); private Q_SLOTS: void dataRequest( KIO::Job *job, QByteArray &data ); private: SmtpJobPrivate *const d; }; -} +} // namespace MailTransport -#endif +#endif // MAILTRANSPORT_SMTPJOB_H diff --git a/mailtransport/smtpsettings.ui b/mailtransport/smtpsettings.ui index cd6140c1a..fcbaadb7a 100644 --- a/mailtransport/smtpsettings.ui +++ b/mailtransport/smtpsettings.ui @@ -1,574 +1,513 @@ Volker Krause <vkrause@kde.org>, KovoKs <tomalbers@kde.nl> SMTPSettings 0 0 - 524 - 509 + 362 + 438 - - - - 75 - true - - - - Transport: SMTP - - - - - - - 0 General - - - - - &Name: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - kcfg_name - - - - - - - - - - Outgoing mail &server: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Outgoing mail &server: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + kcfg_host + + + + + + + + + + &Port: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + kcfg_port + + + + + + + + + 25 - - kcfg_host + + 1 - - - - - - - &Port: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + Qt::Horizontal - - kcfg_port + + + 231 + 23 + - - - - - - - - 25 - - - 1 - - - - - - - Qt::Horizontal - - - - 231 - 23 - - - - - + - - - - - - Encryption - - + + + + Encryption + + + + - - - - - &None - - - - - - - &SSL - - - - - - - &TLS - - - - + + + &None + + - + - Check &What the Server Supports + &SSL - - - false + + + &TLS - - - - - - Qt::Horizontal - - - - 166 - 81 - - - - - + + + + + Check &What the Server Supports + + + + + + + false + + + + + Advanced - - - - + + + + + Server &requires authentication + + + + + + false - - QFrame::Box + + &Login: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + kcfg_userName + + + + + + + false - - QFrame::Raised + + + + + + false - This server does not support authentication + P&assword: - Qt::AlignCenter + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + password - - + + + + false + + + The password to send to the server for authorization. + + + QLineEdit::Password + + + + + + + false + - Server &requires authentication + &Store SMTP password - - - - - - false - - - &Login: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - kcfg_userName - - - - - - - false - - - - - - - false - - - P&assword: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - password - - - - - - - false - - - The password to send to the server for authorization. - - - QLineEdit::Password - - - - - - - false - - - &Store SMTP password - - - - - - - false - - - Authentication Method - + + + + false + + + Authentication Method + + + - - - - - &LOGIN - - - - - - - &PLAIN - - - - - - - CRAM-MD&5 - - - - - - - &DIGEST-MD5 - - - - - - - &GSSAPI - - - - - - - &NTLM - - - - + + + &LOGIN + + + + + + + &PLAIN + + + + + + + CRAM-MD&5 + + + + + + + &DIGEST-MD5 + + + + + + + &GSSAPI + + + + + + + &NTLM + + - - - + + + - + - + Sen&d custom hostname to server - - - - - - false - - - Hos&tname: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - kcfg_localHostname - - - - - - - false - - - - + + + + false + + + Hos&tname: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + kcfg_localHostname + + + + + + + false + + - + - - - - - - Precommand: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - + + + + Precommand: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + 0 + 0 + 100 + 30 + + + + false + + + QFrame::Box + + + QFrame::Raised + + + This server does not support authentication + + + Qt::AlignCenter + + KButtonGroup QGroupBox
kbuttongroup.h
1
KPushButton QPushButton
kpushbutton.h
KLineEdit QLineEdit
klineedit.h
1
KTabWidget QTabWidget
ktabwidget.h
1
KIntNumInput QWidget
knuminput.h
KSeparator QFrame
kseparator.h
1
- tabWidget - kcfg_name kcfg_host kcfg_requiresAuthentication toggled(bool) usernameLabel setEnabled(bool) 29 88 112 117 kcfg_requiresAuthentication toggled(bool) kcfg_userName setEnabled(bool) 35 85 186 115 kcfg_requiresAuthentication toggled(bool) passwordLabel setEnabled(bool) 49 88 61 142 kcfg_requiresAuthentication toggled(bool) password setEnabled(bool) 43 89 140 142 kcfg_requiresAuthentication toggled(bool) kcfg_storePassword setEnabled(bool) 75 86 62 176 kcfg_requiresAuthentication toggled(bool) kcfg_authenticationType setEnabled(bool) 82 89 78 202 kcfg_specifyHostname toggled(bool) hostnameLabel setEnabled(bool) 90 334 81 357 kcfg_specifyHostname toggled(bool) kcfg_localHostname setEnabled(bool) 185 327 179 360
diff --git a/mailtransport/socket.cpp b/mailtransport/socket.cpp index 0bfa84d2c..f42dacb7e 100644 --- a/mailtransport/socket.cpp +++ b/mailtransport/socket.cpp @@ -1,228 +1,228 @@ /* Copyright (C) 2006-2007 KovoKs This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // Uncomment the next line for full comm debug // #define comm_debug // Own #include "socket.h" // Qt #include #include #include // KDE -#include +#include +#include #include -#include using namespace MailTransport; namespace MailTransport { class SocketPrivate { public: SocketPrivate( Socket *s ); Socket *const q; QSslSocket *socket; QString server; QString protocol; int port; bool secure; // slots void slotConnected(); void slotStateChanged( QAbstractSocket::SocketState state ); void slotModeChanged( QSslSocket::SslMode state ); void slotSocketRead(); void slotSslErrors( const QList &errors ); private: QString m_msg; }; } SocketPrivate::SocketPrivate( Socket *s ) : q( s ) { } void SocketPrivate::slotConnected() { kDebug() ; if ( !secure ) { kDebug() << "normal connect"; emit q->connected(); } else { kDebug() << "encrypted connect"; socket->startClientEncryption(); } } void SocketPrivate::slotStateChanged( QAbstractSocket::SocketState state ) { #ifdef comm_debug kDebug() << "State is now:" << ( int ) state; #endif if ( state == QAbstractSocket::UnconnectedState ) { emit q->failed(); } } void SocketPrivate::slotModeChanged( QSslSocket::SslMode state ) { #ifdef comm_debug kDebug() << "Mode is now:" << state; #endif if ( state == QSslSocket::SslClientMode ) { emit q->tlsDone(); } } void SocketPrivate::slotSocketRead() { kDebug(); if ( !socket ) { return; } m_msg += QLatin1String( socket->readAll() ); if ( !m_msg.endsWith( QLatin1Char( '\n' ) ) ) { return; } #ifdef comm_debug kDebug() << socket->isEncrypted() << m_msg.trimmed(); #endif emit q->data( m_msg ); m_msg.clear(); } void SocketPrivate::slotSslErrors( const QList & ) { kDebug(); /* We can safely ignore the errors, we are only interested in the capabilities. We're not sending auth info. */ socket->ignoreSslErrors(); emit q->connected(); } // ------------------ end private ---------------------------// Socket::Socket( QObject *parent ) : QObject( parent ), d( new SocketPrivate( this ) ) { d->socket = 0; d->port = 0; d->secure = false; kDebug(); } Socket::~Socket() { kDebug(); delete d; } void Socket::reconnect() { kDebug() << "Connecting to:" << d->server << ":" << d->port; #ifdef comm_debug // kDebug() << d->protocol; #endif if ( d->socket ) { return; } d->socket = static_cast( KSocketFactory::connectToHost( d->protocol, d->server, d->port, this ) ); d->socket->setProtocol( QSsl::AnyProtocol ); connect( d->socket, SIGNAL( stateChanged( QAbstractSocket::SocketState ) ), SLOT( slotStateChanged( QAbstractSocket::SocketState ) ) ); connect( d->socket, SIGNAL( modeChanged( QSslSocket::SslMode ) ), SLOT( slotModeChanged( QSslSocket::SslMode ) ) ); connect( d->socket, SIGNAL( connected() ), SLOT( slotConnected() ) ); connect( d->socket, SIGNAL( readyRead() ), SLOT( slotSocketRead() ) ); connect( d->socket, SIGNAL( encrypted() ), SIGNAL( connected() ) ); connect( d->socket, SIGNAL( sslErrors( const QList & ) ), SLOT( slotSslErrors( const QList& ) ) ); } void Socket::write( const QString &text ) { // kDebug(); // Eat things in the queue when there is no connection. We need // to get a connection first don't we... if ( !d->socket || !available() ) { return; } QByteArray cs = ( text + QLatin1String( "\r\n" ) ).toLatin1(); #ifdef comm_debug kDebug() << "C :" << cs; #endif d->socket->write( cs.data(), cs.size() ); } bool Socket::available() { // kDebug(); bool ok = d->socket && d->socket->state() == QAbstractSocket::ConnectedState; return ok; } void Socket::startTLS() { kDebug() << objectName(); d->socket->setProtocol( QSsl::TlsV1 ); d->socket->startClientEncryption(); } void Socket::setProtocol( const QString &proto ) { d->protocol = proto; } void Socket::setServer( const QString &server ) { d->server = server; } void Socket::setPort( int port ) { d->port = port; } void Socket::setSecure( bool what ) { d->secure = what; } #include "socket.moc" diff --git a/mailtransport/socket.h b/mailtransport/socket.h index f6b16dcd5..4ef03bbd7 100644 --- a/mailtransport/socket.h +++ b/mailtransport/socket.h @@ -1,131 +1,131 @@ /* Copyright (C) 2006-2007 KovoKs This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 MAILTRANSPORT_SOCKET_H #define MAILTRANSPORT_SOCKET_H #include -#include +#include namespace MailTransport { class SocketPrivate; /** * @class Socket * Responsible for communicating with the server, it's designed to work * with the ServerTest class. * @author Tom Albers */ class MAILTRANSPORT_EXPORT Socket : public QObject { Q_OBJECT public: /** * Contructor, it will not auto connect. Call reconnect() to connect to * the parameters given. * @param parent the parent */ explicit Socket( QObject *parent ); /** * Destructor */ ~Socket(); /** * Existing connection will be closed and a new connection will be * made */ virtual void reconnect(); /** * Write @p text to the socket */ virtual void write( const QString &text ); /** * @return true when the connection is live and kicking */ virtual bool available(); /** * set the protocol to use */ void setProtocol( const QString &proto ); /** * set the server to use */ void setServer( const QString &server ); /** * set the port to use. If not specified, it will use the default * belonging to the protocol. */ void setPort( int port ); /** * this will be a secure connection */ void setSecure( bool what ); /** * If you want to start TLS encryption, call this. For example after the starttls command. */ void startTLS(); private: Q_DECLARE_PRIVATE( Socket ) SocketPrivate *const d; Q_PRIVATE_SLOT( d, void slotConnected() ) Q_PRIVATE_SLOT( d, void slotStateChanged( QAbstractSocket::SocketState state ) ) Q_PRIVATE_SLOT( d, void slotModeChanged( QSslSocket::SslMode state ) ) Q_PRIVATE_SLOT( d, void slotSocketRead() ) Q_PRIVATE_SLOT( d, void slotSslErrors( const QList &errors ) ) Q_SIGNALS: /** * emits the incoming data */ void data( const QString & ); /** * emitted when there is a connection (ready to send something). */ void connected(); /** * emitted when not connected. */ void failed(); /** * emitted when startShake() is completed. */ void tlsDone(); }; -} +} // namespace MailTransport -#endif +#endif // MAILTRANSPORT_SOCKET_H diff --git a/mailtransport/tests/CMakeLists.txt b/mailtransport/tests/CMakeLists.txt index 5660e72f7..60b94bb3d 100644 --- a/mailtransport/tests/CMakeLists.txt +++ b/mailtransport/tests/CMakeLists.txt @@ -1,6 +1,64 @@ set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) +macro(add_akonadi_isolated_test _source) + get_filename_component(_targetName ${_source} NAME_WE) + set(_srcList ${_source} ) + + kde4_add_executable(${_targetName} TEST ${_srcList}) + target_link_libraries(${_targetName} + ${QT_QTTEST_LIBRARY} + ${QT_QTGUI_LIBRARY} + ${KDE4_AKONADI_LIBS} + ${KDE4_AKONADI_KMIME_LIBS} + ${KDE4_KDECORE_LIBS} + mailtransport + ${KDE4_KMIME_LIBS} + ${QT_QTCORE_LIBRARY} + ${QT_QTDBUS_LIBRARY} + ) + + # based on kde4_add_unit_test + if (WIN32) + get_target_property( _loc ${_targetName} LOCATION ) + set(_executable ${_loc}.bat) + else (WIN32) + set(_executable ${EXECUTABLE_OUTPUT_PATH}/${_targetName}) + endif (WIN32) + if (UNIX) + set(_executable ${_executable}.shell) + endif (UNIX) + + find_program(_testrunner akonaditest) + + add_test( mailtransport-${_targetName} ${_testrunner} -c ${CMAKE_CURRENT_SOURCE_DIR}/unittestenv/config.xml ${_executable} ) +endmacro(add_akonadi_isolated_test) + + + +# Independent executables: + set(tm_srcs transportmgr.cpp) kde4_add_executable(transportmgr TEST ${tm_srcs}) target_link_libraries(transportmgr ${KDE4_KDEUI_LIBS} mailtransport) +set(queuer_srcs queuer.cpp) +kde4_add_executable(queuer TEST ${queuer_srcs}) +target_link_libraries(queuer ${KDE4_KDEUI_LIBS} ${KDE4_MAILTRANSPORT_LIBS} ${KDE4_KMIME_LIBS} mailtransport) + +set( sendqueued_srcs sendqueued.cpp ) +kde4_add_executable( sendqueued TEST ${sendqueued_srcs} ) +target_link_libraries( sendqueued mailtransport ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY}) + +set( clearerror_srcs clearerror.cpp ) +kde4_add_executable( clearerror TEST ${clearerror_srcs} ) +target_link_libraries( clearerror mailtransport ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY}) + +set( abort_srcs abort.cpp ) +kde4_add_executable( abort TEST ${abort_srcs} ) +target_link_libraries( abort mailtransport ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY}) + + +# Akonadi testrunner-based tests: + +add_akonadi_isolated_test( attributetest.cpp ) +add_akonadi_isolated_test( messagequeuejobtest.cpp ) diff --git a/mailtransport/tests/TODO b/mailtransport/tests/TODO new file mode 100644 index 000000000..37f78b4b7 --- /dev/null +++ b/mailtransport/tests/TODO @@ -0,0 +1,6 @@ +MessageQueueJob: +- see source + +Attributes: +- add test for common mistakes such as forgetting to setDueDate + diff --git a/mailtransport/tests/abort.cpp b/mailtransport/tests/abort.cpp new file mode 100644 index 000000000..dba6e2a63 --- /dev/null +++ b/mailtransport/tests/abort.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 "abort.h" + +#include + +#include +#include +#include + +#include + +#include + +using namespace Akonadi; +using namespace MailTransport; + + +Runner::Runner() +{ + Control::start(); + + QTimer::singleShot( 0, this, SLOT(sendAbort()) ); +} + +void Runner::sendAbort() +{ + const AgentInstance mda = DispatcherInterface::self()->dispatcherInstance(); + if( !mda.isValid() ) { + kDebug() << "Invalid instance; waiting."; + QTimer::singleShot( 1000, this, SLOT(sendAbort()) ); + return; + } + + mda.abort(); + kDebug() << "Told the MDA to abort."; + KApplication::exit( 0 ); +} + +int main( int argc, char **argv ) +{ + KCmdLineArgs::init( argc, argv, "abort", 0, + ki18n( "abort" ), "0", + ki18n( "An app that sends an abort signal to the MDA" ) ); + KApplication app; + new Runner(); + return app.exec(); +} + + +#include "abort.moc" diff --git a/mailtransport/configmodule.h b/mailtransport/tests/abort.h similarity index 68% copy from mailtransport/configmodule.h copy to mailtransport/tests/abort.h index 6994d37bd..82037c054 100644 --- a/mailtransport/configmodule.h +++ b/mailtransport/tests/abort.h @@ -1,39 +1,43 @@ /* - Copyright (c) 2007 Volker Krause + 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 MAILTRANSPORT_CONFIGMODULE_H -#define MAILTRANSPORT_CONFIGMODULE_H +#ifndef ABORT_H +#define ABORT_H -#include +#include -namespace MailTransport { +class KJob; /** - KCModule for transport management. + This class uses the DispatcherInterface to send an abort() signal th the MDA. */ -class ConfigModule : public KCModule +class Runner : public QObject { + Q_OBJECT + public: - explicit ConfigModule( QWidget *parent = 0, - const QVariantList &args = QVariantList() ); + Runner(); + + private slots: + void sendAbort(); + }; -} #endif diff --git a/mailtransport/tests/attributetest.cpp b/mailtransport/tests/attributetest.cpp new file mode 100644 index 000000000..a1c29e59c --- /dev/null +++ b/mailtransport/tests/attributetest.cpp @@ -0,0 +1,139 @@ +/* + Copyright 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 "attributetest.h" + +#include +#include +#include + +#include +#include +#include +#include + +using namespace Akonadi; +using namespace MailTransport; + +void AttributeTest::initTestCase() +{ +} + +void AttributeTest::testRegistrar() +{ + // The attributes should have been registered without any effort on our part. + { + Attribute *a = AttributeFactory::createAttribute( "AddressAttribute" ); + QVERIFY( dynamic_cast( a ) ); + } + + { + Attribute *a = AttributeFactory::createAttribute( "DispatchModeAttribute" ); + QVERIFY( dynamic_cast( a ) ); + } + + { + Attribute *a = AttributeFactory::createAttribute( "ErrorAttribute" ); + QVERIFY( dynamic_cast( a ) ); + } + + { + Attribute *a = AttributeFactory::createAttribute( "SentBehaviourAttribute" ); + QVERIFY( dynamic_cast( a ) ); + } + + { + Attribute *a = AttributeFactory::createAttribute( "TransportAttribute" ); + QVERIFY( dynamic_cast( a ) ); + } +} + +void AttributeTest::testSerialization() +{ + { + QString from( "from@me.org" ); + QStringList to( "to1@me.org" ); + to << "to2@me.org"; + QStringList cc( "cc1@me.org" ); + cc << "cc2@me.org"; + QStringList bcc( "bcc1@me.org" ); + bcc << "bcc2@me.org"; + AddressAttribute *a = new AddressAttribute( from, to, cc, bcc ); + QByteArray data = a->serialized(); + delete a; + a = new AddressAttribute; + a->deserialize( data ); + QCOMPARE( from, a->from() ); + QCOMPARE( to, a->to() ); + QCOMPARE( cc, a->cc() ); + QCOMPARE( bcc, a->bcc() ); + } + + { + DispatchModeAttribute::DispatchMode mode = DispatchModeAttribute::AfterDueDate; + QDateTime date = QDateTime::currentDateTime(); + // The serializer does not keep track of milliseconds, so forget them. + kDebug() << "ms" << date.toString( "z" ); + int ms = date.toString( "z" ).toInt(); + date = date.addMSecs( -ms ); + DispatchModeAttribute *a = new DispatchModeAttribute( mode, date ); + QByteArray data = a->serialized(); + delete a; + a = new DispatchModeAttribute; + a->deserialize( data ); + QCOMPARE( mode, a->dispatchMode() ); + QCOMPARE( date, a->dueDate() ); + } + + { + QString msg( "The #!@$ing thing failed!" ); + ErrorAttribute *a = new ErrorAttribute( msg ); + QByteArray data = a->serialized(); + delete a; + a = new ErrorAttribute; + a->deserialize( data ); + QCOMPARE( msg, a->message() ); + } + + { + SentBehaviourAttribute::SentBehaviour beh = SentBehaviourAttribute::MoveToCollection; + Collection::Id id = 123456789012345ll; + SentBehaviourAttribute *a = new SentBehaviourAttribute( beh, id ); + QByteArray data = a->serialized(); + delete a; + a = new SentBehaviourAttribute; + a->deserialize( data ); + QCOMPARE( beh, a->sentBehaviour() ); + QCOMPARE( id, a->moveToCollection() ); + } + + { + int id = 3219; + TransportAttribute *a = new TransportAttribute( id ); + QByteArray data = a->serialized(); + delete a; + a = new TransportAttribute; + a->deserialize( data ); + QCOMPARE( id, a->transportId() ); + } +} + +QTEST_AKONADIMAIN( AttributeTest, NoGUI ) + +#include "attributetest.moc" diff --git a/mailtransport/configmodule.h b/mailtransport/tests/attributetest.h similarity index 67% copy from mailtransport/configmodule.h copy to mailtransport/tests/attributetest.h index 6994d37bd..0760b38b3 100644 --- a/mailtransport/configmodule.h +++ b/mailtransport/tests/attributetest.h @@ -1,39 +1,39 @@ /* - Copyright (c) 2007 Volker Krause + Copyright 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 MAILTRANSPORT_CONFIGMODULE_H -#define MAILTRANSPORT_CONFIGMODULE_H +#ifndef ATTRIBUTETEST_H +#define ATTRIBUTETEST_H -#include - -namespace MailTransport { +#include /** - KCModule for transport management. + This is a test of the various attributes. */ -class ConfigModule : public KCModule +class AttributeTest : public QObject { - public: - explicit ConfigModule( QWidget *parent = 0, - const QVariantList &args = QVariantList() ); -}; + Q_OBJECT -} + private Q_SLOTS: + void initTestCase(); + void testRegistrar(); + void testSerialization(); + +}; #endif diff --git a/mailtransport/tests/clearerror.cpp b/mailtransport/tests/clearerror.cpp new file mode 100644 index 000000000..9165fc0b9 --- /dev/null +++ b/mailtransport/tests/clearerror.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 "clearerror.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +using namespace Akonadi; +using namespace MailTransport; + + +Runner::Runner() +{ + Control::start(); + + connect( LocalFolders::self(), SIGNAL( foldersReady() ), + this, SLOT( checkFolders() ) ); + LocalFolders::self()->fetch(); +} + +void Runner::checkFolders() +{ + Collection outbox = LocalFolders::self()->outbox(); + kDebug() << "Got outbox" << outbox.id(); + + if( !outbox.isValid() ) { + KApplication::exit( 1 ); + } + + FilterActionJob *fjob = new FilterActionJob( outbox, new ClearErrorAction, this ); + connect( fjob, SIGNAL(result(KJob*)), this, SLOT(jobResult(KJob*)) ); +} + +void Runner::jobResult( KJob *job ) +{ + if( job->error() ) { + kDebug() << "Job error:" << job->errorString(); + KApplication::exit( 2 ); + } else { + kDebug() << "Job success."; + KApplication::exit( 0 ); + } +} + +int main( int argc, char **argv ) +{ + KCmdLineArgs::init( argc, argv, "clearerror", 0, + ki18n( "clearerror" ), "0", + ki18n( "An app that re-queues failed items from the outbox" ) ); + KApplication app; + new Runner(); + return app.exec(); +} + + +#include "clearerror.moc" diff --git a/mailtransport/configmodule.h b/mailtransport/tests/clearerror.h similarity index 68% copy from mailtransport/configmodule.h copy to mailtransport/tests/clearerror.h index 6994d37bd..2f319c2c5 100644 --- a/mailtransport/configmodule.h +++ b/mailtransport/tests/clearerror.h @@ -1,39 +1,45 @@ /* - Copyright (c) 2007 Volker Krause + 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 MAILTRANSPORT_CONFIGMODULE_H -#define MAILTRANSPORT_CONFIGMODULE_H +#ifndef CLEARERROR_H +#define CLEARERROR_H -#include +#include -namespace MailTransport { +class KJob; /** - KCModule for transport management. + This class uses the ClearErrorAction to mark all failed messages in the + outbox for immediate sending. */ -class ConfigModule : public KCModule +class Runner : public QObject { + Q_OBJECT + public: - explicit ConfigModule( QWidget *parent = 0, - const QVariantList &args = QVariantList() ); + Runner(); + + private slots: + void checkFolders(); + void jobResult( KJob *job ); + }; -} #endif diff --git a/mailtransport/tests/messagequeuejobtest.cpp b/mailtransport/tests/messagequeuejobtest.cpp new file mode 100644 index 000000000..275f32f27 --- /dev/null +++ b/mailtransport/tests/messagequeuejobtest.cpp @@ -0,0 +1,191 @@ +/* + Copyright 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 "messagequeuejobtest.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define SPAM_ADDRESS ( QStringList() << "idanoka@gmail.com" ) + +using namespace Akonadi; +using namespace KMime; +using namespace MailTransport; + + +void MessageQueueJobTest::initTestCase() +{ + Control::start(); + // HACK: Otherwise the MDA is not switched offline soon enough apparently... + QTest::qWait( 1000 ); + + // Switch MDA offline to avoid spam. + AgentInstance mda = AgentManager::self()->instance( "akonadi_maildispatcher_agent" ); + QVERIFY( mda.isValid() ); + mda.setIsOnline( false ); + + // check that outbox is empty + LocalFolders::self()->fetch(); + QTest::kWaitForSignal( LocalFolders::self(), SIGNAL( foldersReady() ) ); + verifyOutboxContents( 0 ); +} + +void MessageQueueJobTest::testValidMessages() +{ + // check transport + int tid = TransportManager::self()->defaultTransportId(); + QVERIFY2( tid >= 0, "I need a default transport, but there is none." ); + + // send a valid message using the default transport + MessageQueueJob *qjob = new MessageQueueJob; + qjob->setTransportId( tid ); + Message::Ptr msg = Message::Ptr( new Message ); + msg->setContent( "\nThis is message #1 from the MessageQueueJobTest unit test.\n" ); + qjob->setMessage( msg ); + qjob->setTo( SPAM_ADDRESS ); + verifyOutboxContents( 0 ); + AKVERIFYEXEC( qjob ); + + // fetch the message and verify it + QTest::qWait( 1000 ); + verifyOutboxContents( 1 ); + ItemFetchJob *fjob = new ItemFetchJob( LocalFolders::self()->outbox() ); + fjob->fetchScope().fetchFullPayload(); + fjob->fetchScope().fetchAllAttributes(); + AKVERIFYEXEC( fjob ); + QCOMPARE( fjob->items().count(), 1 ); + Item item = fjob->items().first(); + QVERIFY( !item.remoteId().isEmpty() ); // stored by the resource + QVERIFY( item.hasPayload() ); + AddressAttribute *addrA = item.attribute(); + QVERIFY( addrA ); + QVERIFY( addrA->from().isEmpty() ); + QCOMPARE( addrA->to().count(), 1 ); + QCOMPARE( addrA->to(), SPAM_ADDRESS ); + QCOMPARE( addrA->cc().count(), 0 ); + QCOMPARE( addrA->bcc().count(), 0 ); + DispatchModeAttribute *dA = item.attribute(); + QVERIFY( dA ); + QCOMPARE( dA->dispatchMode(), DispatchModeAttribute::Immediately ); // default mode + SentBehaviourAttribute *sA = item.attribute(); + QVERIFY( sA ); + QCOMPARE( sA->sentBehaviour(), SentBehaviourAttribute::MoveToDefaultSentCollection ); // default sent collection + TransportAttribute *tA = item.attribute(); + QVERIFY( tA ); + QCOMPARE( tA->transportId(), tid ); + ErrorAttribute *eA = item.attribute(); + QVERIFY( !eA ); // no error + QCOMPARE( item.flags().count(), 1 ); + QVERIFY( item.flags().contains( "queued" ) ); + + // delete message, for further tests + ItemDeleteJob *djob = new ItemDeleteJob( item ); + AKVERIFYEXEC( djob ); + verifyOutboxContents( 0 ); + + // TODO test with no To: but only BCC: + + // TODO test due-date sending + + // TODO test sending with custom sent-mail collections +} + +void MessageQueueJobTest::testInvalidMessages() +{ + MessageQueueJob *job = 0; + Message::Ptr msg; + + // without message + job = new MessageQueueJob; + job->setTransportId( TransportManager::self()->defaultTransportId() ); + job->setTo( SPAM_ADDRESS ); + QVERIFY( !job->exec() ); + + // without recipients + job = new MessageQueueJob; + msg = Message::Ptr( new Message ); + msg->setContent( "\nThis is a message sent from the MessageQueueJobTest unittest. This shouldn't have been sent.\n" ); + job->setMessage( msg ); + job->setTransportId( TransportManager::self()->defaultTransportId() ); + QVERIFY( !job->exec() ); + + // without transport + job = new MessageQueueJob; + msg = Message::Ptr( new Message ); + msg->setContent( "\nThis is a message sent from the MessageQueueJobTest unittest. This shouldn't have been sent.\n" ); + job->setMessage( msg ); + job->setTo( SPAM_ADDRESS ); + QVERIFY( !job->exec() ); + + // with AfterDueDate and no due date + job = new MessageQueueJob; + msg = Message::Ptr( new Message ); + msg->setContent( "\nThis is a message sent from the MessageQueueJobTest unittest. This shouldn't have been sent.\n" ); + job->setMessage( msg ); + job->setTo( SPAM_ADDRESS ); + job->setDispatchMode( DispatchModeAttribute::AfterDueDate ); + QVERIFY( !job->exec() ); + + // with MoveToCollection and no sent-mail folder + job = new MessageQueueJob; + msg = Message::Ptr( new Message ); + msg->setContent( "\nThis is a message sent from the MessageQueueJobTest unittest. This shouldn't have been sent.\n" ); + job->setMessage( msg ); + job->setTo( SPAM_ADDRESS ); + job->setSentBehaviour( SentBehaviourAttribute::MoveToCollection ); + QVERIFY( !job->exec() ); +} + +void MessageQueueJobTest::verifyOutboxContents( qlonglong count ) +{ + QVERIFY( LocalFolders::self()->isReady() ); + Collection outbox = LocalFolders::self()->outbox(); + QVERIFY( outbox.isValid() ); + CollectionStatisticsJob *job = new CollectionStatisticsJob( outbox ); + AKVERIFYEXEC( job ); + QCOMPARE( job->statistics().count(), count ); +} + + +QTEST_AKONADIMAIN( MessageQueueJobTest, NoGUI ) + +#include "messagequeuejobtest.moc" diff --git a/mailtransport/configmodule.h b/mailtransport/tests/messagequeuejobtest.h similarity index 60% copy from mailtransport/configmodule.h copy to mailtransport/tests/messagequeuejobtest.h index 6994d37bd..767e6539c 100644 --- a/mailtransport/configmodule.h +++ b/mailtransport/tests/messagequeuejobtest.h @@ -1,39 +1,46 @@ /* - Copyright (c) 2007 Volker Krause + Copyright 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 MAILTRANSPORT_CONFIGMODULE_H -#define MAILTRANSPORT_CONFIGMODULE_H +#ifndef MESSAGEQUEUEJOBTEST_H +#define MESSAGEQUEUEJOBTEST_H -#include +#include -namespace MailTransport { /** - KCModule for transport management. -*/ -class ConfigModule : public KCModule + This tests the ability to queue messages (MessageQueueJob class). + Note that the actual sending of messages is the MDA's job, and is not tested + here. + */ +class MessageQueueJobTest : public QObject { - public: - explicit ConfigModule( QWidget *parent = 0, - const QVariantList &args = QVariantList() ); + Q_OBJECT + + private Q_SLOTS: + void initTestCase(); + void testValidMessages(); + void testInvalidMessages(); + + private: + void verifyOutboxContents( qlonglong count ); + }; -} #endif diff --git a/mailtransport/tests/queuer.cpp b/mailtransport/tests/queuer.cpp new file mode 100644 index 000000000..715fa07b9 --- /dev/null +++ b/mailtransport/tests/queuer.cpp @@ -0,0 +1,176 @@ +/* + Copyright (c) 2006 - 2007 Volker Krause + 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 "queuer.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace KMime; +using namespace MailTransport; + + +MessageQueuer::MessageQueuer() +{ + if( !Akonadi::Control::start() ) { + kFatal() << "Could not start Akonadi server."; + } + + mComboBox = new TransportComboBox( this ); + mComboBox->setEditable( true ); + mSenderEdit = new KLineEdit( this ); + mSenderEdit->setClickMessage( "Sender" ); + mToEdit = new KLineEdit( this ); + mToEdit->setText( "idanoka@gmail.com" ); + mToEdit->setClickMessage( "To" ); + mCcEdit = new KLineEdit( this ); + mCcEdit->setClickMessage( "Cc" ); + mBccEdit = new KLineEdit( this ); + mBccEdit->setClickMessage( "Bcc" ); + mMailEdit = new KTextEdit( this ); + mMailEdit->setText( "test from queuer!" ); + mMailEdit->setAcceptRichText( false ); + mMailEdit->setLineWrapMode( QTextEdit::NoWrap ); + QPushButton *b = new QPushButton( "&Send Now", this ); + connect( b, SIGNAL(clicked(bool)), SLOT(sendNowClicked()) ); + b = new QPushButton( "Send &Queued", this ); + connect( b, SIGNAL(clicked(bool)), SLOT(sendQueuedClicked()) ); + b = new QPushButton( "Send on &Date...", this ); + connect( b, SIGNAL(clicked(bool)), SLOT(sendOnDateClicked()) ); +} + +void MessageQueuer::sendNowClicked() +{ + MessageQueueJob *qjob = createQueueJob(); + kDebug() << "DispatchMode default (Immediately)."; + qjob->start(); +} + +void MessageQueuer::sendQueuedClicked() +{ + MessageQueueJob *qjob = createQueueJob(); + kDebug() << "DispatchMode Never."; + qjob->setDispatchMode( DispatchModeAttribute::Never ); + qjob->start(); +} + +void MessageQueuer::sendOnDateClicked() +{ + QPointer dialog = new KDialog( this ); + KDateTimeWidget *dt = new KDateTimeWidget( dialog ); + dt->setDateTime( QDateTime::currentDateTime() ); + // HACK: + QTimeEdit *te = dt->findChild(); + Q_ASSERT( te ); + te->setDisplayFormat( "hh:mm:ss" ); + dialog->setMainWidget( dt ); + dialog->enableButtonCancel( false ); + dialog->exec(); + if( !dialog ) { + return; + } + kDebug() << "DispatchMode AfterDueDate" << dt->dateTime(); + MessageQueueJob *qjob = createQueueJob(); + qjob->setDispatchMode( DispatchModeAttribute::AfterDueDate ); + qjob->setDueDate( dt->dateTime() ); + qjob->start(); + delete dialog; +} + +MessageQueueJob *MessageQueuer::createQueueJob() +{ + Message::Ptr msg = Message::Ptr( new Message ); + // No headers; need a '\n' to separate headers from body. + // TODO: use real headers + msg->setContent( QByteArray("\n") + mMailEdit->document()->toPlainText().toLatin1() ); + kDebug() << "msg:" << msg->encodedContent( true ); + + MessageQueueJob *job = new MessageQueueJob(); + job->setMessage( msg ); + job->setTransportId( mComboBox->currentTransportId() ); + // default dispatch mode + // default sent-mail collection + job->setFrom( mSenderEdit->text() ); + job->setTo( mToEdit->text().isEmpty() ? QStringList() : mToEdit->text().split( ',' ) ); + job->setCc( mCcEdit->text().isEmpty() ? QStringList() : mCcEdit->text().split( ',' ) ); + job->setBcc( mBccEdit->text().isEmpty() ? QStringList() : mBccEdit->text().split( ',' ) ); + + connect( job, SIGNAL(result(KJob*)), + SLOT(jobResult(KJob*)) ); + connect( job, SIGNAL(percent(KJob*,unsigned long)), + SLOT(jobPercent(KJob*,unsigned long)) ); + connect( job, SIGNAL(infoMessage(KJob*,QString,QString)), + SLOT(jobInfoMessage(KJob*,QString,QString)) ); + + return job; +} + +int main( int argc, char **argv ) +{ + KCmdLineArgs::init( argc, argv, "messagequeuer", 0, + ki18n( "messagequeuer" ), "0", + ki18n( "MessageQueuerJob Demo" ) ); + KApplication app; + MessageQueuer *t = new MessageQueuer(); + t->show(); + app.exec(); + delete t; +} + +void MessageQueuer::jobResult( KJob *job ) +{ + if( job->error() ) { + kDebug() << "job error:" << job->errorText(); + } else { + kDebug() << "job success."; + } +} + +void MessageQueuer::jobPercent( KJob *job, unsigned long percent ) +{ + Q_UNUSED( job ); + kDebug() << percent << "%"; +} + +void MessageQueuer::jobInfoMessage( KJob *job, const QString &info, const QString &info2 ) +{ + Q_UNUSED( job ); + kDebug() << info; + kDebug() << info2; +} + + +#include "queuer.moc" diff --git a/mailtransport/tests/transportmgr.h b/mailtransport/tests/queuer.h similarity index 73% copy from mailtransport/tests/transportmgr.h copy to mailtransport/tests/queuer.h index e5f14ed49..5e0076c6b 100644 --- a/mailtransport/tests/transportmgr.h +++ b/mailtransport/tests/queuer.h @@ -1,53 +1,64 @@ /* Copyright (c) 2006 - 2007 Volker Krause + 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 TRANSPORTMGR_H -#define TRANSPORTMGR_H +#ifndef MESSAGEQUEUER_H +#define MESSAGEQUEUER_H #include #include class KJob; class KLineEdit; -class QTextEdit; +class KTextEdit; -class TransportMgr : public KVBox +namespace MailTransport { + class MessageQueueJob; +} + + +/** + Mostly stolen from transportmgr.{h,cpp} +*/ +class MessageQueuer : public KVBox { Q_OBJECT public: - TransportMgr(); + MessageQueuer(); private slots: - void removeAllBtnClicked(); - void editBtnClicked(); - void sendBtnClicked(); - void cancelBtnClicked(); + void sendNowClicked(); + void sendQueuedClicked(); + void sendOnDateClicked(); void jobResult( KJob *job ); void jobPercent( KJob *job, unsigned long percent ); void jobInfoMessage( KJob *job, const QString &info, const QString &info2 ); private: MailTransport::TransportComboBox *mComboBox; KLineEdit *mSenderEdit, *mToEdit, *mCcEdit, *mBccEdit; - QTextEdit *mMailEdit; - KJob *mCurrentJob; + KTextEdit *mMailEdit; + + MailTransport::MessageQueueJob *createQueueJob(); + }; + #endif diff --git a/mailtransport/tests/sendqueued.cpp b/mailtransport/tests/sendqueued.cpp new file mode 100644 index 000000000..9038ecd20 --- /dev/null +++ b/mailtransport/tests/sendqueued.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 "sendqueued.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +using namespace Akonadi; +using namespace MailTransport; + + +Runner::Runner() +{ + Control::start(); + + connect( LocalFolders::self(), SIGNAL( foldersReady() ), + this, SLOT( checkFolders() ) ); + LocalFolders::self()->fetch(); +} + +void Runner::checkFolders() +{ + Collection outbox = LocalFolders::self()->outbox(); + kDebug() << "Got outbox" << outbox.id(); + + if( !outbox.isValid() ) { + KApplication::exit( 1 ); + } + + FilterActionJob *fjob = new FilterActionJob( outbox, new SendQueuedAction, this ); + connect( fjob, SIGNAL(result(KJob*)), this, SLOT(jobResult(KJob*)) ); +} + +void Runner::jobResult( KJob *job ) +{ + if( job->error() ) { + kDebug() << "Job error:" << job->errorString(); + KApplication::exit( 2 ); + } else { + kDebug() << "Job success."; + KApplication::exit( 0 ); + } +} + +int main( int argc, char **argv ) +{ + KCmdLineArgs::init( argc, argv, "sendqueued", 0, + ki18n( "sendqueued" ), "0", + ki18n( "An app that sends all queued messages" ) ); + KApplication app; + new Runner(); + return app.exec(); +} + + +#include "sendqueued.moc" diff --git a/mailtransport/configmodule.h b/mailtransport/tests/sendqueued.h similarity index 68% copy from mailtransport/configmodule.h copy to mailtransport/tests/sendqueued.h index 6994d37bd..470a1f247 100644 --- a/mailtransport/configmodule.h +++ b/mailtransport/tests/sendqueued.h @@ -1,39 +1,45 @@ /* - Copyright (c) 2007 Volker Krause + 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 MAILTRANSPORT_CONFIGMODULE_H -#define MAILTRANSPORT_CONFIGMODULE_H +#ifndef SENDQUEUED_H +#define SENDQUEUED_H -#include +#include -namespace MailTransport { +class KJob; /** - KCModule for transport management. + This class uses the SendQueuedAction to mark all queued messages in the + outbox for immediate sending. */ -class ConfigModule : public KCModule +class Runner : public QObject { + Q_OBJECT + public: - explicit ConfigModule( QWidget *parent = 0, - const QVariantList &args = QVariantList() ); + Runner(); + + private slots: + void checkFolders(); + void jobResult( KJob *job ); + }; -} #endif diff --git a/mailtransport/tests/transportmgr.cpp b/mailtransport/tests/transportmgr.cpp index be6c7accb..afe9ddf0b 100644 --- a/mailtransport/tests/transportmgr.cpp +++ b/mailtransport/tests/transportmgr.cpp @@ -1,146 +1,148 @@ /* Copyright (c) 2006 - 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 "transportmgr.h" #include #include #include #include #include #include #include #include +#include #include -#include using namespace MailTransport; TransportMgr::TransportMgr() : mCurrentJob( 0 ) { new TransportManagementWidget( this ); mComboBox = new TransportComboBox( this ); mComboBox->setEditable( true ); QPushButton *b = new QPushButton( "&Edit", this ); connect( b, SIGNAL(clicked(bool)), SLOT(editBtnClicked()) ); b = new QPushButton( "&Remove all transports", this ); connect( b, SIGNAL(clicked(bool)), SLOT(removeAllBtnClicked()) ); mSenderEdit = new KLineEdit( this ); mSenderEdit->setClickMessage( "Sender" ); mToEdit = new KLineEdit( this ); mToEdit->setClickMessage( "To" ); mCcEdit = new KLineEdit( this ); mCcEdit->setClickMessage( "Cc" ); mBccEdit = new KLineEdit( this ); mBccEdit->setClickMessage( "Bcc" ); - mMailEdit = new QTextEdit( this ); + mMailEdit = new KTextEdit( this ); mMailEdit->setAcceptRichText( false ); mMailEdit->setLineWrapMode( QTextEdit::NoWrap ); b = new QPushButton( "&Send", this ); connect( b, SIGNAL(clicked(bool)), SLOT(sendBtnClicked()) ); b = new QPushButton( "&Cancel", this ); connect( b, SIGNAL(clicked(bool)), SLOT(cancelBtnClicked()) ); } void TransportMgr::removeAllBtnClicked() { MailTransport::TransportManager *manager = MailTransport::TransportManager::self(); QList transports = manager->transports(); for ( int i=0; i < transports.count(); i++ ) { MailTransport::Transport *transport = transports.at( i ); kDebug() << transport->host(); manager->removeTransport( transport->id() ); } } void TransportMgr::editBtnClicked() { + // NOTE: Using deprecated TransportConfigDialog here for testing purposes. + // The TransportManagementWidget uses the non-deprecated method instead. TransportConfigDialog *t = new TransportConfigDialog( TransportManager::self()->transportById( mComboBox->currentTransportId() ), this ); t->exec(); delete t; } void TransportMgr::sendBtnClicked() { TransportJob *job; job = TransportManager::self()->createTransportJob( mComboBox->currentTransportId() ); if ( !job ) { kDebug() << "Invalid transport!"; return; } job->setSender( mSenderEdit->text() ); job->setTo( mToEdit->text().isEmpty() ? QStringList() : mToEdit->text().split( ',' ) ); job->setCc( mCcEdit->text().isEmpty() ? QStringList() : mCcEdit->text().split( ',' ) ); job->setBcc( mBccEdit->text().isEmpty() ? QStringList() : mBccEdit->text().split( ',' ) ); job->setData( mMailEdit->document()->toPlainText().toLatin1() ); connect( job, SIGNAL(result(KJob*)), SLOT(jobResult(KJob*)) ); connect( job, SIGNAL(percent(KJob*,unsigned long)), SLOT(jobPercent(KJob*,unsigned long)) ); connect( job, SIGNAL(infoMessage(KJob*,QString,QString)), SLOT(jobInfoMessage(KJob*,QString,QString)) ); mCurrentJob = job; TransportManager::self()->schedule( job ); } void TransportMgr::cancelBtnClicked() { if ( mCurrentJob ) { kDebug() << "kill success:" << mCurrentJob->kill(); } mCurrentJob = 0; } int main( int argc, char **argv ) { KCmdLineArgs::init( argc, argv, "transportmgr", 0, ki18n( "transportmgr" ), "0", ki18n( "Mail Transport Manager Demo" ) ); KApplication app; TransportMgr *t = new TransportMgr(); t->show(); app.exec(); delete t; } void TransportMgr::jobResult( KJob *job ) { kDebug() << job->error() << job->errorText(); mCurrentJob = 0; } void TransportMgr::jobPercent( KJob *job, unsigned long percent ) { Q_UNUSED( job ); kDebug() << percent << "%"; } void TransportMgr::jobInfoMessage( KJob *job, const QString &info, const QString &info2 ) { Q_UNUSED( job ); kDebug() << info; kDebug() << info2; } #include "transportmgr.moc" diff --git a/mailtransport/tests/transportmgr.h b/mailtransport/tests/transportmgr.h index e5f14ed49..76591eb0d 100644 --- a/mailtransport/tests/transportmgr.h +++ b/mailtransport/tests/transportmgr.h @@ -1,53 +1,55 @@ /* Copyright (c) 2006 - 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 TRANSPORTMGR_H #define TRANSPORTMGR_H +#define USES_DEPRECATED_MAILTRANSPORT_API + #include #include class KJob; class KLineEdit; -class QTextEdit; +class KTextEdit; class TransportMgr : public KVBox { Q_OBJECT public: TransportMgr(); private slots: void removeAllBtnClicked(); void editBtnClicked(); void sendBtnClicked(); void cancelBtnClicked(); void jobResult( KJob *job ); void jobPercent( KJob *job, unsigned long percent ); void jobInfoMessage( KJob *job, const QString &info, const QString &info2 ); private: MailTransport::TransportComboBox *mComboBox; KLineEdit *mSenderEdit, *mToEdit, *mCcEdit, *mBccEdit; - QTextEdit *mMailEdit; + KTextEdit *mMailEdit; KJob *mCurrentJob; }; #endif diff --git a/mailtransport/transport.cpp b/mailtransport/transport.cpp index 6304cbe5c..263530ee9 100644 --- a/mailtransport/transport.cpp +++ b/mailtransport/transport.cpp @@ -1,273 +1,338 @@ /* Copyright (c) 2006 - 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 "transport.h" -#include "transportmanager.h" -#include "mailtransport_defs.h" #include "legacydecrypt.h" +#include "mailtransport_defs.h" +#include "transportmanager.h" +#include "transporttype_p.h" #include -#include -#include -#include -#include -#include -#include + +#include +#include +#include +#include +#include +#include + +#include +#include using namespace MailTransport; using namespace KWallet; /** * Private class that helps to provide binary compatibility between releases. * @internal */ class TransportPrivate { public: + TransportType transportType; QString password; bool passwordLoaded; bool passwordDirty; bool storePasswordInFile; bool needsWalletMigration; QString oldName; }; Transport::Transport( const QString &cfgGroup ) : TransportBase( cfgGroup ), d( new TransportPrivate ) { kDebug() << cfgGroup; d->passwordLoaded = false; d->passwordDirty = false; d->storePasswordInFile = false; d->needsWalletMigration = false; readConfig(); } Transport::~Transport() { delete d; } bool Transport::isValid() const { return ( id() > 0 ) && !host().isEmpty() && port() <= 65536; } QString Transport::password() { if ( !d->passwordLoaded && requiresAuthentication() && storePassword() && d->password.isEmpty() ) { TransportManager::self()->loadPasswords(); d->password = TransportManager::self()->transportById( id(), false )->password(); } return d->password; } void Transport::setPassword( const QString &passwd ) { d->passwordLoaded = true; if ( d->password == passwd ) { return; } d->passwordDirty = true; d->password = passwd; } +void Transport::forceUniqueName() +{ + QStringList existingNames; + foreach ( Transport *t, TransportManager::self()->transports() ) { + if ( t->id() != id() ) { + existingNames << t->name(); + } + } + int suffix = 1; + QString origName = name(); + while ( existingNames.contains( name() ) ) { + setName( i18nc( "%1: name; %2: number appended to it to make " + "it unique among a list of names", "%1 #%2", origName, suffix ) ); + ++suffix; + } + +} + void Transport::updatePasswordState() { Transport *original = TransportManager::self()->transportById( id(), false ); if ( original == this ) { kWarning() << "Tried to update password state of non-cloned transport."; return; } if ( original ) { d->password = original->d->password; d->passwordLoaded = original->d->passwordLoaded; d->passwordDirty = original->d->passwordDirty; } else { kWarning() << "Transport with this ID not managed by transport manager."; } } bool Transport::isComplete() const { return !requiresAuthentication() || !storePassword() || d->passwordLoaded; } QString Transport::authenticationTypeString() const { switch ( authenticationType() ) { case EnumAuthenticationType::LOGIN: return QLatin1String( "LOGIN" ); case EnumAuthenticationType::PLAIN: return QLatin1String( "PLAIN" ); case EnumAuthenticationType::CRAM_MD5: return QLatin1String( "CRAM-MD5" ); case EnumAuthenticationType::DIGEST_MD5: return QLatin1String( "DIGEST-MD5" ); case EnumAuthenticationType::NTLM: return QLatin1String( "NTLM" ); case EnumAuthenticationType::GSSAPI: return QLatin1String( "GSSAPI" ); } Q_ASSERT( false ); return QString(); } void Transport::usrReadConfig() { TransportBase::usrReadConfig(); setHost( host().trimmed() ); if ( d->oldName.isEmpty() ) { d->oldName = name(); } + // Set TransportType. + { + using namespace Akonadi; + d->transportType = TransportType(); + d->transportType.d->mType = type(); + kDebug() << "type" << type(); + if( type() == EnumType::Akonadi ) { + const AgentInstance instance = AgentManager::self()->instance( host() ); + if( !instance.isValid() ) { + kWarning() << "Akonadi transport with invalid resource instance."; + } + d->transportType.d->mAgentType = instance.type(); + kDebug() << "agent type" << instance.type().name() << "id" << instance.type().identifier(); + } + // Now we have the type and possibly agentType. Get the name, description + // etc. from TransportManager. + const TransportType::List &types = TransportManager::self()->types(); + int index = types.indexOf( d->transportType ); + if( index != -1 ) { + d->transportType = types[ index ]; + } else { + kWarning() << "Type unknown to manager."; + d->transportType.d->mName = i18nc( "An unknown transport type", "Unknown" ); + } + } + // we have everything we need if ( !storePassword() || d->passwordLoaded ) { return; } // try to find a password in the config file otherwise KConfigGroup group( config(), currentGroup() ); if ( group.hasKey( "password" ) ) { d->password = KStringHandler::obscure( group.readEntry( "password" ) ); } else if ( group.hasKey( "password-kmail" ) ) { d->password = Legacy::decryptKMail( group.readEntry( "password-kmail" ) ); } else if ( group.hasKey( "password-knode" ) ) { d->password = Legacy::decryptKNode( group.readEntry( "password-knode" ) ); } if ( !d->password.isEmpty() ) { d->passwordLoaded = true; if ( Wallet::isEnabled() ) { d->needsWalletMigration = true; } else { d->storePasswordInFile = true; } } else { // read password if wallet is open, defer otherwise if ( Wallet::isOpen( Wallet::NetworkWallet() ) ) { // Don't read the password right away because this can lead // to reentrancy problems in KDBusServiceStarter when an application // run in Kontact creates the transports (due to a QEventLoop in the // synchronous KWallet openWallet call). QTimer::singleShot( 0, this, SLOT(readPassword()) ); } } } void Transport::usrWriteConfig() { if ( requiresAuthentication() && storePassword() && d->passwordDirty ) { Wallet *wallet = TransportManager::self()->wallet(); if ( !wallet || wallet->writePassword( QString::number( id() ), d->password ) != 0 ) { // wallet saving failed, ask if we should store in the config file instead if ( d->storePasswordInFile || KMessageBox::warningYesNo( 0, i18n( "KWallet is not available. It is strongly recommended to use " "KWallet for managing your passwords.\n" "However, the password can be stored in the configuration " "file instead. The password is stored in an obfuscated format, " "but should not be considered secure from decryption efforts " "if access to the configuration file is obtained.\n" "Do you want to store the password for server '%1' in the " "configuration file?", name() ), i18n( "KWallet Not Available" ), KGuiItem( i18n( "Store Password" ) ), KGuiItem( i18n( "Do Not Store Password" ) ) ) == KMessageBox::Yes ) { // write to config file KConfigGroup group( config(), currentGroup() ); group.writeEntry( "password", KStringHandler::obscure( d->password ) ); d->storePasswordInFile = true; } } d->passwordDirty = false; } TransportBase::usrWriteConfig(); TransportManager::self()->emitChangesCommitted(); if ( name() != d->oldName ) { emit TransportManager::self()->transportRenamed( id(), d->oldName, name() ); d->oldName = name(); } } void Transport::readPassword() { // no need to load a password if the account doesn't require auth if ( !requiresAuthentication() ) { return; } d->passwordLoaded = true; // check whether there is a chance to find our password at all if ( Wallet::folderDoesNotExist( Wallet::NetworkWallet(), WALLET_FOLDER ) || Wallet::keyDoesNotExist( Wallet::NetworkWallet(), WALLET_FOLDER, QString::number( id() ) ) ) { // try migrating password from kmail if ( Wallet::folderDoesNotExist( Wallet::NetworkWallet(), KMAIL_WALLET_FOLDER ) || Wallet::keyDoesNotExist( Wallet::NetworkWallet(), KMAIL_WALLET_FOLDER, QString::fromLatin1( "transport-%1" ).arg( id() ) ) ) { return; } kDebug() << "migrating password from kmail wallet"; KWallet::Wallet *wallet = TransportManager::self()->wallet(); if ( wallet ) { wallet->setFolder( KMAIL_WALLET_FOLDER ); wallet->readPassword( QString::fromLatin1( "transport-%1" ).arg( id() ), d->password ); wallet->removeEntry( QString::fromLatin1( "transport-%1" ).arg( id() ) ); wallet->setFolder( WALLET_FOLDER ); d->passwordDirty = true; writeConfig(); } return; } // finally try to open the wallet and read the password KWallet::Wallet *wallet = TransportManager::self()->wallet(); if ( wallet ) { wallet->readPassword( QString::number( id() ), d->password ); } } bool Transport::needsWalletMigration() const { return d->needsWalletMigration; } void Transport::migrateToWallet() { kDebug() << "migrating" << id() << "to wallet"; d->needsWalletMigration = false; KConfigGroup group( config(), currentGroup() ); group.deleteEntry( "password" ); d->passwordDirty = true; d->storePasswordInFile = false; writeConfig(); } Transport *Transport::clone() const { QString id = currentGroup().mid( 10 ); return new Transport( id ); } +TransportType Transport::transportType() const +{ + if( !d->transportType.isValid() ) { + kWarning() << "Invalid transport type."; + } + return d->transportType; +} + +void Transport::setTransportType( const TransportType &type ) +{ + Q_ASSERT( type.isValid() ); + d->transportType = type; + setType( type.type() ); +} + #include "transport.moc" diff --git a/mailtransport/transport.h b/mailtransport/transport.h index 8e8a00512..9f2b7d7c2 100644 --- a/mailtransport/transport.h +++ b/mailtransport/transport.h @@ -1,127 +1,157 @@ /* Copyright (c) 2006 - 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 MAILTRANSPORT_TRANSPORT_H #define MAILTRANSPORT_TRANSPORT_H -#include #include +#include +#include class TransportPrivate; namespace MailTransport { +class TransportType; + /** Represents the settings of a specific mail transport. To create a new empty Transport object, use TransportManager::createTransport(). */ +// TODO KDE5: Do something about the kcfg-generated TransportBase. +// Currently it has the config stuff as private members, which means it is +// utterly inextensible. Also the sendmail and akonadi-type transports use +// the "host" setting for keeping the location of the sendmail executable and +// the resource id, respectively. This is a hack; they should have separate +// config options... (cberzan) class MAILTRANSPORT_EXPORT Transport : public TransportBase { Q_OBJECT friend class TransportManager; public: - /** - Destructor - */ + /** + Destructor + */ virtual ~Transport(); typedef QList List; /** Returns true if this transport is valid, ie. has all necessary data set. */ bool isValid() const; /** Returns the password of this transport. */ QString password(); /** Sets the password of this transport. @param passwd The new password. */ void setPassword( const QString &passwd ); + /** + Makes sure the transport has a unique name. Adds #1, #2, #3 etc. if + necessary. + @since 4.4 + */ + void forceUniqueName(); + /** This function synchronizes the password of this transport with the password of the transport with the same ID that is managed by the transport manager. This is only useful for cloned transports, since their passwords don't automatically get updated when calling TransportManager::loadPasswordsAsync() or TransportManager::loadPasswords(). @sa clone() @since 4.2 */ void updatePasswordState(); /** Returns true if all settings have been loaded. This is the way to find out if the password has already been loaded from the wallet. */ bool isComplete() const; /** Returns a string representation of the authentication type. */ QString authenticationTypeString() const; /** Returns a deep copy of this Transport object which will no longer be automatically updated. Use this if you need to store a Transport object over a longer time. However it is recommended to store transport identifiers instead if possible. @sa updatePasswordState() */ Transport *clone() const; + /** + Returns the type of this transport. + @see TransportType. + @since 4.4 + */ + TransportType transportType() const; + + /** + Sets the type of this transport. + @see TransportType. + @since 4.4 + */ + void setTransportType( const TransportType &type ); + protected: /** Creates a Transport object. Should only be used by TransportManager. @param cfgGroup The KConfig group to read its data from. */ Transport( const QString &cfgGroup ); virtual void usrReadConfig(); virtual void usrWriteConfig(); /** Returns true if the password was not stored in the wallet. */ bool needsWalletMigration() const; /** Try to migrate the password from the config file to the wallet. */ void migrateToWallet(); private Q_SLOTS: void readPassword(); private: TransportPrivate *const d; }; -} +} // namespace MailTransport -#endif +#endif // MAILTRANSPORT_TRANSPORT_H diff --git a/mailtransport/transportattribute.cpp b/mailtransport/transportattribute.cpp new file mode 100644 index 000000000..1e738ba13 --- /dev/null +++ b/mailtransport/transportattribute.cpp @@ -0,0 +1,81 @@ +/* + Copyright 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 "transportattribute.h" + +#include "transportmanager.h" + +#include + +using namespace Akonadi; +using namespace MailTransport; + +class TransportAttribute::Private +{ + public: + int mId; +}; + +TransportAttribute::TransportAttribute( int id ) + : d( new Private ) +{ + d->mId = id; +} + +TransportAttribute::~TransportAttribute() +{ + delete d; +} + +TransportAttribute* TransportAttribute::clone() const +{ + return new TransportAttribute( d->mId ); +} + +QByteArray TransportAttribute::type() const +{ + static const QByteArray sType( "TransportAttribute" ); + return sType; +} + +QByteArray TransportAttribute::serialized() const +{ + return QByteArray::number( d->mId ); +} + +void TransportAttribute::deserialize( const QByteArray &data ) +{ + d->mId = data.toInt(); +} + +int TransportAttribute::transportId() const +{ + return d->mId; +} + +Transport* TransportAttribute::transport() const +{ + return TransportManager::self()->transportById( d->mId, false ); +} + +void TransportAttribute::setTransportId( int id ) +{ + d->mId = id; +} + diff --git a/mailtransport/transportattribute.h b/mailtransport/transportattribute.h new file mode 100644 index 000000000..93f613120 --- /dev/null +++ b/mailtransport/transportattribute.h @@ -0,0 +1,85 @@ +/* + Copyright 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 MAILTRANSPORT_TRANSPORTATTRIBUTE_H +#define MAILTRANSPORT_TRANSPORTATTRIBUTE_H + +#include + +#include + +namespace MailTransport { + +class Transport; + +/** + Attribute determining which transport to use for sending a message. + + @see mailtransport + @see TransportManager. + + @author Constantin Berzan + @since 4.4 +*/ +class MAILTRANSPORT_EXPORT TransportAttribute : public Akonadi::Attribute +{ + public: + /** + Creates a new TransportAttribute. + */ + TransportAttribute( int id = -1 ); + + /** + Destroys this TransportAttribute. + */ + virtual ~TransportAttribute(); + + /* reimpl */ + virtual TransportAttribute* clone() const; + virtual QByteArray type() const; + virtual QByteArray serialized() const; + virtual void deserialize( const QByteArray &data ); + + /** + Returns the transport id to use for sending this message. + @see TransportManager. + */ + int transportId() const; + + /** + Returns the transport object corresponding to the transport id contained + in this attribute. + @see Transport. + */ + Transport* transport() const; + + /** + Sets the transport id to use for sending this message. + */ + void setTransportId( int id ); + + private: + class Private; + Private *const d; + +}; + +} // namespace MailTransport + +#endif // MAILTRANSPORT_TRANSPORTATTRIBUTE_H diff --git a/mailtransport/transportcombobox.cpp b/mailtransport/transportcombobox.cpp index f1a310f98..28a72a8a8 100644 --- a/mailtransport/transportcombobox.cpp +++ b/mailtransport/transportcombobox.cpp @@ -1,98 +1,96 @@ /* Copyright (c) 2006 - 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 "transportcombobox.h" #include "transport.h" #include "transportmanager.h" -#include -#include - -#include +#include +#include using namespace MailTransport; /** * Private class that helps to provide binary compatibility between releases. * @internal */ class TransportComboBoxPrivate { public: QList transports; }; TransportComboBox::TransportComboBox( QWidget *parent ) : KComboBox( parent ), d( new TransportComboBoxPrivate ) { fillComboBox(); connect( TransportManager::self(), SIGNAL(transportsChanged()), SLOT(fillComboBox()) ); } TransportComboBox::~TransportComboBox() { delete d; } int TransportComboBox::currentTransportId() const { if ( currentIndex() >= 0 && currentIndex() < d->transports.count() ) { return d->transports.at( currentIndex() ); } return -1; } void TransportComboBox::setCurrentTransport( int transportId ) { int i = d->transports.indexOf( transportId ); if ( i >= 0 && i < count() ) { setCurrentIndex( i ); } } TransportBase::EnumType::type TransportComboBox::transportType() const { int transtype = TransportManager::self()->transportById( currentTransportId() )->type(); return static_cast( transtype ); } void TransportComboBox::fillComboBox() { int oldTransport = currentTransportId(); clear(); d->transports.clear(); int defaultId = 0; if ( !TransportManager::self()->isEmpty() ) { QStringList listNames = TransportManager::self()->transportNames(); QList listIds = TransportManager::self()->transportIds(); addItems( listNames ); d->transports << listIds; defaultId = TransportManager::self()->defaultTransportId(); } if ( oldTransport != -1 ) { setCurrentTransport( oldTransport ); } else { setCurrentTransport( defaultId ); } } #include "transportcombobox.moc" diff --git a/mailtransport/transportcombobox.h b/mailtransport/transportcombobox.h index 6e6c0e865..562f2aa27 100644 --- a/mailtransport/transportcombobox.h +++ b/mailtransport/transportcombobox.h @@ -1,72 +1,74 @@ /* Copyright (c) 2006 - 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 MAILTRANSPORT_TRANSPORTCOMBOBOX_H #define MAILTRANSPORT_TRANSPORTCOMBOBOX_H -#include #include -#include +#include + +#include class TransportComboBoxPrivate; namespace MailTransport { /** A combo-box for selecting a mail transport. + It is updated automatically when transports are added, changed, or removed. */ class MAILTRANSPORT_EXPORT TransportComboBox : public KComboBox { Q_OBJECT public: /** Creates a new mail transport selection combo box. @param parent The paren widget. */ TransportComboBox( QWidget *parent = 0 ); ~TransportComboBox(); /** Returns identifier of the currently selected mail transport. */ int currentTransportId() const; /** Selects the given transport. @param transportId The transport identifier. */ void setCurrentTransport( int transportId ); /** Returns the type of the selected transport. */ TransportBase::EnumType::type transportType() const; private Q_SLOTS: void fillComboBox(); private: TransportComboBoxPrivate *const d; }; -} +} // namespace MailTransport -#endif +#endif // MAILTRANSPORT_TRANSPORTCOMBOBOX_H diff --git a/mailtransport/transportconfigdialog.cpp b/mailtransport/transportconfigdialog.cpp index 1ef1e5a69..c1efd5bcf 100644 --- a/mailtransport/transportconfigdialog.cpp +++ b/mailtransport/transportconfigdialog.cpp @@ -1,394 +1,101 @@ /* Copyright (c) 2006 - 2007 Volker Krause Copyright (c) 2007 KovoKs + Copyright (c) 2009 Constantin Berzan Based on KMail code by: Copyright (c) 2001-2002 Michael Haeckel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 "transportconfigdialog.h" #include "transport.h" +#include "transportconfigwidget.h" #include "transportmanager.h" -#include "servertest.h" -#include "mailtransport_defs.h" +#include "transporttype.h" +#include "sendmailconfigwidget.h" +#include "smtpconfigwidget.h" -#include "ui_smtpsettings.h" -#include "ui_sendmailsettings.h" +#include +#include -#include -#include -#include -#include - -#include - -namespace { - -class BusyCursorHelper : public QObject -{ - public: - inline BusyCursorHelper( QObject *parent ) : QObject( parent ) - { - qApp->setOverrideCursor( Qt::BusyCursor ); - } - - inline ~BusyCursorHelper() - { - qApp->restoreOverrideCursor(); - } -}; - -} +#include +#include using namespace MailTransport; class MailTransport::TransportConfigDialog::Private { public: Transport *transport; + QWidget *configWidget; - Ui::SMTPSettings smtp; - Ui::SendmailSettings sendmail; - - KConfigDialogManager *manager; - KLineEdit *passwordEdit; - ServerTest *serverTest; - QButtonGroup *encryptionGroup; - QButtonGroup *authGroup; - - // detected authentication capabilities - QList noEncCapa, sslCapa, tlsCapa; - - bool serverTestFailed; - - void resetAuthCapabilities() - { - noEncCapa.clear(); - noEncCapa << Transport::EnumAuthenticationType::LOGIN - << Transport::EnumAuthenticationType::PLAIN - << Transport::EnumAuthenticationType::CRAM_MD5 - << Transport::EnumAuthenticationType::DIGEST_MD5 - << Transport::EnumAuthenticationType::NTLM - << Transport::EnumAuthenticationType::GSSAPI; - sslCapa = tlsCapa = noEncCapa; - if ( authGroup ) { - updateAuthCapbilities(); - } - } - - void updateAuthCapbilities() - { - Q_ASSERT( transport->type() == Transport::EnumType::SMTP ); - - if ( serverTestFailed ) { - return; - } - - QList capa = noEncCapa; - if ( smtp.ssl->isChecked() ) { - capa = sslCapa; - } else if ( smtp.tls->isChecked() ) { - capa = tlsCapa; - } - - for ( int i = 0; i < authGroup->buttons().count(); ++i ) { - authGroup->buttons().at( i )->setEnabled( capa.contains( i ) ); - } - - if ( capa.count() == 0 ) { - smtp.noAuthPossible->setVisible( true ); - smtp.kcfg_requiresAuthentication->setChecked( false ); - smtp.kcfg_requiresAuthentication->setEnabled( false ); - } else { - smtp.noAuthPossible->setVisible( false ); - smtp.kcfg_requiresAuthentication->setEnabled( true ); - } - } + // slots + void okClicked(); }; +void TransportConfigDialog::Private::okClicked() +{ + if( TransportConfigWidget *w = dynamic_cast( configWidget ) ) { + // It is not an Akonadi transport. + w->apply(); + transport->writeConfig(); + } +} + TransportConfigDialog::TransportConfigDialog( Transport *transport, QWidget *parent ) : KDialog( parent ), d( new Private ) { Q_ASSERT( transport ); - d->transport = transport; - d->passwordEdit = 0; - d->serverTest = 0; - d->encryptionGroup = 0; - d->authGroup = 0; - d->resetAuthCapabilities(); - setButtons( Ok|Cancel|User3 ); - showButton( User3, false ); - setButtonText( User3, i18n( "Use Sendmail" ) ); - connect( this, SIGNAL( user3Clicked() ), SLOT( slotUser3() ) ); - connect( this, SIGNAL(okClicked()), SLOT(save()) ); - connect( TransportManager::self(), SIGNAL(passwordsChanged()), - SLOT(passwordsLoaded()) ); - - switch ( transport->type() ) { + switch( transport->type() ) { case Transport::EnumType::SMTP: - { - showButton( User3, true ); - - d->smtp.setupUi( mainWidget() ); - d->passwordEdit = d->smtp.password; - - d->encryptionGroup = new QButtonGroup( this ); - d->encryptionGroup->addButton( d->smtp.none ); - d->encryptionGroup->addButton( d->smtp.ssl ); - d->encryptionGroup->addButton( d->smtp.tls ); - - d->authGroup = new QButtonGroup( this ); - d->authGroup->addButton( d->smtp.login ); - d->authGroup->addButton( d->smtp.plain ); - d->authGroup->addButton( d->smtp.crammd5 ); - d->authGroup->addButton( d->smtp.digestmd5 ); - d->authGroup->addButton( d->smtp.gssapi ); - d->authGroup->addButton( d->smtp.ntlm ); - - if ( KProtocolInfo::capabilities( SMTP_PROTOCOL ).contains( QLatin1String( "SASL" ) ) == 0 ) { - d->smtp.ntlm->hide(); - d->smtp.gssapi->hide(); + { + d->configWidget = new SMTPConfigWidget( transport, this ); + break; } - - connect( d->smtp.checkCapabilities, SIGNAL(clicked()), - SLOT(checkSmtpCapabilities()) ); - connect( d->smtp.kcfg_host, SIGNAL(textChanged(QString)), - SLOT(hostNameChanged(QString)) ); - connect( d->smtp.kcfg_encryption, SIGNAL(clicked(int)), - SLOT(encryptionChanged(int)) ); - connect( d->smtp.kcfg_requiresAuthentication, SIGNAL( toggled(bool) ), - SLOT( ensureValidAuthSelection() ) ); - break; - } case Transport::EnumType::Sendmail: - { - d->sendmail.setupUi( mainWidget() ); - - connect( d->sendmail.chooseButton, SIGNAL(clicked()), - SLOT(chooseSendmail()) ); - connect( d->sendmail.kcfg_host, SIGNAL(textChanged(QString)), - SLOT(hostNameChanged(QString)) ); - } - } - - // load the password if necessary - if ( d->passwordEdit ) { - if ( d->transport->isComplete() ) { - d->passwordEdit->setText( d->transport->password() ); - } else { - if ( d->transport->requiresAuthentication() ) { - TransportManager::self()->loadPasswordsAsync(); + { + d->configWidget = new SendmailConfigWidget( transport, this ); + break; + } + case Transport::EnumType::Akonadi: + { + kWarning() << "Tried to configure an Akonadi transport."; + d->configWidget = new QLabel( i18n( "This transport cannot be configured." ), this ); + break; + } + default: + { + Q_ASSERT( false ); + d->configWidget = 0; + break; } - } } + setMainWidget( d->configWidget ); - d->manager = new KConfigDialogManager( this, transport ); - d->manager->updateWidgets(); - hostNameChanged( d->transport->host() ); + setButtons( Ok|Cancel ); + connect( this, SIGNAL(okClicked()), this, SLOT(okClicked()) ); } -TransportConfigDialog::~ TransportConfigDialog() +TransportConfigDialog::~TransportConfigDialog() { delete d; } -void TransportConfigDialog::checkSmtpCapabilities() -{ - Q_ASSERT( d->transport->type() == Transport::EnumType::SMTP ); - - d->serverTest = new ServerTest( this ); - d->serverTest->setProtocol( SMTP_PROTOCOL ); - d->serverTest->setServer( d->smtp.kcfg_host->text().trimmed() ); - if ( d->smtp.kcfg_specifyHostname->isChecked() ) { - d->serverTest->setFakeHostname( d->smtp.kcfg_localHostname->text() ); - } - d->serverTest->setProgressBar( d->smtp.checkCapabilitiesProgress ); - BusyCursorHelper *busyCursorHelper = new BusyCursorHelper( d->serverTest ); - - connect( d->serverTest, SIGNAL(finished( QList< int > )), - SLOT(slotFinished( QList< int > ))); - connect( d->serverTest, SIGNAL(finished( QList< int > )), - busyCursorHelper, SLOT(deleteLater()) ); - d->smtp.checkCapabilities->setEnabled( false ); - d->serverTest->start(); - d->serverTestFailed = false; -} - -void TransportConfigDialog::save() -{ - d->manager->updateSettings(); - if ( d->passwordEdit ) { - d->transport->setPassword( d->passwordEdit->text() ); - } - - // enforce unique name - QStringList existingNames; - foreach ( Transport *t, TransportManager::self()->transports() ) { - if ( t->id() != d->transport->id() ) { - existingNames << t->name(); - } - } - int suffix = 1; - QString origName = d->transport->name(); - while ( existingNames.contains( d->transport->name() ) ) { - d->transport->setName( i18nc( "%1: name; %2: number appended to it to make " - "it unique among a list of names", "%1 #%2", origName, suffix ) ); - ++suffix; - } - - d->transport->writeConfig(); -} - -void TransportConfigDialog::slotUser3() -{ - reject(); - emit sendmailClicked(); -} - -void TransportConfigDialog::chooseSendmail() -{ - Q_ASSERT( d->transport->type() == Transport::EnumType::Sendmail ); - - KFileDialog dialog( KUrl( "/" ), QString(), this ); - dialog.setCaption( i18n( "Choose sendmail Location" ) ); - - if ( dialog.exec() == QDialog::Accepted ) { - KUrl url = dialog.selectedUrl(); - if ( url.isEmpty() == true ) { - return; - } - if ( !url.isLocalFile() ) { - KMessageBox::sorry( this, i18n( "Only local files allowed." ) ); - return; - } - d->sendmail.kcfg_host->setText( url.path() ); - } -} - -void TransportConfigDialog::passwordsLoaded() -{ - Q_ASSERT( d->passwordEdit ); - - // Load the password from the original to our cloned copy - d->transport->updatePasswordState(); - - if ( d->passwordEdit->text().isEmpty() ) { - d->passwordEdit->setText( d->transport->password() ); - } -} - -static void checkHighestEnabledButton( QButtonGroup *group ) -{ - Q_ASSERT( group ); - - for ( int i = group->buttons().count() - 1; i >= 0; --i ) { - QAbstractButton *b = group->buttons().at( i ); - if ( b && b->isEnabled() ) { - b->animateClick(); - return; - } - } -} - -void TransportConfigDialog::slotFinished( QList results ) -{ - d->smtp.checkCapabilities->setEnabled( true ); - d->serverTest->deleteLater(); - - // If the servertest did not find any useable authentication modes, assume the - // connection failed and don't disable any of the radioboxes. - if ( results.isEmpty() ) { - d->serverTestFailed = true; - return; - } - - // encryption method - d->smtp.none->setEnabled( results.contains( Transport::EnumEncryption::None ) ); - d->smtp.ssl->setEnabled( results.contains( Transport::EnumEncryption::SSL ) ); - d->smtp.tls->setEnabled( results.contains( Transport::EnumEncryption::TLS ) ); - checkHighestEnabledButton( d->encryptionGroup ); - - d->noEncCapa = d->serverTest->normalProtocols(); - if ( d->smtp.tls->isEnabled() ) { - d->tlsCapa = d->serverTest->tlsProtocols(); - } else { - d->tlsCapa.clear(); - } - d->sslCapa = d->serverTest->secureProtocols(); - d->updateAuthCapbilities(); - checkHighestEnabledButton( d->authGroup ); -} - -void TransportConfigDialog::hostNameChanged( const QString &text ) -{ - // sanitize hostname... - if ( d->transport->type() == Transport::EnumType::Sendmail ) { - int pos = d->sendmail.kcfg_host->cursorPosition(); - d->sendmail.kcfg_host->blockSignals( true ); - d->sendmail.kcfg_host->setText( text.trimmed() ); - d->sendmail.kcfg_host->blockSignals( false ); - d->sendmail.kcfg_host->setCursorPosition( pos ); - } else if ( d->transport->type() == Transport::EnumType::SMTP ) { - int pos = d->smtp.kcfg_host->cursorPosition(); - d->smtp.kcfg_host->blockSignals( true ); - d->smtp.kcfg_host->setText( text.trimmed() ); - d->smtp.kcfg_host->blockSignals( false ); - d->smtp.kcfg_host->setCursorPosition( pos ); - } - - d->resetAuthCapabilities(); - enableButton( Ok, !text.isEmpty() ); - for ( int i = 0; d->encryptionGroup && i < d->encryptionGroup->buttons().count(); i++ ) { - d->encryptionGroup->buttons().at( i )->setEnabled( true ); - } -} - -void TransportConfigDialog::ensureValidAuthSelection() -{ - // adjust available authentication methods - d->updateAuthCapbilities(); - foreach ( QAbstractButton *b, d->authGroup->buttons() ) { - if ( b->isChecked() && !b->isEnabled() ) { - checkHighestEnabledButton( d->authGroup ); - break; - } - } -} - -void TransportConfigDialog::encryptionChanged( int enc ) -{ - Q_ASSERT( d->transport->type() == Transport::EnumType::SMTP ); - kDebug() << enc; - - // adjust port - if ( enc == Transport::EnumEncryption::SSL ) { - if ( d->smtp.kcfg_port->value() == SMTP_PORT ) { - d->smtp.kcfg_port->setValue( SMTPS_PORT ); - } - } else { - if ( d->smtp.kcfg_port->value() == SMTPS_PORT ) { - d->smtp.kcfg_port->setValue( SMTP_PORT ); - } - } - - ensureValidAuthSelection(); -} - #include "transportconfigdialog.moc" diff --git a/mailtransport/transportconfigdialog.h b/mailtransport/transportconfigdialog.h index f0cc949d6..440163d97 100644 --- a/mailtransport/transportconfigdialog.h +++ b/mailtransport/transportconfigdialog.h @@ -1,77 +1,79 @@ /* Copyright (c) 2006 - 2007 Volker Krause + Copyright (c) 2009 Constantin Berzan Based on KMail code by: Copyright (c) 2001-2002 Michael Haeckel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 MAILTRANSPORT_TRANSPORTCONFIGDIALOG_H #define MAILTRANSPORT_TRANSPORTCONFIGDIALOG_H #include -#include + +#include namespace MailTransport { class Transport; /** Configuration dialog for a mail transport. + + @deprecated Use TransportManager::configureTransport() instead. */ -class MAILTRANSPORT_EXPORT TransportConfigDialog : public KDialog +// TODO KDE5: this class should not be exported. +// FIXME how to avoid deprecated warning from its own moc? +class MAILTRANSPORT_EXPORT_DEPRECATED TransportConfigDialog : public KDialog { Q_OBJECT public: /** Creates a new mail transport configuration dialog for the given Transport object. + The config dialog does not delete @p transport, you have to delete it + yourself. + + Note that this class only works for transports that are handled directly + by MailTransport, i.e. SMTP and Sendmail. This class cannot be used to + configure an Akonadi transport. + @param transport The Transport object to configure. This must be a deep copy of a Transport object or a newly created one, which hasn't been added to the TransportManager yet. @param parent The parent widget. */ explicit TransportConfigDialog( Transport *transport, QWidget *parent = 0 ); /** Destroys the dialog. */ virtual ~TransportConfigDialog(); - private Q_SLOTS: - void checkSmtpCapabilities(); - void chooseSendmail(); - void passwordsLoaded(); - void save(); - void slotUser3(); - void slotFinished( QList results ); - void hostNameChanged( const QString &text ); - void encryptionChanged( int enc ); - void ensureValidAuthSelection(); - private: class Private; Private *const d; - Q_SIGNALS: - void sendmailClicked(); + Q_PRIVATE_SLOT( d, void okClicked() ) + }; -} +} // namespace MailTransport -#endif +#endif // MAILTRANSPORT_TRANSPORTCONFIGDIALOG_H diff --git a/mailtransport/transportconfigwidget.cpp b/mailtransport/transportconfigwidget.cpp new file mode 100644 index 000000000..ab9afab31 --- /dev/null +++ b/mailtransport/transportconfigwidget.cpp @@ -0,0 +1,82 @@ +/* + Copyright (c) 2009 Constantin Berzan + + Based on MailTransport code by: + Copyright (c) 2006 - 2007 Volker Krause + Copyright (c) 2007 KovoKs + + Based on KMail code by: + Copyright (c) 2001-2002 Michael Haeckel + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; 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 "transportconfigwidget.h" +#include "transportconfigwidget_p.h" +#include "transport.h" +#include "transportmanager.h" + +#include +#include + +using namespace MailTransport; + +TransportConfigWidget::TransportConfigWidget( Transport *transport, QWidget *parent ) + : QWidget( parent ), d_ptr( new TransportConfigWidgetPrivate ) +{ + init( transport ); +} + +TransportConfigWidget::TransportConfigWidget( TransportConfigWidgetPrivate &dd, + Transport *transport, QWidget *parent ) + : QWidget( parent ), d_ptr( &dd ) +{ + init( transport ); +} + +TransportConfigWidget::~ TransportConfigWidget() +{ + delete d_ptr; +} + +void TransportConfigWidget::init( Transport *transport ) +{ + Q_D( TransportConfigWidget ); + kDebug() << "this" << this << "d" << d; + Q_ASSERT( transport ); + d->transport = transport; + + d->manager = new KConfigDialogManager( this, transport ); + //d->manager->updateWidgets(); // no-op; ui is set up in subclasses. +} + +KConfigDialogManager *TransportConfigWidget::configManager() const +{ + Q_D( const TransportConfigWidget ); + Q_ASSERT( d->manager ); + return d->manager; +} + +void TransportConfigWidget::apply() +{ + Q_D( TransportConfigWidget ); + d->manager->updateSettings(); + d->transport->forceUniqueName(); + d->transport->writeConfig(); + kDebug() << "Config written."; +} + +#include "transportconfigwidget.moc" diff --git a/mailtransport/transportconfigwidget.h b/mailtransport/transportconfigwidget.h new file mode 100644 index 000000000..71f92637f --- /dev/null +++ b/mailtransport/transportconfigwidget.h @@ -0,0 +1,108 @@ +/* + Copyright (c) 2009 Constantin Berzan + + Based on MailTransport code by: + Copyright (c) 2006 - 2007 Volker Krause + + Based on KMail code by: + Copyright (c) 2001-2002 Michael Haeckel + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; 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 MAILTRANSPORT_TRANSPORTCONFIGWIDGET_H +#define MAILTRANSPORT_TRANSPORTCONFIGWIDGET_H + +#include + +class KConfigDialogManager; + +namespace MailTransport { + +class Transport; +class TransportConfigWidgetPrivate; + +/** + @internal + + Abstract configuration widget for a mail transport. It makes sure that + the configured transport has a unique name, and takes care of writing its + settings to the config file. If it is a new transport, the caller must + still call TransportManager::addTransport() to register the transport. + + Concrete configuration is done in subclasses SMTPConfigWidget and + SendmailConfigWidget. Akonadi-type transports are not configured by + MailTransport directly, instead the configure() method of their agent + instance is called. + + To configure a transport from applications, use + TransportManager::configureTransport(). You still need to call + TransportManager::addTransport() if this is a new transport, not registered + with TransportManager. + + @author Constantin Berzan + @since 4.4 +*/ +class TransportConfigWidget : public QWidget +{ + Q_OBJECT + + public: + /** + Creates a new mail transport configuration widget for the given + Transport object. + @param transport The Transport object to configure. + @param parent The parent widget. + */ + explicit TransportConfigWidget( Transport *transport, QWidget *parent = 0 ); + + /** + Destroys the widget. + */ + virtual ~TransportConfigWidget(); + + /** + @internal + Get the KConfigDialogManager for this widget. + */ + KConfigDialogManager *configManager() const; + + public Q_SLOTS: + /** + Saves the transport's settings. + + The base implementation writes the settings to the config file and makes + sure the transport has a unique name. Reimplement in derived classes to + save your custom settings, and call the base implementation. + */ + // TODO: do we also want to check for invalid settings? + virtual void apply(); + + protected: + TransportConfigWidgetPrivate *const d_ptr; + TransportConfigWidget( TransportConfigWidgetPrivate &dd, + Transport *transport, QWidget *parent ); + + private: + Q_DECLARE_PRIVATE( TransportConfigWidget ) + + void init( Transport *transport ); + +}; + +} // namespace MailTransport + +#endif // MAILTRANSPORT_TRANSPORTCONFIGWIDGET_H diff --git a/mailtransport/configmodule.h b/mailtransport/transportconfigwidget_p.h similarity index 64% copy from mailtransport/configmodule.h copy to mailtransport/transportconfigwidget_p.h index 6994d37bd..1e61ba505 100644 --- a/mailtransport/configmodule.h +++ b/mailtransport/transportconfigwidget_p.h @@ -1,39 +1,46 @@ /* - Copyright (c) 2007 Volker Krause + 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 MAILTRANSPORT_CONFIGMODULE_H -#define MAILTRANSPORT_CONFIGMODULE_H +#ifndef MAILTRANSPORT_TRANSPORTCONFIGWIDGET_P_H +#define MAILTRANSPORT_TRANSPORTCONFIGWIDGET_P_H -#include +#include "transport.h" + +#include namespace MailTransport { /** - KCModule for transport management. + @internal */ -class ConfigModule : public KCModule +class TransportConfigWidgetPrivate { public: - explicit ConfigModule( QWidget *parent = 0, - const QVariantList &args = QVariantList() ); + Transport *transport; + KConfigDialogManager *manager; + + virtual ~TransportConfigWidgetPrivate() + { + } + }; -} +} // namespace MailTransport -#endif +#endif // MAILTRANSPORT_TRANSPORTCONFIGWIDGET_P_H diff --git a/mailtransport/transportjob.cpp b/mailtransport/transportjob.cpp index 63361499c..4967778cf 100644 --- a/mailtransport/transportjob.cpp +++ b/mailtransport/transportjob.cpp @@ -1,130 +1,130 @@ /* Copyright (c) 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 "transportjob.h" #include "transport.h" -#include - #include +#include + using namespace MailTransport; class MailTransport::TransportJob::Private { public: Transport *transport; QString sender; QStringList to; QStringList cc; QStringList bcc; QByteArray data; QBuffer *buffer; }; TransportJob::TransportJob( Transport *transport, QObject *parent ) : KCompositeJob( parent ), d( new Private ) { d->transport = transport; d->buffer = 0; } TransportJob::~ TransportJob() { delete d->transport; delete d; } void TransportJob::setSender( const QString &sender ) { d->sender = sender; } void TransportJob::setTo( const QStringList &to ) { d->to = to; } void TransportJob::setCc( const QStringList &cc ) { d->cc = cc; } void TransportJob::setBcc( const QStringList &bcc ) { d->bcc = bcc; } void TransportJob::setData( const QByteArray &data ) { d->data = data; } Transport *TransportJob::transport() const { return d->transport; } QString TransportJob::sender() const { return d->sender; } QStringList TransportJob::to() const { return d->to; } QStringList TransportJob::cc() const { return d->cc; } QStringList TransportJob::bcc() const { return d->bcc; } QByteArray TransportJob::data() const { return d->data; } QBuffer *TransportJob::buffer() { if ( !d->buffer ) { d->buffer = new QBuffer( this ); d->buffer->setData( d->data ); d->buffer->open( QIODevice::ReadOnly ); Q_ASSERT( d->buffer->isOpen() ); } return d->buffer; } void TransportJob::start() { if ( !transport()->isValid() ) { setError( UserDefinedError ); setErrorText( i18n( "The mail transport \"%1\" is not correctly configured.", transport()->name() ) ); emitResult(); return; } doStart(); } diff --git a/mailtransport/transportjob.h b/mailtransport/transportjob.h index 28bf00fdc..4afcc4c76 100644 --- a/mailtransport/transportjob.h +++ b/mailtransport/transportjob.h @@ -1,142 +1,146 @@ /* Copyright (c) 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 MAILTRANSPORT_TRANSPORTJOB_H #define MAILTRANSPORT_TRANSPORTJOB_H #include -#include + #include +#include + class QBuffer; namespace MailTransport { class Transport; /** Abstract base class for all mail transport jobs. This is a job that is supposed to send exactly one mail. + + @deprecated Use MessageQueueJob for sending e-mail. */ -class MAILTRANSPORT_EXPORT TransportJob : public KCompositeJob +class MAILTRANSPORT_EXPORT_DEPRECATED TransportJob : public KCompositeJob { friend class TransportManager; public: /** Deletes this transport job. */ virtual ~TransportJob(); /** Sets the sender of the mail. @p sender must be the plain email address, not including display name. */ void setSender( const QString &sender ); /** Sets the "To" receiver(s) of the mail. @p to must be the plain email address(es), not including display name. */ void setTo( const QStringList &to ); /** Sets the "Cc" receiver(s) of the mail. @p cc must be the plain email address(es), not including display name. */ void setCc( const QStringList &cc ); /** Sets the "Bcc" receiver(s) of the mail. @p bcc must be the plain email address(es), not including display name. */ void setBcc( const QStringList &bcc ); /** Sets the content of the mail. */ void setData( const QByteArray &data ); /** Starts this job. It is recommended to not call this method directly but use TransportManager::schedule() to execute the job instead. @see TransportManager::schedule() */ virtual void start(); /** Returns the Transport object containing the mail transport settings. */ Transport *transport() const; protected: /** Creates a new mail transport job. @param transport The transport configuration. This must be a deep copy of a Transport object, the job takes the ownership of this object. @param parent The parent object. @see TransportManager::createTransportJob() */ explicit TransportJob( Transport *transport, QObject *parent = 0 ); /** Returns the sender of the mail. */ QString sender() const; /** Returns the "To" receiver(s) of the mail. */ QStringList to() const; /** Returns the "Cc" receiver(s) of the mail. */ QStringList cc() const; /** Returns the "Bcc" receiver(s) of the mail. */ QStringList bcc() const; /** Returns the data of the mail. */ QByteArray data() const; /** Returns a QBuffer opened on the message data. This is useful for processing the data in smaller chunks. */ QBuffer *buffer(); /** Do the actual work, implement in your subclass. */ virtual void doStart() = 0; private: class Private; Private *const d; }; -} +} // namespace MailTransport -#endif +#endif // MAILTRANSPORT_TRANSPORTJOB_H diff --git a/mailtransport/transportlistview.cpp b/mailtransport/transportlistview.cpp new file mode 100644 index 000000000..0956f6547 --- /dev/null +++ b/mailtransport/transportlistview.cpp @@ -0,0 +1,114 @@ +/* + Copyright (c) 2009 Constantin Berzan + + Based on KMail code by: + Copyright (c) 2002 Marc Mutz + 2007 Mathias Soeken + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; 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 "transportlistview.h" +#include "transport.h" +#include "transportmanager.h" +#include "transporttype.h" + +#include +#include + +#include +#include + +using namespace MailTransport; + +TransportListView::TransportListView( QWidget *parent ) + : QTreeWidget( parent ) +{ + setHeaderLabels( QStringList() + << i18nc( "@title:column email transport name", "Name" ) + << i18nc( "@title:column email transport type", "Type" ) ); + setRootIsDecorated( false ); + header()->setMovable( false ); + setAllColumnsShowFocus( true ); + setAlternatingRowColors( true ); + setSortingEnabled( true ); + sortByColumn( 0, Qt::AscendingOrder ); + setSelectionMode( SingleSelection ); + + fillTransportList(); + connect( TransportManager::self(), SIGNAL(transportsChanged()), + this, SLOT(fillTransportList()) ); +} + +void TransportListView::editItem( QTreeWidgetItem *item, int column ) +{ + // TODO: is there a nicer way to make only the 'name' column editable? + if ( column == 0 && item ) { + Qt::ItemFlags oldFlags = item->flags(); + item->setFlags( oldFlags | Qt::ItemIsEditable ); + QTreeWidget::editItem( item, 0 ); + item->setFlags( oldFlags ); + } +} + +void TransportListView::commitData( QWidget *editor ) +{ + if( selectedItems().size() < 1 ) { + // transport was deleted by someone else??? + kDebug() << "No selected item."; + return; + } + QTreeWidgetItem *item = selectedItems()[0]; + QLineEdit *edit = dynamic_cast( editor ); // krazy:exclude=qclasses + Q_ASSERT( edit ); // original code had if + + int id = item->data( 0, Qt::UserRole ).toInt(); + Transport *t = TransportManager::self()->transportById( id ); + if( !t ) { + kWarning() << "Transport" << id << "not known by manager."; + return; + } + kDebug() << "Renaming transport" << id << "to" << edit->text(); + t->setName( edit->text() ); + t->forceUniqueName(); + t->writeConfig(); +} + +void TransportListView::fillTransportList() +{ + // try to preserve the selection + int selected = -1; + if ( currentItem() ) { + selected = currentItem()->data( 0, Qt::UserRole ).toInt(); + } + + clear(); + foreach ( Transport *t, TransportManager::self()->transports() ) { + QTreeWidgetItem *item = new QTreeWidgetItem( this ); + item->setData( 0, Qt::UserRole, t->id() ); + item->setText( 0, t->name() ); + QString type = t->transportType().name(); + if ( TransportManager::self()->defaultTransportId() == t->id() ) { + type += i18nc( "@label the default mail transport", " (Default)" ); + } + item->setText( 1, type ); + if ( t->id() == selected ) { + setCurrentItem( item ); + } + } +} + +#include "transportlistview.moc" diff --git a/mailtransport/legacydecrypt.h b/mailtransport/transportlistview.h similarity index 56% copy from mailtransport/legacydecrypt.h copy to mailtransport/transportlistview.h index 209a3e9c1..1ffd9571a 100644 --- a/mailtransport/legacydecrypt.h +++ b/mailtransport/transportlistview.h @@ -1,49 +1,52 @@ /* - Copyright (c) 2007 Volker Krause - - KNode code: - Copyright (c) 1999-2005 the KNode authors. // krazy:exclude=copyright + 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 MAILTRANSPORT_LEGACYDECRYPT_H -#define MAILTRANSPORT_LEGACYDECRYPT_H +#ifndef MAILTRANSPORT_TRANSPORTLISTVIEW_H +#define MAILTRANSPORT_TRANSPORTLISTVIEW_H -#include +#include namespace MailTransport { /** - Methods to read passwords from config files still using legacy encryption. + @internal + A QTreeWidget for transports. */ -class Legacy +class TransportListView : public QTreeWidget { + Q_OBJECT + public: - /** - Read data encrypted using KMail's legacy encryption. - */ - static QString decryptKMail( const QString &data ); - - /** - Read data encrypted using KNode's legacy encryption. - */ - static QString decryptKNode( const QString &data ); + TransportListView( QWidget *parent = 0 ); + //virtual ~TransportListView() {} + + // overloaded from QTreeWidget + void editItem( QTreeWidgetItem *item, int column = 0 ); + + protected slots: + virtual void commitData( QWidget *editor ); + + private slots: + void fillTransportList(); + }; -} +} // namespace MailTransport -#endif +#endif // MAILTRANSPORT_TRANSPORTLISTVIEW_H diff --git a/mailtransport/transportmanagementwidget.cpp b/mailtransport/transportmanagementwidget.cpp index b5e18a702..9e0e06876 100644 --- a/mailtransport/transportmanagementwidget.cpp +++ b/mailtransport/transportmanagementwidget.cpp @@ -1,183 +1,125 @@ /* Copyright (c) 2006 - 2007 Volker Krause Based on KMail code by: Copyright (C) 2001-2003 Marc Mutz This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 "transportmanagementwidget.h" #include "ui_transportmanagementwidget.h" #include "transportmanager.h" #include "transport.h" -#include "transportconfigdialog.h" using namespace MailTransport; class TransportManagementWidget::Private { public: Ui::TransportManagementWidget ui; }; TransportManagementWidget::TransportManagementWidget( QWidget *parent ) : QWidget( parent ), d( new Private ) { KGlobal::locale()->insertCatalog( QString::fromLatin1( "libmailtransport" ) ); d->ui.setupUi( this ); + updateButtonState(); - d->ui.transportList->setHeaderLabels( QStringList() - << i18nc( "@title:column email transport name", "Name" ) - << i18nc( "@title:column email transport type", "Type" ) ); - d->ui.transportList->sortItems( 0, Qt::AscendingOrder ); connect( d->ui.transportList, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), SLOT(updateButtonState()) ); connect( d->ui.transportList, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), SLOT(editClicked()) ); connect( d->ui.addButton, SIGNAL(clicked()), SLOT(addClicked()) ); connect( d->ui.editButton, SIGNAL(clicked()), SLOT(editClicked()) ); + connect( d->ui.renameButton, SIGNAL(clicked()), SLOT(renameClicked()) ); connect( d->ui.removeButton, SIGNAL(clicked()), SLOT(removeClicked()) ); connect( d->ui.defaultButton, SIGNAL(clicked()), SLOT(defaultClicked()) ); - - fillTransportList(); - connect( TransportManager::self(), SIGNAL(transportsChanged()), - SLOT(fillTransportList()) ); } TransportManagementWidget::~TransportManagementWidget() { delete d; } -void TransportManagementWidget::fillTransportList() -{ - // try to preserve the selection - int selected = -1; - if ( d->ui.transportList->currentItem() ) { - selected = d->ui.transportList->currentItem()->data( 0, Qt::UserRole ).toInt(); - } - - d->ui.transportList->clear(); - foreach ( Transport *t, TransportManager::self()->transports() ) { - QTreeWidgetItem *item = new QTreeWidgetItem( d->ui.transportList ); - item->setData( 0, Qt::UserRole, t->id() ); - item->setText( 0, t->name() ); - QString type; - switch ( t->type() ) { - case Transport::EnumType::SMTP: - type = i18nc( "@option SMTP transport", "SMTP" ); - break; - case Transport::EnumType::Sendmail: - type = i18nc( "@option sendmail transport", "Sendmail" ); - break; - } - if ( TransportManager::self()->defaultTransportId() == t->id() ) { - type += i18nc( "@label the default mail transport", " (Default)" ); - } - item->setText( 1, type ); - if ( t->id() == selected ) { - d->ui.transportList->setCurrentItem( item ); - } - } - - updateButtonState(); -} - void TransportManagementWidget::updateButtonState() { + // TODO figure out current item vs. selected item (in almost every function) if ( !d->ui.transportList->currentItem() ) { d->ui.editButton->setEnabled( false ); + d->ui.renameButton->setEnabled( false ); d->ui.removeButton->setEnabled( false ); d->ui.defaultButton->setEnabled( false ); } else { d->ui.editButton->setEnabled( true ); + d->ui.renameButton->setEnabled( true ); d->ui.removeButton->setEnabled( true ); if ( d->ui.transportList->currentItem()->data( 0, Qt::UserRole ) == TransportManager::self()->defaultTransportId() ) { d->ui.defaultButton->setEnabled( false ); } else { d->ui.defaultButton->setEnabled( true ); } } } void TransportManagementWidget::addClicked() { - // initialize transport - Transport *t = TransportManager::self()->createTransport(); - t->setType( Transport::EnumType::SMTP ); - - // configure transporr - TransportConfigDialog *tcd = new TransportConfigDialog( t, this ); - connect( tcd, SIGNAL(sendmailClicked()), SLOT(slotSendmail()) ); - tcd->setCaption( i18nc( "@title:window", "Add Transport" ) ); - if ( tcd->exec() == KDialog::Accepted ) { - TransportManager::self()->addTransport( t ); - } else { - delete t; - } -} - -void TransportManagementWidget::slotSendmail() -{ - // initialize transport - Transport *t = TransportManager::self()->createTransport(); - t->setType( Transport::EnumType::Sendmail ); - t->setHost( QLatin1String( "/usr/sbin/sendmail" ) ); - - TransportConfigDialog tcd( t, this ); - tcd.setCaption( i18nc( "@title:window", "Add Transport" ) ); - if ( tcd.exec() == KDialog::Accepted ) { - TransportManager::self()->addTransport( t ); - } else { - delete t; - } + TransportManager::self()->showNewTransportDialog( this ); } void TransportManagementWidget::editClicked() { - Q_ASSERT( d->ui.transportList->currentItem() ); + if( !d->ui.transportList->currentItem() ) { + return; + } int currentId = d->ui.transportList->currentItem()->data( 0, Qt::UserRole ).toInt(); Transport *transport = TransportManager::self()->transportById( currentId ); - if ( !transport ) { + TransportManager::self()->configureTransport( transport, this ); +} + +void TransportManagementWidget::renameClicked() +{ + if( !d->ui.transportList->currentItem() ) { return; } - transport = transport->clone(); - TransportConfigDialog t( transport, this ); - t.setCaption( i18nc( "@title:window", "Modify Transport" ) ); - t.exec(); - delete transport; + + d->ui.transportList->editItem( d->ui.transportList->currentItem(), 0 ); } void TransportManagementWidget::removeClicked() { - Q_ASSERT( d->ui.transportList->currentItem() ); + if( !d->ui.transportList->currentItem() ) { + return; + } TransportManager::self()->removeTransport( d->ui.transportList->currentItem()->data( 0, Qt::UserRole ).toInt() ); } void TransportManagementWidget::defaultClicked() { - Q_ASSERT( d->ui.transportList->currentItem() ); + if( !d->ui.transportList->currentItem() ) { + return; + } TransportManager::self()->setDefaultTransport( d->ui.transportList->currentItem()->data( 0, Qt::UserRole ).toInt() ); } #include "transportmanagementwidget.moc" diff --git a/mailtransport/transportmanagementwidget.h b/mailtransport/transportmanagementwidget.h index 3b10d22ed..81b49ac64 100644 --- a/mailtransport/transportmanagementwidget.h +++ b/mailtransport/transportmanagementwidget.h @@ -1,66 +1,66 @@ /* Copyright (c) 2006 - 2007 Volker Krause Based on KMail code by: Copyright (C) 2001-2003 Marc Mutz This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 MAILTRANSPORT_TRANSPORTMANAGEMENTWIDGET_H #define MAILTRANSPORT_TRANSPORTMANAGEMENTWIDGET_H #include + #include namespace MailTransport { /** A widget to manage mail transports. */ class MAILTRANSPORT_EXPORT TransportManagementWidget : public QWidget { Q_OBJECT public: /** Creates a new TransportManagementWidget. @param parent The parent widget. */ TransportManagementWidget( QWidget *parent = 0 ); /** Destroys the widget. */ virtual ~TransportManagementWidget(); private Q_SLOTS: - void fillTransportList(); void updateButtonState(); void addClicked(); void editClicked(); + void renameClicked(); void removeClicked(); void defaultClicked(); - void slotSendmail(); private: class Private; Private * const d; }; -} +} // namespace MailTransport -#endif +#endif // MAILTRANSPORT_TRANSPORTMANAGEMENTWIDGET_H diff --git a/mailtransport/transportmanagementwidget.ui b/mailtransport/transportmanagementwidget.ui index 46c546ab8..b243783dd 100644 --- a/mailtransport/transportmanagementwidget.ui +++ b/mailtransport/transportmanagementwidget.ui @@ -1,97 +1,85 @@ - + + MailTransport::TransportManagementWidget - - + + 0 0 400 300 - - - - - Qt::Vertical - - - - 20 - 141 - - - - - - - - Set Default + + + + + false - - - - R&emove + + + + A&dd... - - - + + + &Modify... - - - - A&dd... + + + + &Rename - - - - true - - - false + + + + Remo&ve - - false - - - true + + + + + + &Set as Default - - true + + + + + + Qt::Vertical - - 2 + + + 20 + 141 + - - - 1 - - - - - 1 - - - + KPushButton QPushButton
kpushbutton.h
+ + TransportListView + QTreeWidget +
transportlistview.h
+
diff --git a/mailtransport/transportmanager.cpp b/mailtransport/transportmanager.cpp index dc7b3b270..7311d9311 100644 --- a/mailtransport/transportmanager.cpp +++ b/mailtransport/transportmanager.cpp @@ -1,616 +1,771 @@ /* Copyright (c) 2006 - 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 "transportmanager.h" +#include "addtransportdialog.h" +#include "resourcesendjob.h" #include "mailtransport_defs.h" -#include "transport.h" -#include "smtpjob.h" +#include "sendmailconfigwidget.h" #include "sendmailjob.h" +#include "smtpconfigwidget.h" +#include "smtpjob.h" +#include "transport.h" +#include "transportconfigwidget.h" +#include "transportjob.h" +#include "transporttype.h" +#include "transporttype_p.h" #include "transportconfigdialog.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include #include #include +#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + using namespace MailTransport; using namespace KWallet; /** * Private class that helps to provide binary compatibility between releases. * @internal */ class TransportManager::Private { public: Private() {} ~Private() { delete config; qDeleteAll( transports ); } KConfig *config; QList transports; + TransportType::List types; bool myOwnChange; bool appliedChange; KWallet::Wallet *wallet; bool walletOpenFailed; bool walletAsyncOpen; int defaultTransportId; bool isMainInstance; QList walletQueue; }; class StaticTransportManager : public TransportManager { public: StaticTransportManager() : TransportManager() {} }; StaticTransportManager *sSelf = 0; static void destroyStaticTransportManager() { delete sSelf; } TransportManager::TransportManager() : QObject(), d( new Private ) { KGlobal::locale()->insertCatalog( QLatin1String( "libmailtransport" ) ); qAddPostRoutine( destroyStaticTransportManager ); d->myOwnChange = false; d->appliedChange = false; d->wallet = 0; d->walletOpenFailed = false; d->walletAsyncOpen = false; d->defaultTransportId = -1; d->config = new KConfig( QLatin1String( "mailtransports" ) ); QDBusConnection::sessionBus().registerObject( DBUS_OBJECT_PATH, this, QDBusConnection::ExportScriptableSlots | QDBusConnection::ExportScriptableSignals ); QDBusConnection::sessionBus().connect( QString(), QString(), DBUS_INTERFACE_NAME, DBUS_CHANGE_SIGNAL, this, SLOT(slotTransportsChanged()) ); d->isMainInstance = QDBusConnection::sessionBus().registerService( DBUS_SERVICE_NAME ); connect( QDBusConnection::sessionBus().interface(), SIGNAL(serviceOwnerChanged(QString,QString,QString)), SLOT(dbusServiceOwnerChanged(QString,QString,QString)) ); + + fillTypes(); } TransportManager::~TransportManager() { qRemovePostRoutine( destroyStaticTransportManager ); delete d; } TransportManager *TransportManager::self() { if ( !sSelf ) { sSelf = new StaticTransportManager; sSelf->readConfig(); } return sSelf; } Transport *TransportManager::transportById( int id, bool def ) const { foreach ( Transport *t, d->transports ) { if ( t->id() == id ) { return t; } } if ( def || ( id == 0 && d->defaultTransportId != id ) ) { return transportById( d->defaultTransportId, false ); } return 0; } Transport *TransportManager::transportByName( const QString &name, bool def ) const { foreach ( Transport *t, d->transports ) { if ( t->name() == name ) { return t; } } if ( def ) { return transportById( 0, false ); } return 0; } QList< Transport * > TransportManager::transports() const { return d->transports; } +TransportType::List TransportManager::types() const +{ + return d->types; +} + Transport *TransportManager::createTransport() const { int id = createId(); Transport *t = new Transport( QString::number( id ) ); t->setId( id ); return t; } void TransportManager::addTransport( Transport *transport ) { if ( d->transports.contains( transport ) ) { + kDebug() << "Already have this transport."; return; } + kDebug() << "Added transport" << transport; d->transports.append( transport ); validateDefault(); emitChangesCommitted(); } void TransportManager::schedule( TransportJob *job ) { connect( job, SIGNAL(result(KJob*)), SLOT(jobResult(KJob*)) ); // check if the job is waiting for the wallet if ( !job->transport()->isComplete() ) { kDebug() << "job waits for wallet:" << job; d->walletQueue << job; loadPasswordsAsync(); return; } job->start(); } void TransportManager::createDefaultTransport() { KEMailSettings kes; Transport *t = createTransport(); t->setName( i18n( "Default Transport" ) ); t->setHost( kes.getSetting( KEMailSettings::OutServer ) ); if ( t->isValid() ) { t->writeConfig(); addTransport( t ); } else { kWarning() << "KEMailSettings does not contain a valid transport."; } } -bool TransportManager::checkTransport( QWidget *parent ) +bool TransportManager::showNewTransportDialog( QWidget *parent ) +{ + QPointer dialog = new AddTransportDialog( parent ); + bool accepted = ( dialog->exec() == QDialog::Accepted ); + delete dialog; + return accepted; +} + +bool TransportManager::promptCreateTransportIfNoneExists( QWidget *parent ) { if ( !isEmpty() ) { return true; } - const int response = KMessageBox::messageBox( - parent, - KMessageBox::WarningContinueCancel, - i18n( "You must create an outgoing account before sending." ), - i18n( "Create Account Now?" ), - KGuiItem( i18n( "Create Account Now" ) ) ); + const int response = KMessageBox::messageBox( parent, + KMessageBox::WarningContinueCancel, + i18n( "You must create an outgoing account before sending." ), + i18n( "Create Account Now?" ), + KGuiItem( i18n( "Create Account Now" ) ) ); if ( response == KMessageBox::Continue ) { - Transport *transport = createTransport(); - TransportConfigDialog *dialog = new TransportConfigDialog( transport, parent ); - dialog->setAttribute( Qt::WA_DeleteOnClose ); - dialog->setWindowModality( Qt::WindowModal ); - if ( ( dialog->exec() == QDialog::Accepted ) && transport->isValid() ) { - addTransport( transport ); - return true; - } else { - delete transport; - } + return showNewTransportDialog( parent ); } return false; } +bool TransportManager::configureTransport( Transport *transport, QWidget *parent ) +{ + if( transport->type() == Transport::EnumType::Akonadi ) { + using namespace Akonadi; + AgentInstance instance = AgentManager::self()->instance( transport->host() ); + if( !instance.isValid() ) { + kWarning() << "Invalid resource instance" << transport->host(); + } + instance.configure( parent ); // Async... + transport->writeConfig(); + return true; // No way to know here if the user cancelled or not. + } + + QPointer dialog = new KDialog( parent ); + TransportConfigWidget *configWidget = 0; + switch( transport->type() ) { + case Transport::EnumType::SMTP: + { + configWidget = new SMTPConfigWidget( transport, dialog ); + break; + } + case Transport::EnumType::Sendmail: + { + configWidget = new SendmailConfigWidget( transport, dialog ); + break; + } + default: + { + Q_ASSERT( false ); + delete dialog; + return false; + } + } + dialog->setMainWidget( configWidget ); + dialog->setCaption( i18n( "Configure account" ) ); + dialog->setButtons( KDialog::Ok | KDialog::Cancel ); + bool okClicked = ( dialog->exec() == QDialog::Accepted ); + if( okClicked ) { + configWidget->apply(); // calls transport->writeConfig() + } + delete dialog; + return okClicked; +} + TransportJob *TransportManager::createTransportJob( int transportId ) { Transport *t = transportById( transportId, false ); if ( !t ) { return 0; } + t = t->clone(); // Jobs delete their transports. + t->updatePasswordState(); switch ( t->type() ) { - case Transport::EnumType::SMTP: - return new SmtpJob( t->clone(), this ); - case Transport::EnumType::Sendmail: - return new SendmailJob( t->clone(), this ); + case Transport::EnumType::SMTP: + return new SmtpJob( t, this ); + case Transport::EnumType::Sendmail: + return new SendmailJob( t, this ); + case Transport::EnumType::Akonadi: + return new ResourceSendJob( t, this ); } Q_ASSERT( false ); return 0; } TransportJob *TransportManager::createTransportJob( const QString &transport ) { bool ok = false; Transport *t = 0; int transportId = transport.toInt( &ok ); if ( ok ) { t = transportById( transportId ); } if ( !t ) { t = transportByName( transport, false ); } if ( t ) { return createTransportJob( t->id() ); } return 0; } bool TransportManager::isEmpty() const { return d->transports.isEmpty(); } QList TransportManager::transportIds() const { QList rv; foreach ( Transport *t, d->transports ) { rv << t->id(); } return rv; } QStringList TransportManager::transportNames() const { QStringList rv; foreach ( Transport *t, d->transports ) { rv << t->name(); } return rv; } QString TransportManager::defaultTransportName() const { Transport *t = transportById( d->defaultTransportId, false ); if ( t ) { return t->name(); } return QString(); } int TransportManager::defaultTransportId() const { return d->defaultTransportId; } void TransportManager::setDefaultTransport( int id ) { if ( id == d->defaultTransportId || !transportById( id, false ) ) { return; } d->defaultTransportId = id; writeConfig(); } void TransportManager::removeTransport( int id ) { Transport *t = transportById( id, false ); if ( !t ) { return; } emit transportRemoved( t->id(), t->name() ); + + // Kill the resource, if Akonadi-type transport. + if( t->type() == Transport::EnumType::Akonadi ) { + using namespace Akonadi; + const AgentInstance instance = AgentManager::self()->instance( t->host() ); + if( !instance.isValid() ) { + kWarning() << "Could not find resource instance."; + } + AgentManager::self()->removeInstance( instance ); + } + d->transports.removeAll( t ); validateDefault(); QString group = t->currentGroup(); delete t; d->config->deleteGroup( group ); writeConfig(); + } void TransportManager::readConfig() { QList oldTransports = d->transports; d->transports.clear(); QRegExp re( QLatin1String( "^Transport (.+)$" ) ); QStringList groups = d->config->groupList().filter( re ); foreach ( const QString &s, groups ) { re.indexIn( s ); Transport *t = 0; // see if we happen to have that one already foreach ( Transport *old, oldTransports ) { if ( old->currentGroup() == QLatin1String( "Transport " ) + re.cap( 1 ) ) { kDebug() << "reloading existing transport:" << s; t = old; t->readConfig(); oldTransports.removeAll( old ); break; } } if ( !t ) { t = new Transport( re.cap( 1 ) ); } if ( t->id() <= 0 ) { t->setId( createId() ); t->writeConfig(); } d->transports.append( t ); } qDeleteAll( oldTransports ); oldTransports.clear(); // read default transport KConfigGroup group( d->config, "General" ); d->defaultTransportId = group.readEntry( "default-transport", 0 ); if ( d->defaultTransportId == 0 ) { // migrated default transport contains the name instead QString name = group.readEntry( "default-transport", QString() ); if ( !name.isEmpty() ) { Transport *t = transportByName( name, false ); if ( t ) { d->defaultTransportId = t->id(); writeConfig(); } } } validateDefault(); migrateToWallet(); } void TransportManager::writeConfig() { KConfigGroup group( d->config, "General" ); group.writeEntry( "default-transport", d->defaultTransportId ); d->config->sync(); emitChangesCommitted(); } +void TransportManager::fillTypes() +{ + Q_ASSERT( d->types.isEmpty() ); + + // SMTP. + { + TransportType type; + type.d->mType = Transport::EnumType::SMTP; + type.d->mName = i18nc( "@option SMTP transport", "SMTP" ); + type.d->mDescription = i18n( "An SMTP server on the internet" ); + d->types << type; + } + + // Sendmail. + { + TransportType type; + type.d->mType = Transport::EnumType::Sendmail; + type.d->mName = i18nc( "@option sendmail transport", "Sendmail" ); + type.d->mDescription = i18n( "A local sendmail installation" ); + d->types << type; + } + + // All Akonadi resources with MailTransport capability. + { + using namespace Akonadi; + foreach ( const AgentType &atype, AgentManager::self()->types() ) { + // TODO probably the string "MailTransport" should be #defined somewhere + // and used like that in the resources (?) + if( atype.capabilities().contains( QLatin1String( "MailTransport" ) ) ) { + TransportType type; + type.d->mType = Transport::EnumType::Akonadi; + type.d->mAgentType = atype; + type.d->mName = atype.name(); + type.d->mDescription = atype.description(); + d->types << type; + kDebug() << "Found Akonadi type" << atype.name(); + } + } + + // Watch for appearing and disappearing types. + connect( AgentManager::self(), SIGNAL(typeAdded(Akonadi::AgentType)), + this, SLOT(agentTypeAdded(Akonadi::AgentType)) ); + connect( AgentManager::self(), SIGNAL(typeRemoved(Akonadi::AgentType)), + this, SLOT(agentTypeRemoved(Akonadi::AgentType)) ); + } + + kDebug() << "Have SMTP, Sendmail, and" << d->types.count() - 2 << "Akonadi types."; +} + void TransportManager::emitChangesCommitted() { d->myOwnChange = true; // prevent us from reading our changes again d->appliedChange = false; // but we have to read them at least once emit transportsChanged(); emit changesCommitted(); } void TransportManager::slotTransportsChanged() { if ( d->myOwnChange && d->appliedChange ) { d->myOwnChange = false; d->appliedChange = false; return; } kDebug(); d->config->reparseConfiguration(); // FIXME: this deletes existing transport objects! readConfig(); d->appliedChange = true; // to prevent recursion emit transportsChanged(); } int TransportManager::createId() const { QList usedIds; foreach ( Transport *t, d->transports ) { usedIds << t->id(); } usedIds << 0; // 0 is default for unknown int newId; do { newId = KRandom::random(); } while ( usedIds.contains( newId ) ); return newId; } KWallet::Wallet * TransportManager::wallet() { if ( d->wallet && d->wallet->isOpen() ) { return d->wallet; } if ( !Wallet::isEnabled() || d->walletOpenFailed ) { return 0; } WId window = 0; if ( qApp->activeWindow() ) { window = qApp->activeWindow()->winId(); } else if ( !QApplication::topLevelWidgets().isEmpty() ) { window = qApp->topLevelWidgets().first()->winId(); } delete d->wallet; d->wallet = Wallet::openWallet( Wallet::NetworkWallet(), window ); if ( !d->wallet ) { d->walletOpenFailed = true; return 0; } prepareWallet(); return d->wallet; } void TransportManager::prepareWallet() { if ( !d->wallet ) { return; } if ( !d->wallet->hasFolder( WALLET_FOLDER ) ) { d->wallet->createFolder( WALLET_FOLDER ); } d->wallet->setFolder( WALLET_FOLDER ); } void TransportManager::loadPasswords() { foreach ( Transport *t, d->transports ) { t->readPassword(); } // flush the wallet queue foreach ( TransportJob *job, d->walletQueue ) { job->start(); } d->walletQueue.clear(); emit passwordsChanged(); } void TransportManager::loadPasswordsAsync() { kDebug(); // check if there is anything to do at all bool found = false; foreach ( Transport *t, d->transports ) { if ( !t->isComplete() ) { found = true; break; } } if ( !found ) { return; } // async wallet opening if ( !d->wallet && !d->walletOpenFailed ) { WId window = 0; if ( qApp->activeWindow() ) { window = qApp->activeWindow()->winId(); } else if ( !QApplication::topLevelWidgets().isEmpty() ) { window = qApp->topLevelWidgets().first()->winId(); } d->wallet = Wallet::openWallet( Wallet::NetworkWallet(), window, Wallet::Asynchronous ); if ( d->wallet ) { connect( d->wallet, SIGNAL(walletOpened(bool)), SLOT(slotWalletOpened(bool)) ); d->walletAsyncOpen = true; } else { d->walletOpenFailed = true; loadPasswords(); } return; } if ( d->wallet && !d->walletAsyncOpen ) { loadPasswords(); } } void TransportManager::slotWalletOpened( bool success ) { kDebug(); d->walletAsyncOpen = false; if ( !success ) { d->walletOpenFailed = true; delete d->wallet; d->wallet = 0; } else { prepareWallet(); } loadPasswords(); } void TransportManager::validateDefault() { if ( !transportById( d->defaultTransportId, false ) ) { if ( isEmpty() ) { d->defaultTransportId = -1; } else { d->defaultTransportId = d->transports.first()->id(); writeConfig(); } } } void TransportManager::migrateToWallet() { // check if we tried this already static bool firstRun = true; if ( !firstRun ) { return; } firstRun = false; // check if we are the main instance if ( !d->isMainInstance ) { return; } // check if migration is needed QStringList names; foreach ( Transport *t, d->transports ) { if ( t->needsWalletMigration() ) { names << t->name(); } } if ( names.isEmpty() ) { return; } // ask user if he wants to migrate int result = KMessageBox::questionYesNoList( 0, i18n( "The following mail transports store their passwords in an " "unencrypted configuration file.\nFor security reasons, " "please consider migrating these passwords to KWallet, the " "KDE Wallet management tool,\nwhich stores sensitive data " "for you in a strongly encrypted file.\n" "Do you want to migrate your passwords to KWallet?" ), names, i18n( "Question" ), KGuiItem( i18n( "Migrate" ) ), KGuiItem( i18n( "Keep" ) ), QString::fromAscii( "WalletMigrate" ) ); if ( result != KMessageBox::Yes ) { return; } // perform migration foreach ( Transport *t, d->transports ) { if ( t->needsWalletMigration() ) { t->migrateToWallet(); } } } void TransportManager::dbusServiceOwnerChanged( const QString &service, const QString &oldOwner, const QString &newOwner ) { Q_UNUSED( oldOwner ); if ( service == DBUS_SERVICE_NAME && newOwner.isEmpty() ) { QDBusConnection::sessionBus().registerService( DBUS_SERVICE_NAME ); } } +void TransportManager::agentTypeAdded( const Akonadi::AgentType &atype ) +{ + using namespace Akonadi; + if( atype.capabilities().contains( QLatin1String( "MailTransport" ) ) ) { + TransportType type; + type.d->mType = Transport::EnumType::Akonadi; + type.d->mAgentType = atype; + type.d->mName = atype.name(); + type.d->mDescription = atype.description(); + d->types << type; + kDebug() << "Added new Akonadi type" << atype.name(); + } +} + +void TransportManager::agentTypeRemoved( const Akonadi::AgentType &atype ) +{ + using namespace Akonadi; + foreach ( const TransportType &type, d->types ) { + if( type.type() == Transport::EnumType::Akonadi && + type.agentType() == atype ) { + d->types.removeAll( type ); + kDebug() << "Removed Akonadi type" << atype.name(); + } + } +} + void TransportManager::jobResult( KJob *job ) { d->walletQueue.removeAll( static_cast( job ) ); } #include "transportmanager.moc" diff --git a/mailtransport/transportmanager.h b/mailtransport/transportmanager.h index e2d228fed..452982e66 100644 --- a/mailtransport/transportmanager.h +++ b/mailtransport/transportmanager.h @@ -1,262 +1,312 @@ /* Copyright (c) 2006 - 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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 MAILTRANSPORT_TRANSPORTMANAGER_H #define MAILTRANSPORT_TRANSPORTMANAGER_H #include +#include #include #include +#include + class KJob; namespace KWallet { class Wallet; } namespace MailTransport { class Transport; +class TransportConfigWidget; class TransportJob; /** - Takes care of loading and storing mail transport settings and - creating of transport jobs. + @short Central transport management interface. + + This class manages the creation, configuration, and removal of mail + transports, as well as the loading and storing of mail transport settings. + + It also handles the creation of transport jobs, although that behaviour is + deprecated and you are encouraged to use MessageQueueJob. + + @see MessageQueueJob. */ class MAILTRANSPORT_EXPORT TransportManager : public QObject { Q_OBJECT Q_CLASSINFO( "D-Bus Interface", "org.kde.pim.TransportManager" ) friend class Transport; friend class Private; public: class Private; /** Destructor. */ virtual ~TransportManager(); /** Returns the TransportManager instance. */ static TransportManager *self(); /** Tries to load passwords asynchronously from KWallet if needed. The passwordsChanged() signal is emitted once the passwords have been loaded. Nothing happens if the passwords were already available. */ void loadPasswordsAsync(); /** Returns the Transport object with the given id. @param id The identifier of the Transport. @param def if set to true, the default transport will be returned if the specified Transport object could not be found, 0 otherwise. @returns A Transport object for immediate use. It might become invalid as soon as the event loop is entered again due to remote changes. If you need to store a Transport object, store the transport identifier instead. */ Transport *transportById( int id, bool def = true ) const; /** Returns the transport object with the given name. @param name The transport name. @param def if set to true, the default transport will be returned if the specified Transport object could not be found, 0 otherwise. @returns A Transport object for immediate use, see transportById() for limitations. */ Transport *transportByName( const QString &name, bool def = true ) const; /** Returns a list of all available transports. Note: The Transport objects become invalid as soon as a change occur, so they are only suitable for immediate use. */ QListtransports() const; + /** + Returns a list of all available transport types. + */ + TransportType::List types() const; + /** Creates a new, empty Transport object. The object is owned by the caller. If you want to add the Transport permanently (eg. after configuring it) call addTransport(). */ Transport *createTransport() const; /** Adds the given transport. The object ownership is transferred to TransportMananger, ie. you must not delete @p transport. @param transport The Transport object to add. */ void addTransport( Transport *transport ); /** Creates a mail transport job for the given transport identifier. Returns 0 if the specified transport is invalid. @param transportId The transport identifier. + + @deprecated use MessageQueueJob to queue messages + and rely on the Dispatcher Agent to send them. */ - TransportJob *createTransportJob( int transportId ); + MAILTRANSPORT_DEPRECATED TransportJob *createTransportJob( int transportId ); /** Creates a mail transport job for the given transport identifer, or transport name. Returns 0 if the specified transport is invalid. @param transport A string defining a mail transport. + + @deprecated use MessageQueueJob to queue messages + and rely on the Dispatcher Agent to send them. */ - TransportJob *createTransportJob( const QString &transport ); + MAILTRANSPORT_DEPRECATED TransportJob *createTransportJob( const QString &transport ); /** Executes the given transport job. This is the preferred way to start transport jobs. It takes care of asynchronously loading passwords from KWallet if necessary. @param job The completely configured transport job to execute. + + @deprecated use MessageQueueJob to queue messages + and rely on the Dispatcher Agent to send them. */ - void schedule( TransportJob *job ); + MAILTRANSPORT_DEPRECATED void schedule( TransportJob *job ); /** Tries to create a transport based on KEMailSettings. If the data in KEMailSettings is incomplete, no transport is created. */ void createDefaultTransport(); /** - Check for an existing transport, and show a configuration dialog if not. - Returns true if transport exists or user creates one. Otherwise false. - @param parent Parent widget of the dialog + Shows a dialog for creating and configuring a new transport. + @param parent Parent widget of the dialog. + @return True if a new transport has been created and configured. @since 4.4 */ - bool checkTransport( QWidget *parent ); + bool showNewTransportDialog( QWidget *parent ); + + /** + If no transport exists, asks the user to create and configure one. + Returns true if a transport exists or the user created one. Otherwise + returns false. + @param parent Parent widget of the dialog. + @since 4.4 + */ + bool promptCreateTransportIfNoneExists( QWidget *parent ); + + /** + Open a configuration dialog for an existing transport. + @param transport The transport to configure. It can be a new transport, + or one already managed by TransportManager. + @param parent The parent widget for the dialog. + @return True if the user clicked Ok, false if the user cancelled. + @since 4.4 + */ + bool configureTransport( Transport *transport, QWidget *parent ); public Q_SLOTS: /** Returns true if there are no mail transports at all. */ Q_SCRIPTABLE bool isEmpty() const; /** Returns a list of transport identifiers. */ Q_SCRIPTABLE QList transportIds() const; /** Returns a list of transport names. */ Q_SCRIPTABLE QStringList transportNames() const; /** Returns the default transport name. */ Q_SCRIPTABLE QString defaultTransportName() const; /** Returns the default transport identifier. Invalid if there are no transports at all. */ Q_SCRIPTABLE int defaultTransportId() const; /** Sets the default transport. The change will be in effect immediately. @param id The identifier of the new default transport. */ Q_SCRIPTABLE void setDefaultTransport( int id ); /** Deletes the specified transport. @param id The identifier of the mail transport to remove. */ Q_SCRIPTABLE void removeTransport( int id ); Q_SIGNALS: /** Emitted when transport settings have changed (by this or any other TransportManager instance). */ Q_SCRIPTABLE void transportsChanged(); /** Internal signal to synchronize all TransportManager instances. This signal is emitted by the instance writing the changes. You probably want to use transportsChanged() instead. */ Q_SCRIPTABLE void changesCommitted(); /** Emitted when passwords have been loaded from the wallet. If you made a deep copy of a transport, you should call updatePasswordState() for the cloned transport to ensure its password is updated as well. */ void passwordsChanged(); /** Emitted when a transport is deleted. @param id The identifier of the deleted transport. @param name The name of the deleted transport. */ void transportRemoved( int id, const QString &name ); /** Emitted when a transport has been renamed. @param id The identifier of the renamed transport. @param oldName The old name. @param newName The new name. */ void transportRenamed( int id, const QString &oldName, const QString &newName ); protected: /** Returns a pointer to an open wallet if available, 0 otherwise. The wallet is opened synchronously if necessary. */ KWallet::Wallet *wallet(); /** Loads all passwords synchronously. */ void loadPasswords(); + /** + Singleton class, the only instance resides in the static object sSelf. + */ TransportManager(); private: void readConfig(); void writeConfig(); + void fillTypes(); void emitChangesCommitted(); int createId() const; void prepareWallet(); void validateDefault(); void migrateToWallet(); private Q_SLOTS: void slotTransportsChanged(); void slotWalletOpened( bool success ); void dbusServiceOwnerChanged( const QString &service, const QString &oldOwner, const QString &newOwner ); + void agentTypeAdded( const Akonadi::AgentType &atype ); + void agentTypeRemoved( const Akonadi::AgentType &atype ); void jobResult( KJob *job ); private: Private *const d; }; -} +} // namespace MailTransport -#endif +#endif // MAILTRANSPORT_TRANSPORTMANAGER_H diff --git a/mailtransport/transporttype.cpp b/mailtransport/transporttype.cpp new file mode 100644 index 000000000..d913a67df --- /dev/null +++ b/mailtransport/transporttype.cpp @@ -0,0 +1,90 @@ +/* + 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 "transporttype.h" +#include "transporttype_p.h" +#include "transport.h" + +#include + +using namespace MailTransport; + +TransportType::TransportType() + : d( new Private ) +{ +} + +TransportType::TransportType( const TransportType &other ) + : d( other.d ) +{ +} + +TransportType::~TransportType() +{ +} + +TransportType &TransportType::operator=( const TransportType &other ) +{ + if( this != &other ) { + d = other.d; + } + return *this; +} + +bool TransportType::operator==( const TransportType &other ) const +{ + if( d->mType == Transport::EnumType::Akonadi && + other.d->mType == Transport::EnumType::Akonadi ) { + return ( d->mAgentType == other.d->mAgentType ); + } + return ( d->mType == other.d->mType ); +} + +bool TransportType::isValid() const +{ + using namespace Akonadi; + + if( d->mType == Transport::EnumType::Akonadi ) { + return d->mAgentType.isValid() && + AgentManager::self()->types().contains( d->mAgentType ); + } else { + return d->mType >= 0; + } +} + +int TransportType::type() const +{ + return d->mType; +} + +QString TransportType::name() const +{ + return d->mName; +} + +QString TransportType::description() const +{ + return d->mDescription; +} + +Akonadi::AgentType TransportType::agentType() const +{ + Q_ASSERT( d->mType == Transport::EnumType::Akonadi ); + return d->mAgentType; +} diff --git a/mailtransport/transporttype.h b/mailtransport/transporttype.h new file mode 100644 index 000000000..03afbd18b --- /dev/null +++ b/mailtransport/transporttype.h @@ -0,0 +1,128 @@ +/* + 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 MAILTRANSPORT_TRANSPORTTYPE_H +#define MAILTRANSPORT_TRANSPORTTYPE_H + +#include "mailtransport_export.h" +#include "transport.h" + +#include + +#include + +namespace MailTransport { + +class AddTransportDialog; +class TransportManager; + +/** + @short A representation of a transport type. + + Represents an available transport type. SMTP and Sendmail are available, + as well as a number of Akonadi-based types. Each Akonadi-based type + corresponds to an Akonadi resource type that supports sending messages. + + This class provides information about the type, such as name and + description. Additionally, for Akonadi types, it provides the corresponding + Akonadi AgentType. + + All available transport types can be retrieved via TransportManager::types(). + + @author Constantin Berzan + @since 4.4 +*/ +class MAILTRANSPORT_EXPORT TransportType +{ + friend class AddTransportDialog; + friend class Transport; + friend class TransportManager; + + public: + /** + Describes a list of transport types. + */ + typedef QList List; + + /** + Constructs a new TransportType. + */ + TransportType(); + + /** + Creates a copy of the @p other TransportType. + */ + TransportType( const TransportType &other ); + + /** + Destroys the TransportType. + */ + ~TransportType(); + + /** + @internal + */ + TransportType &operator=( const TransportType &other ); + + /** + @internal + Compares two transport types. + */ + bool operator==( const TransportType &other ) const; + + /** + Returns whether the transport type is valid. + */ + bool isValid() const; + + /** + @internal + Returns the numeric type of the transport. This corresponds to + Transport::EnumType::type. + */ + // TODO should this be Transport::EnumType::type instead of int? + int type() const; + + /** + Returns the i18n'ed name of the transport type. + */ + QString name() const; + + /** + Returns a description of the transport type. + */ + QString description() const; + + /** + Returns the corresponding Akonadi::AgentType that this transport type + represents. Only valid if type() is Transport::EnumType::Akonadi. + */ + Akonadi::AgentType agentType() const; + + private: + class Private; + QSharedDataPointer d; + +}; + +} // namespace MailTransport + +Q_DECLARE_METATYPE( MailTransport::TransportType ) + +#endif // MAILTRANSPORT_TRANSPORTTYPE_H diff --git a/mailtransport/legacydecrypt.h b/mailtransport/transporttype_p.h similarity index 54% copy from mailtransport/legacydecrypt.h copy to mailtransport/transporttype_p.h index 209a3e9c1..407d191ca 100644 --- a/mailtransport/legacydecrypt.h +++ b/mailtransport/transporttype_p.h @@ -1,49 +1,58 @@ /* - Copyright (c) 2007 Volker Krause - - KNode code: - Copyright (c) 1999-2005 the KNode authors. // krazy:exclude=copyright + 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 MAILTRANSPORT_LEGACYDECRYPT_H -#define MAILTRANSPORT_LEGACYDECRYPT_H +#ifndef MAILTRANSPORT_TRANSPORTTYPE_P_H +#define MAILTRANSPORT_TRANSPORTTYPE_P_H + +#include +#include -#include +#include namespace MailTransport { /** - Methods to read passwords from config files still using legacy encryption. + @internal */ -class Legacy +class TransportType::Private : public QSharedData { public: - /** - Read data encrypted using KMail's legacy encryption. - */ - static QString decryptKMail( const QString &data ); - - /** - Read data encrypted using KNode's legacy encryption. - */ - static QString decryptKNode( const QString &data ); + Private() + { + mType = -1; + } + + Private( const Private &other ) + : QSharedData( other ) + { + mType = other.mType; + mName = other.mName; + mDescription = other.mDescription; + mAgentType = other.mAgentType; + } + + int mType; + QString mName; + QString mDescription; + Akonadi::AgentType mAgentType; }; -} +} // namespace MailTransport -#endif +#endif //MAILTRANSPORT_TRANSPORTTYPE_P_H