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 <KMessageBox>
52 #include <KWallet/Wallet>
54 #include <akonadi/agentinstance.h>
55 #include <akonadi/agentmanager.h>
57 using namespace MailTransport;
58 using namespace KWallet;
60 namespace MailTransport {
65 class TransportManagerPrivate
73 ~TransportManagerPrivate() {
75 qDeleteAll( transports );
79 QList<Transport *> transports;
83 KWallet::Wallet *wallet;
84 bool walletOpenFailed;
86 int defaultTransportId;
88 QList<TransportJob *> walletQueue;
96 void validateDefault();
97 void migrateToWallet();
100 void slotTransportsChanged();
101 void slotWalletOpened(
bool success );
102 void dbusServiceUnregistered();
103 void agentTypeAdded(
const Akonadi::AgentType &atype );
104 void agentTypeRemoved(
const Akonadi::AgentType &atype );
105 void jobResult( KJob *job );
116 StaticTransportManager *sSelf = 0;
118 static void destroyStaticTransportManager() {
123 : QObject(), d( new TransportManagerPrivate( this ) )
125 KGlobal::locale()->insertCatalog( QLatin1String(
"libmailtransport" ) );
126 KGlobal::locale()->insertCatalog( QLatin1String(
"libakonadi-kmime" ) );
127 qAddPostRoutine( destroyStaticTransportManager );
128 d->myOwnChange =
false;
129 d->appliedChange =
false;
131 d->walletOpenFailed =
false;
132 d->walletAsyncOpen =
false;
133 d->defaultTransportId = -1;
134 d->config =
new KConfig( QLatin1String(
"mailtransports" ) );
136 QDBusConnection::sessionBus().registerObject( DBUS_OBJECT_PATH,
this,
137 QDBusConnection::ExportScriptableSlots |
138 QDBusConnection::ExportScriptableSignals );
140 QDBusServiceWatcher *watcher =
141 new QDBusServiceWatcher( DBUS_SERVICE_NAME, QDBusConnection::sessionBus(),
142 QDBusServiceWatcher::WatchForUnregistration,
this );
143 connect( watcher, SIGNAL(serviceUnregistered(QString)),
144 SLOT(dbusServiceUnregistered()) );
146 QDBusConnection::sessionBus().connect( QString(), QString(),
147 DBUS_INTERFACE_NAME, DBUS_CHANGE_SIGNAL,
148 this, SLOT(slotTransportsChanged()) );
150 d->isMainInstance = QDBusConnection::sessionBus().registerService( DBUS_SERVICE_NAME );
157 qRemovePostRoutine( destroyStaticTransportManager );
164 sSelf =
new StaticTransportManager;
165 sSelf->d->readConfig();
172 foreach (
Transport *t, d->transports ) {
173 if ( t->id() == id ) {
178 if ( def || (
id == 0 && d->defaultTransportId !=
id ) ) {
186 foreach (
Transport *t, d->transports ) {
187 if ( t->name() == name ) {
199 return d->transports;
209 int id = d->createId();
217 if ( d->transports.contains( transport ) ) {
218 kDebug() <<
"Already have this transport.";
222 kDebug() <<
"Added transport" << transport;
223 d->transports.append( transport );
224 d->validateDefault();
225 emitChangesCommitted();
230 connect( job, SIGNAL(result(KJob*)), SLOT(jobResult(KJob*)) );
234 kDebug() <<
"job waits for wallet:" << job;
235 d->walletQueue << job;
247 t->setName( i18n(
"Default Transport" ) );
248 t->setHost( kes.getSetting( KEMailSettings::OutServer ) );
253 kWarning() <<
"KEMailSettings does not contain a valid transport.";
265 const int response = KMessageBox::messageBox( parent,
266 KMessageBox::WarningContinueCancel,
267 i18n(
"You must create an outgoing account before sending." ),
268 i18n(
"Create Account Now?" ),
269 KGuiItem( i18n(
"Create Account Now" ) ) );
270 if ( response != KMessageBox::Continue ) {
276 const bool accepted = ( dialog->exec() == QDialog::Accepted );
283 if ( transport->type() == Transport::EnumType::Akonadi ) {
284 using namespace Akonadi;
285 AgentInstance instance = AgentManager::self()->instance( transport->host() );
286 if ( !instance.isValid() ) {
287 kWarning() <<
"Invalid resource instance" << transport->host();
289 instance.configure( parent );
290 transport->writeConfig();
294 QPointer<TransportConfigDialog> transportConfigDialog =
new TransportConfigDialog(transport, parent);
295 transportConfigDialog->setCaption( i18n(
"Configure account" ) );
296 bool okClicked = ( transportConfigDialog->exec() == QDialog::Accepted );
297 delete transportConfigDialog;
309 switch ( t->type() ) {
310 case Transport::EnumType::SMTP:
312 case Transport::EnumType::Sendmail:
314 case Transport::EnumType::Akonadi:
326 int transportId = transport.toInt( &ok );
344 return d->transports.isEmpty();
350 foreach (
Transport *t, d->transports ) {
359 foreach (
Transport *t, d->transports ) {
376 return d->defaultTransportId;
381 if (
id == d->defaultTransportId || !
transportById(
id,
false ) ) {
384 d->defaultTransportId = id;
397 if ( t->type() == Transport::EnumType::Akonadi ) {
398 using namespace Akonadi;
399 const AgentInstance instance = AgentManager::self()->instance( t->host() );
400 if ( !instance.isValid() ) {
401 kWarning() <<
"Could not find resource instance.";
403 AgentManager::self()->removeInstance( instance );
406 d->transports.removeAll( t );
407 d->validateDefault();
408 QString group = t->currentGroup();
410 d->config->deleteGroup( group );
415 void TransportManagerPrivate::readConfig()
417 QList<Transport *> oldTransports =
transports;
420 QRegExp re( QLatin1String(
"^Transport (.+)$" ) );
421 QStringList groups = config->groupList().filter( re );
422 foreach (
const QString &s, groups ) {
427 foreach (
Transport *old, oldTransports ) {
428 if ( old->currentGroup() == QLatin1String(
"Transport " ) + re.cap( 1 ) ) {
429 kDebug() <<
"reloading existing transport:" << s;
431 t->d->passwordNeedsUpdateFromWallet =
true;
433 oldTransports.removeAll( old );
441 if ( t->id() <= 0 ) {
442 t->setId( createId() );
448 qDeleteAll( oldTransports );
449 oldTransports.clear();
452 KConfigGroup group( config,
"General" );
456 QString name = group.readEntry(
"default-transport", QString() );
457 if ( !name.isEmpty() ) {
458 Transport *t = q->transportByName( name,
false );
467 q->loadPasswordsAsync();
470 void TransportManagerPrivate::writeConfig()
472 KConfigGroup group( config,
"General" );
475 q->emitChangesCommitted();
478 void TransportManagerPrivate::fillTypes()
480 Q_ASSERT(
types.isEmpty() );
485 type.d->mType = Transport::EnumType::SMTP;
486 type.d->mName = i18nc(
"@option SMTP transport",
"SMTP" );
487 type.d->mDescription = i18n(
"An SMTP server on the Internet" );
494 type.d->mType = Transport::EnumType::Sendmail;
495 type.d->mName = i18nc(
"@option sendmail transport",
"Sendmail" );
496 type.d->mDescription = i18n(
"A local sendmail installation" );
502 using namespace Akonadi;
503 foreach (
const AgentType &atype, AgentManager::self()->
types() ) {
506 if ( atype.capabilities().contains( QLatin1String(
"MailTransport" ) ) ) {
508 type.d->mType = Transport::EnumType::Akonadi;
509 type.d->mAgentType = atype;
510 type.d->mName = atype.
name();
513 kDebug() <<
"Found Akonadi type" << atype.
name();
518 QObject::connect( AgentManager::self(), SIGNAL(typeAdded(Akonadi::AgentType)),
519 q, SLOT(agentTypeAdded(Akonadi::AgentType)) );
520 QObject::connect( AgentManager::self(), SIGNAL(typeRemoved(Akonadi::AgentType)),
521 q, SLOT(agentTypeRemoved(Akonadi::AgentType)) );
524 kDebug() <<
"Have SMTP, Sendmail, and" <<
types.count() - 2 <<
"Akonadi types.";
527 void TransportManager::emitChangesCommitted()
529 d->myOwnChange =
true;
530 d->appliedChange =
false;
535 void TransportManagerPrivate::slotTransportsChanged()
537 if ( myOwnChange && appliedChange ) {
539 appliedChange =
false;
544 config->reparseConfiguration();
547 appliedChange =
true;
548 emit q->transportsChanged();
551 int TransportManagerPrivate::createId()
const
560 newId = KRandom::random();
561 }
while ( usedIds.contains( newId ) );
567 if ( d->wallet && d->wallet->isOpen() ) {
571 if ( !Wallet::isEnabled() || d->walletOpenFailed ) {
576 if ( qApp->activeWindow() ) {
577 window = qApp->activeWindow()->winId();
578 }
else if ( !QApplication::topLevelWidgets().
isEmpty() ) {
579 window = qApp->topLevelWidgets().first()->winId();
583 d->wallet = Wallet::openWallet( Wallet::NetworkWallet(), window );
586 d->walletOpenFailed =
true;
594 void TransportManagerPrivate::prepareWallet()
599 if ( !
wallet->hasFolder( WALLET_FOLDER ) ) {
600 wallet->createFolder( WALLET_FOLDER );
602 wallet->setFolder( WALLET_FOLDER );
607 foreach (
Transport *t, d->transports ) {
612 const QList<TransportJob*> copy = d->walletQueue;
613 d->walletQueue.clear();
627 foreach (
Transport *t, d->transports ) {
638 if ( !d->wallet && !d->walletOpenFailed ) {
640 if ( qApp->activeWindow() ) {
641 window = qApp->activeWindow()->winId();
642 }
else if ( !QApplication::topLevelWidgets().
isEmpty() ) {
643 window = qApp->topLevelWidgets().first()->winId();
646 d->wallet = Wallet::openWallet( Wallet::NetworkWallet(), window,
647 Wallet::Asynchronous );
649 connect( d->wallet, SIGNAL(walletOpened(
bool)), SLOT(slotWalletOpened(
bool)) );
650 d->walletAsyncOpen =
true;
652 d->walletOpenFailed =
true;
657 if ( d->wallet && !d->walletAsyncOpen ) {
662 void TransportManagerPrivate::slotWalletOpened(
bool success )
665 walletAsyncOpen =
false;
667 walletOpenFailed =
true;
676 void TransportManagerPrivate::validateDefault()
679 if ( q->isEmpty() ) {
688 void TransportManagerPrivate::migrateToWallet()
691 static bool firstRun =
true;
698 if ( !isMainInstance ) {
709 if ( names.isEmpty() ) {
714 int result = KMessageBox::questionYesNoList(
716 i18n(
"The following mail transports store their passwords in an "
717 "unencrypted configuration file.\nFor security reasons, "
718 "please consider migrating these passwords to KWallet, the "
719 "KDE Wallet management tool,\nwhich stores sensitive data "
720 "for you in a strongly encrypted file.\n"
721 "Do you want to migrate your passwords to KWallet?" ),
722 names, i18n(
"Question" ),
723 KGuiItem( i18n(
"Migrate" ) ), KGuiItem( i18n(
"Keep" ) ),
724 QString::fromLatin1(
"WalletMigrate" ) );
725 if ( result != KMessageBox::Yes ) {
737 void TransportManagerPrivate::dbusServiceUnregistered()
739 QDBusConnection::sessionBus().registerService( DBUS_SERVICE_NAME );
742 void TransportManagerPrivate::agentTypeAdded(
const Akonadi::AgentType &atype )
744 using namespace Akonadi;
745 if ( atype.capabilities().contains( QLatin1String(
"MailTransport" ) ) ) {
747 type.d->mType = Transport::EnumType::Akonadi;
748 type.d->mAgentType = atype;
749 type.d->mName = atype.
name();
752 kDebug() <<
"Added new Akonadi type" << atype.
name();
756 void TransportManagerPrivate::agentTypeRemoved(
const Akonadi::AgentType &atype )
758 using namespace Akonadi;
760 if ( type.
type() == Transport::EnumType::Akonadi &&
762 types.removeAll( type );
763 kDebug() <<
"Removed Akonadi type" << atype.name();
768 void TransportManagerPrivate::jobResult( KJob *job )
770 walletQueue.removeAll( static_cast<TransportJob*>( job ) );
773 #include "moc_transportmanager.cpp"