diff --git a/mailtransport/CMakeLists.txt b/mailtransport/CMakeLists.txt index b647c5af0..1d6aba546 100644 --- a/mailtransport/CMakeLists.txt +++ b/mailtransport/CMakeLists.txt @@ -1,75 +1,77 @@ +set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}" ) + 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 ) 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 akonadijob.cpp sendmailjob.cpp smtpjob.cpp precommandjob.cpp legacydecrypt.cpp socket.cpp servertest.cpp ) kde4_add_ui_files(mailtransport_lib_srcs 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} akonadi-kde) +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 akonadijob.h sendmailjob.h smtpjob.h ${CMAKE_CURRENT_BINARY_DIR}/transportbase.h transport.h transportmanager.h transporttype.h servertest.h transportcombobox.h transportconfigdialog.h transportmanagementwidget.h DESTINATION ${INCLUDE_INSTALL_DIR}/mailtransport COMPONENT Devel) diff --git a/mailtransport/akonadijob.cpp b/mailtransport/akonadijob.cpp index 7e81619db..4e31fa47e 100644 --- a/mailtransport/akonadijob.cpp +++ b/mailtransport/akonadijob.cpp @@ -1,112 +1,186 @@ /* 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 "akonadijob.h" #include "transport.h" #include #include #include #include #include +#include + +#include +#include +#include +#include +#include + using namespace Akonadi; using namespace MailTransport; /** * Private class that helps to provide binary compatibility between releases. * @internal */ class AkonadiJobPrivate { public: + AkonadiJob *q; Item::Id itemId; QDBusInterface *iface; + + // slots + void itemCreateResult( KJob *job ); + void itemFetchResult( KJob *job ); + + void doSend(); }; +void AkonadiJobPrivate::itemCreateResult( KJob *job ) +{ + if( job->error() ) { + // KCompositeJob takes care of the error. + return; + } + + Q_ASSERT( dynamic_cast( job ) ); + itemId = static_cast( job )->item().id(); + kDebug() << "Created item with id" << itemId; + doSend(); +} + +void AkonadiJobPrivate::itemFetchResult( KJob *job ) +{ + if( job->error() ) { + // KCompositeJob takes care of the error. + return; + } + + Q_ASSERT( dynamic_cast( job ) ); + const ItemFetchJob *fjob = static_cast( job ); + Q_ASSERT( fjob->items().count() == 1 ); + const Item item = fjob->items().first(); + if( !item.hasAttribute() ) { + kWarning() << "Item does not have AddressAttribute."; + q->setError( KJob::UserDefinedError ); + q->setErrorText( i18n( "Item does not have address information." ) ); + q->emitResult(); + } else { + kDebug() << "Good, item" << itemId << "has AddressAttribute."; + itemId = item.id(); + doSend(); + } +} + +void AkonadiJobPrivate::doSend() +{ + Q_ASSERT( itemId >= 0 ); + + iface = new QDBusInterface( + QLatin1String( "org.freedesktop.Akonadi.Resource." ) + q->transport()->host(), + QLatin1String( "/" ), QLatin1String( "org.freedesktop.Akonadi.Resource.Transport" ), + QDBusConnection::sessionBus(), q ); + if( !iface->isValid() ) { + q->setError( KJob::UserDefinedError ); + q->setErrorText( i18n( "Failed to get D-Bus interface of resource %1.", q->transport()->host() ) ); + q->emitResult(); + return; + } + + QObject::connect( iface, SIGNAL(transportResult(qlonglong,bool,QString)), + q, SLOT(resourceResult(qlonglong,bool,QString)) ); + + QDBusReply reply = iface->call( QLatin1String( "send" ), itemId ); + if( !reply.isValid() ) { + q->setError( KJob::UserDefinedError ); + q->setErrorText( i18n( "Invalid D-Bus reply from resource %1.", q->transport()->host() ) ); + q->emitResult(); + return; + } +} + AkonadiJob::AkonadiJob( Transport *transport, QObject *parent ) : TransportJob( transport, parent ), d( new AkonadiJobPrivate ) { + d->q = this; d->itemId = -1; d->iface = 0; } -AkonadiJob::~ AkonadiJob() +AkonadiJob::~AkonadiJob() { delete d; } Akonadi::Item::Id AkonadiJob::itemId() const { + if( d->itemId < 0 ) { + kWarning() << "Invalid item."; + } return d->itemId; } void AkonadiJob::setItemId( Akonadi::Item::Id id ) { + Q_ASSERT( id >= 0 ); d->itemId = id; } void AkonadiJob::doStart() { - if( !d->itemId < 0 ) { - // TODO should this check be performed here or somewhere on a higher level? - setError( UserDefinedError ); - setErrorText( i18n( "Asked to send invalid item with id %1.", d->itemId ) ); - emitResult(); - return; - } - - d->iface = new QDBusInterface( - QLatin1String( "org.freedesktop.Akonadi.Resource." ) + transport()->host(), - QLatin1String( "/" ), QLatin1String( "org.freedesktop.Akonadi.Resource.Transport" ), - QDBusConnection::sessionBus(), this ); - if( !d->iface->isValid() ) { - setError( UserDefinedError ); - setErrorText( i18n( "Failed to get D-Bus interface of resource %1.", transport()->host() ) ); - emitResult(); - return; - } - - connect( d->iface, SIGNAL(transportResult(qlonglong,bool,QString)), - this, SLOT(resourceResult(qlonglong,bool,QString)) ); - - // What TODO about timeouts? It is quite possible that the result D-Bus signal - // will get lost, and then what? - - QDBusReply reply = d->iface->call( QLatin1String( "send" ), d->itemId ); - if( !reply.isValid() ) { - setError( UserDefinedError ); - setErrorText( i18n( "Invalid D-Bus reply from resource %1.", transport()->host() ) ); - emitResult(); - return; + if( d->itemId < 0 ) { + // Create the item from TransportJob data. + using namespace KMime; + Item item; + item.setMimeType( QString::fromLatin1( "message/rfc822" ) ); + Message::Ptr msg = Message::Ptr( new Message ); + msg->setContent( data() ); + item.setPayload( msg ); + AddressAttribute *attr = new AddressAttribute( sender(), to(), cc(), bcc() ); + item.addAttribute( attr ); + // FIXME Where should this item be created??? + // And it should probably be deleted afterwards??? + ItemCreateJob *cjob = new ItemCreateJob( item, Collection::root(), this ); + connect( cjob, SIGNAL(result(KJob*)), this, SLOT(itemCreateResult(KJob*)) ); + addSubjob( cjob ); + } else { + // We have a ready-made item. Check that it has an AddressAttribute. + ItemFetchJob *fjob = new ItemFetchJob( Item( d->itemId ), this ); + fjob->fetchScope().fetchFullPayload( false ); + fjob->fetchScope().fetchAttribute(); + connect( fjob, SIGNAL(result(KJob*)), this, SLOT(itemFetchResult(KJob*)) ); + addSubjob( fjob ); } } void AkonadiJob::resourceResult( qlonglong itemId, bool success, const QString &message ) { Q_ASSERT( itemId == d->itemId ); if( !success ) { setError( UserDefinedError ); setErrorText( message ); } emitResult(); } #include "akonadijob.moc" diff --git a/mailtransport/akonadijob.h b/mailtransport/akonadijob.h index 9751320a8..7bcb92afb 100644 --- a/mailtransport/akonadijob.h +++ b/mailtransport/akonadijob.h @@ -1,84 +1,89 @@ /* 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_AKONADIJOB_H #define MAILTRANSPORT_AKONADIJOB_H #include #include class AkonadiJobPrivate; namespace MailTransport { /** Mail transport job for an Akonadi-based transport. - Unlike SmtpJob and SendmailJob, you also need to call setItemId() before - starting this job. In other words, the item you want to send has to be - created in advance. - - TODO API: - * Should we provide setItem or let the job assemble the item out of data()? - * What to do about from, to, cc, bcc? Should there be some kind of standard - attribute containing these? Currently data(), from(), to() etc. are - completely ignored. + + This job can be used in two ways: + 1) If you already have an Akonadi::Item containing the item you want to + send, use the setItem() method. Your item needs to have an + AddressAttribute. You do not need to call setData(), setSender(), + setTo() etc., in fact they are ignored. + 2) If you do not have a ready-made item, call the usual TransportJob methods + setData(), setSender(), setTo() etc. Then AkonadiJob will create a new + Akonadi::Item for you, and give it an AddressAttribute. + FIXME This does not work yet. See comments in doStart(). */ class MAILTRANSPORT_EXPORT AkonadiJob : public TransportJob { Q_OBJECT public: /** Creates an AkonadiJob. @param transport The transport object to use. @param parent The parent object. */ explicit AkonadiJob( Transport *transport, QObject *parent = 0 ); /** Destroys this job. */ virtual ~AkonadiJob(); /** The id of the item to send. */ Akonadi::Item::Id itemId() const; /** Set the id of the item to send. @param itemId id of the item to send */ void setItemId( Akonadi::Item::Id id ); protected: /** reimpl */ virtual void doStart(); private Q_SLOTS: void resourceResult( qlonglong itemId, bool success, const QString &message ); private: + friend class ::AkonadiJobPrivate; AkonadiJobPrivate *const d; + Q_PRIVATE_SLOT( d, void itemCreateResult( KJob* ) ) + Q_PRIVATE_SLOT( d, void itemFetchResult( KJob* ) ) + }; } // namespace MailTransport #endif // MAILTRANSPORT_AKONADIJOB_H