20 #include "transportmanager.h"
21 #include "resourcesendjob_p.h"
23 #include "sendmailjob.h"
25 #include "transport.h"
26 #include "transport_p.h"
27 #include "transportjob.h"
28 #include "transporttype.h"
29 #include "transporttype_p.h"
30 #include "addtransportdialog.h"
31 #include "transportconfigdialog.h"
32 #include "transportconfigwidget.h"
33 #include "sendmailconfigwidget.h"
34 #include "smtpconfigwidget.h"
36 #include <QApplication>
37 #include <QtDBus/QDBusConnection>
38 #include <QtDBus/QDBusConnectionInterface>
39 #include <QtDBus/QDBusServiceWatcher>
42 #include <QStringList>
45 #include <KConfigGroup>
47 #include <KEMailSettings>
49 #include <KLocalizedString>
50 #include <KMessageBox>
53 #include <KWallet/Wallet>
55 #include <akonadi/agentinstance.h>
56 #include <akonadi/agentmanager.h>
58 using namespace MailTransport;
59 using namespace KWallet;
61 namespace MailTransport {
66 class TransportManagerPrivate
74 ~TransportManagerPrivate() {
76 qDeleteAll( transports );
80 QList<Transport *> transports;
84 KWallet::Wallet *wallet;
85 bool walletOpenFailed;
87 int defaultTransportId;
89 QList<TransportJob *> walletQueue;
97 void validateDefault();
98 void migrateToWallet();
101 void slotTransportsChanged();
102 void slotWalletOpened(
bool success );
103 void dbusServiceUnregistered();
104 void agentTypeAdded(
const Akonadi::AgentType &atype );
105 void agentTypeRemoved(
const Akonadi::AgentType &atype );
106 void jobResult( KJob *job );
117 StaticTransportManager *sSelf = 0;
119 static void destroyStaticTransportManager() {
124 : QObject(), d( new TransportManagerPrivate( this ) )
126 KGlobal::locale()->insertCatalog( QLatin1String(
"libmailtransport" ) );
127 KGlobal::locale()->insertCatalog( QLatin1String(
"libakonadi-kmime" ) );
128 qAddPostRoutine( destroyStaticTransportManager );
129 d->myOwnChange =
false;
130 d->appliedChange =
false;
132 d->walletOpenFailed =
false;
133 d->walletAsyncOpen =
false;
134 d->defaultTransportId = -1;
135 d->config =
new KConfig( QLatin1String(
"mailtransports" ) );
137 QDBusConnection::sessionBus().registerObject( DBUS_OBJECT_PATH,
this,
138 QDBusConnection::ExportScriptableSlots |
139 QDBusConnection::ExportScriptableSignals );
141 QDBusServiceWatcher *watcher =
142 new QDBusServiceWatcher( DBUS_SERVICE_NAME, QDBusConnection::sessionBus(),
143 QDBusServiceWatcher::WatchForUnregistration,
this );
144 connect( watcher, SIGNAL(serviceUnregistered(QString)),
145 SLOT(dbusServiceUnregistered()) );
147 QDBusConnection::sessionBus().connect( QString(), QString(),
148 DBUS_INTERFACE_NAME, DBUS_CHANGE_SIGNAL,
149 this, SLOT(slotTransportsChanged()) );
151 d->isMainInstance = QDBusConnection::sessionBus().registerService( DBUS_SERVICE_NAME );
158 qRemovePostRoutine( destroyStaticTransportManager );
165 sSelf =
new StaticTransportManager;
166 sSelf->d->readConfig();
173 foreach (
Transport *t, d->transports ) {
174 if ( t->id() ==
id ) {
179 if ( def || (
id == 0 && d->defaultTransportId !=
id ) ) {
187 foreach (
Transport *t, d->transports ) {
188 if ( t->name() == name ) {
200 return d->transports;
210 int id = d->createId();
218 if ( d->transports.contains( transport ) ) {
219 kDebug() <<
"Already have this transport.";
223 kDebug() <<
"Added transport" << transport;
224 d->transports.append( transport );
225 d->validateDefault();
226 emitChangesCommitted();
231 connect( job, SIGNAL(result(KJob*)), SLOT(jobResult(KJob*)) );
235 kDebug() <<
"job waits for wallet:" << job;
236 d->walletQueue << job;
248 t->setName( i18n(
"Default Transport" ) );
249 t->setHost( kes.getSetting( KEMailSettings::OutServer ) );
254 kWarning() <<
"KEMailSettings does not contain a valid transport.";
266 const int response = KMessageBox::messageBox( parent,
267 KMessageBox::WarningContinueCancel,
268 i18n(
"You must create an outgoing account before sending." ),
269 i18n(
"Create Account Now?" ),
270 KGuiItem( i18n(
"Create Account Now" ) ) );
271 if ( response != KMessageBox::Continue ) {
277 const bool accepted = ( dialog->exec() == QDialog::Accepted );
284 if ( transport->type() == Transport::EnumType::Akonadi ) {
285 using namespace Akonadi;
286 AgentInstance instance = AgentManager::self()->instance( transport->host() );
287 if ( !instance.isValid() ) {
288 kWarning() <<
"Invalid resource instance" << transport->host();
290 instance.configure( parent );
291 transport->writeConfig();
295 QPointer<TransportConfigDialog> transportConfigDialog =
297 transportConfigDialog->setCaption( i18n(
"Configure account" ) );
298 bool okClicked = ( transportConfigDialog->exec() == QDialog::Accepted );
299 delete transportConfigDialog;
311 switch ( t->type() ) {
312 case Transport::EnumType::SMTP:
314 case Transport::EnumType::Sendmail:
316 case Transport::EnumType::Akonadi:
328 int transportId = transport.toInt( &ok );
346 return d->transports.isEmpty();
352 foreach (
Transport *t, d->transports ) {
361 foreach (
Transport *t, d->transports ) {
378 return d->defaultTransportId;
383 if (
id == d->defaultTransportId || !
transportById(
id,
false ) ) {
386 d->defaultTransportId = id;
399 if ( t->type() == Transport::EnumType::Akonadi ) {
400 using namespace Akonadi;
401 const AgentInstance instance = AgentManager::self()->instance( t->host() );
402 if ( !instance.isValid() ) {
403 kWarning() <<
"Could not find resource instance.";
405 AgentManager::self()->removeInstance( instance );
408 d->transports.removeAll( t );
409 d->validateDefault();
410 QString group = t->currentGroup();
411 if (t->storePassword()) {
412 Wallet *currentWallet =
wallet();
413 if ( currentWallet ) {
414 currentWallet->removeEntry( QString::number(t->id()) );
418 d->config->deleteGroup( group );
423 void TransportManagerPrivate::readConfig()
425 QList<Transport *> oldTransports =
transports;
428 QRegExp re( QLatin1String(
"^Transport (.+)$" ) );
429 QStringList groups = config->groupList().filter( re );
430 foreach (
const QString &s, groups ) {
431 if (re.indexIn( s ) == -1)
436 foreach (
Transport *old, oldTransports ) {
437 if ( old->currentGroup() == QLatin1String(
"Transport " ) + re.cap( 1 ) ) {
438 kDebug() <<
"reloading existing transport:" << s;
440 t->d->passwordNeedsUpdateFromWallet =
true;
442 oldTransports.removeAll( old );
450 if ( t->id() <= 0 ) {
451 t->setId( createId() );
457 qDeleteAll( oldTransports );
458 oldTransports.clear();
461 KConfigGroup group( config,
"General" );
465 QString name = group.readEntry(
"default-transport", QString() );
466 if ( !name.isEmpty() ) {
467 Transport *t = q->transportByName( name,
false );
476 q->loadPasswordsAsync();
479 void TransportManagerPrivate::writeConfig()
481 KConfigGroup group( config,
"General" );
484 q->emitChangesCommitted();
487 void TransportManagerPrivate::fillTypes()
489 Q_ASSERT(
types.isEmpty() );
494 type.d->mType = Transport::EnumType::SMTP;
495 type.d->mName = i18nc(
"@option SMTP transport",
"SMTP" );
496 type.d->mDescription = i18n(
"An SMTP server on the Internet" );
503 type.d->mType = Transport::EnumType::Sendmail;
504 type.d->mName = i18nc(
"@option sendmail transport",
"Sendmail" );
505 type.d->mDescription = i18n(
"A local sendmail installation" );
511 using namespace Akonadi;
512 foreach (
const AgentType &atype, AgentManager::self()->
types() ) {
515 if ( atype.capabilities().contains( QLatin1String(
"MailTransport" ) ) ) {
517 type.d->mType = Transport::EnumType::Akonadi;
518 type.d->mAgentType = atype;
519 type.d->mName = atype.
name();
522 kDebug() <<
"Found Akonadi type" << atype.
name();
527 QObject::connect( AgentManager::self(), SIGNAL(typeAdded(Akonadi::AgentType)),
528 q, SLOT(agentTypeAdded(Akonadi::AgentType)) );
529 QObject::connect( AgentManager::self(), SIGNAL(typeRemoved(Akonadi::AgentType)),
530 q, SLOT(agentTypeRemoved(Akonadi::AgentType)) );
533 kDebug() <<
"Have SMTP, Sendmail, and" <<
types.count() - 2 <<
"Akonadi types.";
536 void TransportManager::emitChangesCommitted()
538 d->myOwnChange =
true;
539 d->appliedChange =
false;
544 void TransportManagerPrivate::slotTransportsChanged()
546 if ( myOwnChange && appliedChange ) {
548 appliedChange =
false;
553 config->reparseConfiguration();
556 appliedChange =
true;
557 emit q->transportsChanged();
560 int TransportManagerPrivate::createId()
const
569 newId = KRandom::random();
570 }
while ( usedIds.contains( newId ) );
576 if ( d->wallet && d->wallet->isOpen() ) {
580 if ( !Wallet::isEnabled() || d->walletOpenFailed ) {
585 if ( qApp->activeWindow() ) {
586 window = qApp->activeWindow()->winId();
587 }
else if ( !QApplication::topLevelWidgets().
isEmpty() ) {
588 window = qApp->topLevelWidgets().first()->winId();
592 d->wallet = Wallet::openWallet( Wallet::NetworkWallet(), window );
595 d->walletOpenFailed =
true;
603 void TransportManagerPrivate::prepareWallet()
608 if ( !
wallet->hasFolder( WALLET_FOLDER ) ) {
609 wallet->createFolder( WALLET_FOLDER );
611 wallet->setFolder( WALLET_FOLDER );
616 foreach (
Transport *t, d->transports ) {
621 const QList<TransportJob*> copy = d->walletQueue;
622 d->walletQueue.clear();
636 foreach (
Transport *t, d->transports ) {
647 if ( !d->wallet && !d->walletOpenFailed ) {
649 if ( qApp->activeWindow() ) {
650 window = qApp->activeWindow()->winId();
651 }
else if ( !QApplication::topLevelWidgets().
isEmpty() ) {
652 window = qApp->topLevelWidgets().first()->winId();
655 d->wallet = Wallet::openWallet( Wallet::NetworkWallet(), window,
656 Wallet::Asynchronous );
658 connect( d->wallet, SIGNAL(walletOpened(
bool)), SLOT(slotWalletOpened(
bool)) );
659 d->walletAsyncOpen =
true;
661 d->walletOpenFailed =
true;
666 if ( d->wallet && !d->walletAsyncOpen ) {
671 void TransportManagerPrivate::slotWalletOpened(
bool success )
674 walletAsyncOpen =
false;
676 walletOpenFailed =
true;
685 void TransportManagerPrivate::validateDefault()
688 if ( q->isEmpty() ) {
697 void TransportManagerPrivate::migrateToWallet()
700 static bool firstRun =
true;
707 if ( !isMainInstance ) {
718 if ( names.isEmpty() ) {
723 int result = KMessageBox::questionYesNoList(
725 i18n(
"The following mail transports store their passwords in an "
726 "unencrypted configuration file.\nFor security reasons, "
727 "please consider migrating these passwords to KWallet, the "
728 "KDE Wallet management tool,\nwhich stores sensitive data "
729 "for you in a strongly encrypted file.\n"
730 "Do you want to migrate your passwords to KWallet?" ),
731 names, i18n(
"Question" ),
732 KGuiItem( i18n(
"Migrate" ) ), KGuiItem( i18n(
"Keep" ) ),
733 QString::fromLatin1(
"WalletMigrate" ) );
734 if ( result != KMessageBox::Yes ) {
746 void TransportManagerPrivate::dbusServiceUnregistered()
748 QDBusConnection::sessionBus().registerService( DBUS_SERVICE_NAME );
751 void TransportManagerPrivate::agentTypeAdded(
const Akonadi::AgentType &atype )
753 using namespace Akonadi;
754 if ( atype.capabilities().contains( QLatin1String(
"MailTransport" ) ) ) {
756 type.d->mType = Transport::EnumType::Akonadi;
757 type.d->mAgentType = atype;
758 type.d->mName = atype.
name();
761 kDebug() <<
"Added new Akonadi type" << atype.
name();
765 void TransportManagerPrivate::agentTypeRemoved(
const Akonadi::AgentType &atype )
767 using namespace Akonadi;
769 if ( type.
type() == Transport::EnumType::Akonadi &&
771 types.removeAll( type );
772 kDebug() <<
"Removed Akonadi type" << atype.name();
777 void TransportManagerPrivate::jobResult( KJob *job )
779 walletQueue.removeAll(
static_cast<TransportJob*
>( job ) );
782 #include "moc_transportmanager.cpp"