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>
54 #include <KWallet/Wallet>
56 #include <akonadi/agentinstance.h>
57 #include <akonadi/agentmanager.h>
59 using namespace MailTransport;
60 using namespace KWallet;
62 namespace MailTransport {
67 class TransportManagerPrivate
75 ~TransportManagerPrivate() {
77 qDeleteAll( transports );
81 QList<Transport *> transports;
85 KWallet::Wallet *wallet;
86 bool walletOpenFailed;
88 int defaultTransportId;
90 QList<TransportJob *> walletQueue;
98 void validateDefault();
99 void migrateToWallet();
102 void slotTransportsChanged();
103 void slotWalletOpened(
bool success );
104 void dbusServiceUnregistered();
105 void agentTypeAdded(
const Akonadi::AgentType &atype );
106 void agentTypeRemoved(
const Akonadi::AgentType &atype );
107 void jobResult( KJob *job );
118 StaticTransportManager *sSelf = 0;
120 static void destroyStaticTransportManager() {
125 : QObject(), d( new TransportManagerPrivate( this ) )
127 KGlobal::locale()->insertCatalog( QLatin1String(
"libmailtransport" ) );
128 KGlobal::locale()->insertCatalog( QLatin1String(
"libakonadi-kmime" ) );
129 qAddPostRoutine( destroyStaticTransportManager );
130 d->myOwnChange =
false;
131 d->appliedChange =
false;
133 d->walletOpenFailed =
false;
134 d->walletAsyncOpen =
false;
135 d->defaultTransportId = -1;
136 d->config =
new KConfig( QLatin1String(
"mailtransports" ) );
138 QDBusConnection::sessionBus().registerObject( DBUS_OBJECT_PATH,
this,
139 QDBusConnection::ExportScriptableSlots |
140 QDBusConnection::ExportScriptableSignals );
142 QDBusServiceWatcher *watcher =
143 new QDBusServiceWatcher( DBUS_SERVICE_NAME, QDBusConnection::sessionBus(),
144 QDBusServiceWatcher::WatchForUnregistration,
this );
145 connect( watcher, SIGNAL(serviceUnregistered(QString)),
146 SLOT(dbusServiceUnregistered()) );
148 QDBusConnection::sessionBus().connect( QString(), QString(),
149 DBUS_INTERFACE_NAME, DBUS_CHANGE_SIGNAL,
150 this, SLOT(slotTransportsChanged()) );
152 d->isMainInstance = QDBusConnection::sessionBus().registerService( DBUS_SERVICE_NAME );
159 qRemovePostRoutine( destroyStaticTransportManager );
166 sSelf =
new StaticTransportManager;
167 sSelf->d->readConfig();
174 foreach (
Transport *t, d->transports ) {
175 if ( t->id() == id ) {
180 if ( def || (
id == 0 && d->defaultTransportId !=
id ) ) {
188 foreach (
Transport *t, d->transports ) {
189 if ( t->name() == name ) {
201 return d->transports;
211 int id = d->createId();
219 if ( d->transports.contains( transport ) ) {
220 kDebug() <<
"Already have this transport.";
224 kDebug() <<
"Added transport" << transport;
225 d->transports.append( transport );
226 d->validateDefault();
227 emitChangesCommitted();
232 connect( job, SIGNAL(result(KJob*)), SLOT(jobResult(KJob*)) );
236 kDebug() <<
"job waits for wallet:" << job;
237 d->walletQueue << job;
249 t->setName( i18n(
"Default Transport" ) );
250 t->setHost( kes.getSetting( KEMailSettings::OutServer ) );
255 kWarning() <<
"KEMailSettings does not contain a valid transport.";
267 const int response = KMessageBox::messageBox( parent,
268 KMessageBox::WarningContinueCancel,
269 i18n(
"You must create an outgoing account before sending." ),
270 i18n(
"Create Account Now?" ),
271 KGuiItem( i18n(
"Create Account Now" ) ) );
272 if ( response != KMessageBox::Continue ) {
278 const bool accepted = ( dialog->exec() == QDialog::Accepted );
285 if ( transport->type() == Transport::EnumType::Akonadi ) {
286 using namespace Akonadi;
287 AgentInstance instance = AgentManager::self()->instance( transport->host() );
288 if ( !instance.isValid() ) {
289 kWarning() <<
"Invalid resource instance" << transport->host();
291 instance.configure( parent );
292 transport->writeConfig();
296 QPointer<TransportConfigDialog> transportConfigDialog =
298 transportConfigDialog->setCaption( i18n(
"Configure account" ) );
299 bool okClicked = ( transportConfigDialog->exec() == QDialog::Accepted );
300 delete transportConfigDialog;
312 switch ( t->type() ) {
313 case Transport::EnumType::SMTP:
315 case Transport::EnumType::Sendmail:
317 case Transport::EnumType::Akonadi:
329 int transportId = transport.toInt( &ok );
347 return d->transports.isEmpty();
353 foreach (
Transport *t, d->transports ) {
362 foreach (
Transport *t, d->transports ) {
379 return d->defaultTransportId;
384 if (
id == d->defaultTransportId || !
transportById(
id,
false ) ) {
387 d->defaultTransportId = id;
400 if ( t->type() == Transport::EnumType::Akonadi ) {
401 using namespace Akonadi;
402 const AgentInstance instance = AgentManager::self()->instance( t->host() );
403 if ( !instance.isValid() ) {
404 kWarning() <<
"Could not find resource instance.";
406 AgentManager::self()->removeInstance( instance );
409 d->transports.removeAll( t );
410 d->validateDefault();
411 QString group = t->currentGroup();
413 d->config->deleteGroup( group );
418 void TransportManagerPrivate::readConfig()
420 QList<Transport *> oldTransports =
transports;
423 QRegExp re( QLatin1String(
"^Transport (.+)$" ) );
424 QStringList groups = config->groupList().filter( re );
425 foreach (
const QString &s, groups ) {
430 foreach (
Transport *old, oldTransports ) {
431 if ( old->currentGroup() == QLatin1String(
"Transport " ) + re.cap( 1 ) ) {
432 kDebug() <<
"reloading existing transport:" << s;
434 t->d->passwordNeedsUpdateFromWallet =
true;
436 oldTransports.removeAll( old );
444 if ( t->id() <= 0 ) {
445 t->setId( createId() );
451 qDeleteAll( oldTransports );
452 oldTransports.clear();
455 KConfigGroup group( config,
"General" );
459 QString name = group.readEntry(
"default-transport", QString() );
460 if ( !name.isEmpty() ) {
461 Transport *t = q->transportByName( name,
false );
470 q->loadPasswordsAsync();
473 void TransportManagerPrivate::writeConfig()
475 KConfigGroup group( config,
"General" );
478 q->emitChangesCommitted();
481 void TransportManagerPrivate::fillTypes()
483 Q_ASSERT(
types.isEmpty() );
488 type.d->mType = Transport::EnumType::SMTP;
489 type.d->mName = i18nc(
"@option SMTP transport",
"SMTP" );
490 type.d->mDescription = i18n(
"An SMTP server on the Internet" );
497 type.d->mType = Transport::EnumType::Sendmail;
498 type.d->mName = i18nc(
"@option sendmail transport",
"Sendmail" );
499 type.d->mDescription = i18n(
"A local sendmail installation" );
505 using namespace Akonadi;
506 foreach (
const AgentType &atype, AgentManager::self()->
types() ) {
509 if ( atype.capabilities().contains( QLatin1String(
"MailTransport" ) ) ) {
511 type.d->mType = Transport::EnumType::Akonadi;
512 type.d->mAgentType = atype;
513 type.d->mName = atype.
name();
516 kDebug() <<
"Found Akonadi type" << atype.
name();
521 QObject::connect( AgentManager::self(), SIGNAL(typeAdded(Akonadi::AgentType)),
522 q, SLOT(agentTypeAdded(Akonadi::AgentType)) );
523 QObject::connect( AgentManager::self(), SIGNAL(typeRemoved(Akonadi::AgentType)),
524 q, SLOT(agentTypeRemoved(Akonadi::AgentType)) );
527 kDebug() <<
"Have SMTP, Sendmail, and" <<
types.count() - 2 <<
"Akonadi types.";
530 void TransportManager::emitChangesCommitted()
532 d->myOwnChange =
true;
533 d->appliedChange =
false;
538 void TransportManagerPrivate::slotTransportsChanged()
540 if ( myOwnChange && appliedChange ) {
542 appliedChange =
false;
547 config->reparseConfiguration();
550 appliedChange =
true;
551 emit q->transportsChanged();
554 int TransportManagerPrivate::createId()
const
563 newId = KRandom::random();
564 }
while ( usedIds.contains( newId ) );
570 if ( d->wallet && d->wallet->isOpen() ) {
574 if ( !Wallet::isEnabled() || d->walletOpenFailed ) {
579 if ( qApp->activeWindow() ) {
580 window = qApp->activeWindow()->winId();
581 }
else if ( !QApplication::topLevelWidgets().
isEmpty() ) {
582 window = qApp->topLevelWidgets().first()->winId();
586 d->wallet = Wallet::openWallet( Wallet::NetworkWallet(), window );
589 d->walletOpenFailed =
true;
597 void TransportManagerPrivate::prepareWallet()
602 if ( !
wallet->hasFolder( WALLET_FOLDER ) ) {
603 wallet->createFolder( WALLET_FOLDER );
605 wallet->setFolder( WALLET_FOLDER );
610 foreach (
Transport *t, d->transports ) {
615 const QList<TransportJob*> copy = d->walletQueue;
616 d->walletQueue.clear();
630 foreach (
Transport *t, d->transports ) {
641 if ( !d->wallet && !d->walletOpenFailed ) {
643 if ( qApp->activeWindow() ) {
644 window = qApp->activeWindow()->winId();
645 }
else if ( !QApplication::topLevelWidgets().
isEmpty() ) {
646 window = qApp->topLevelWidgets().first()->winId();
649 d->wallet = Wallet::openWallet( Wallet::NetworkWallet(), window,
650 Wallet::Asynchronous );
652 connect( d->wallet, SIGNAL(walletOpened(
bool)), SLOT(slotWalletOpened(
bool)) );
653 d->walletAsyncOpen =
true;
655 d->walletOpenFailed =
true;
660 if ( d->wallet && !d->walletAsyncOpen ) {
665 void TransportManagerPrivate::slotWalletOpened(
bool success )
668 walletAsyncOpen =
false;
670 walletOpenFailed =
true;
679 void TransportManagerPrivate::validateDefault()
682 if ( q->isEmpty() ) {
691 void TransportManagerPrivate::migrateToWallet()
694 static bool firstRun =
true;
701 if ( !isMainInstance ) {
712 if ( names.isEmpty() ) {
717 int result = KMessageBox::questionYesNoList(
719 i18n(
"The following mail transports store their passwords in an "
720 "unencrypted configuration file.\nFor security reasons, "
721 "please consider migrating these passwords to KWallet, the "
722 "KDE Wallet management tool,\nwhich stores sensitive data "
723 "for you in a strongly encrypted file.\n"
724 "Do you want to migrate your passwords to KWallet?" ),
725 names, i18n(
"Question" ),
726 KGuiItem( i18n(
"Migrate" ) ), KGuiItem( i18n(
"Keep" ) ),
727 QString::fromLatin1(
"WalletMigrate" ) );
728 if ( result != KMessageBox::Yes ) {
740 void TransportManagerPrivate::dbusServiceUnregistered()
742 QDBusConnection::sessionBus().registerService( DBUS_SERVICE_NAME );
745 void TransportManagerPrivate::agentTypeAdded(
const Akonadi::AgentType &atype )
747 using namespace Akonadi;
748 if ( atype.capabilities().contains( QLatin1String(
"MailTransport" ) ) ) {
750 type.d->mType = Transport::EnumType::Akonadi;
751 type.d->mAgentType = atype;
752 type.d->mName = atype.
name();
755 kDebug() <<
"Added new Akonadi type" << atype.
name();
759 void TransportManagerPrivate::agentTypeRemoved(
const Akonadi::AgentType &atype )
761 using namespace Akonadi;
763 if ( type.
type() == Transport::EnumType::Akonadi &&
765 types.removeAll( type );
766 kDebug() <<
"Removed Akonadi type" << atype.name();
771 void TransportManagerPrivate::jobResult( KJob *job )
773 walletQueue.removeAll( static_cast<TransportJob*>( job ) );
776 #include "moc_transportmanager.cpp"