Commit 6ad5d6b5 authored by Constantin Berzan's avatar Constantin Berzan

* Move OutboxInterface into MailTransport. This was done because (1) they are...

* Move OutboxInterface into MailTransport.  This was done because (1) they are related and (2) a circular dependency would be needed to make resource-based transport jobs work.
* Mark everything related to transport jobs in MT deprecated.  The stuff is meant to be used by the MDA only, and will be moved to the MDA in KDE5.
* Fix bug where transports created by TransportManager::createTransportJob() would not be aware of their passwords.
* Rename AkonadiJob to ResourceSendJob to avoid confusion.  This class is just a wrapper around MessageQueueJob, and it is the MDA who actually forwards the item to the resource responsible for sending it.  (see DESIGN file)

svn path=/branches/work/akonadi-ports/kdepimlibs/; revision=994693
parent 51917e1c
......@@ -9,6 +9,7 @@ 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
......@@ -26,7 +27,7 @@ set(mailtransport_lib_srcs
smtpconfigwidget.cpp
transportjob.cpp
akonadijob.cpp
resourcesendjob.cpp
sendmailjob.cpp
smtpjob.cpp
precommandjob.cpp
......@@ -34,6 +35,16 @@ set(mailtransport_lib_srcs
legacydecrypt.cpp
socket.cpp
servertest.cpp
dispatcherinterface.cpp
messagequeuejob.cpp
outboxactions.cpp
attributeregistrar.cpp
dispatchmodeattribute.cpp
errorattribute.cpp
sentbehaviourattribute.cpp
transportattribute.cpp
)
......@@ -63,7 +74,7 @@ install( FILES
mailtransport_export.h
transportjob.h
akonadijob.h
resourcesendjob.h
sendmailjob.h
smtpjob.h
......@@ -77,5 +88,14 @@ install( FILES
transportconfigdialog.h
transportmanagementwidget.h
dispatcherinterface.h
messagequeuejob.h
outboxactions.h
dispatchmodeattribute.h
errorattribute.h
sentbehaviourattribute.h
transportattribute.h
DESTINATION ${INCLUDE_INSTALL_DIR}/mailtransport COMPONENT Devel)
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)
/*
Copyright (c) 2009 Constantin Berzan <exit3219@gmail.com>
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 <QDBusConnection>
#include <QDBusConnectionInterface>
#include <QDBusInterface>
#include <QString>
#include <KLocalizedString>
#include <kmime/kmime_message.h>
#include <akonadi/collection.h>
#include <akonadi/itemcreatejob.h>
#include <akonadi/itemfetchjob.h>
#include <akonadi/itemfetchscope.h>
#include <akonadi/kmime/addressattribute.h>
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<ItemCreateJob*>( job ) );
itemId = static_cast<ItemCreateJob*>( 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<ItemFetchJob*>( job ) );
const ItemFetchJob *fjob = static_cast<ItemFetchJob*>( job );
Q_ASSERT( fjob->items().count() == 1 );
const Item item = fjob->items().first();
if( !item.hasAttribute<AddressAttribute>() ) {
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<void> 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()
{
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 ) {
// 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<Message::Ptr>( 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<AddressAttribute>();
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"
/*
Copyright (c) 2009 Constantin Berzan <exit3219@gmail.com>
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 "errorattribute.h"
#include "sentbehaviourattribute.h"
#include "transportattribute.h"
#include <akonadi/attributefactory.h>
namespace {
// Anonymous namespace; function is invisible outside this file.
bool dummy()
{
using namespace Akonadi;
using namespace MailTransport;
AttributeFactory::registerAttribute<DispatchModeAttribute>();
AttributeFactory::registerAttribute<ErrorAttribute>();
AttributeFactory::registerAttribute<SentBehaviourAttribute>();
AttributeFactory::registerAttribute<TransportAttribute>();
return true;
}
// Called when this library is loaded.
const bool registered = dummy();
} // namespace
/*
Copyright (c) 2009 Constantin Berzan <exit3219@gmail.com>
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 <KDebug>
#include <KGlobal>
#include <KLocalizedString>
#include <akonadi/agentmanager.h>
#include <akonadi/collection.h>
#include <akonadi/filteractionjob.h>
#include <akonadi/kmime/localfolders.h>
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"
/*
Copyright (c) 2009 Constantin Berzan <exit3219@gmail.com>
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 <mailtransport/mailtransport_export.h>
#include <QtCore/QObject>
#include <akonadi/agentinstance.h>
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 <exit3219@gmail.com>
@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
/*
Copyright 2009 Constantin Berzan <exit3219@gmail.com>
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 <KDebug>
#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;
}
/*
Copyright 2009 Constantin Berzan <exit3219@gmail.com>
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.