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;
286 if( !instance.isValid() ) {
287 kWarning() <<
"Invalid resource instance" << transport->host();
289 instance.configure( parent );
290 transport->writeConfig();
294 QPointer<KDialog> dialog =
new KDialog( parent );
296 switch( transport->type() ) {
297 case Transport::EnumType::SMTP:
302 case Transport::EnumType::Sendmail:
314 dialog->setMainWidget( configWidget );
315 dialog->setCaption( i18n(
"Configure account" ) );
316 dialog->setButtons( KDialog::Ok | KDialog::Cancel );
317 bool okClicked = ( dialog->exec() == QDialog::Accepted );
319 configWidget->
apply();
333 switch ( t->type() ) {
334 case Transport::EnumType::SMTP:
336 case Transport::EnumType::Sendmail:
338 case Transport::EnumType::Akonadi:
350 int transportId = transport.toInt( &ok );
368 return d->transports.isEmpty();
374 foreach (
Transport *t, d->transports ) {
383 foreach (
Transport *t, d->transports ) {
400 return d->defaultTransportId;
405 if (
id == d->defaultTransportId || !
transportById(
id,
false ) ) {
408 d->defaultTransportId = id;
421 if( t->type() == Transport::EnumType::Akonadi ) {
422 using namespace Akonadi;
424 if( !instance.isValid() ) {
425 kWarning() <<
"Could not find resource instance.";
430 d->transports.removeAll( t );
431 d->validateDefault();
432 QString group = t->currentGroup();
434 d->config->deleteGroup( group );
439 void TransportManagerPrivate::readConfig()
441 QList<Transport *> oldTransports =
transports;
444 QRegExp re( QLatin1String(
"^Transport (.+)$" ) );
445 QStringList groups = config->groupList().filter( re );
446 foreach (
const QString &s, groups ) {
451 foreach (
Transport *old, oldTransports ) {
452 if ( old->currentGroup() == QLatin1String(
"Transport " ) + re.cap( 1 ) ) {
453 kDebug() <<
"reloading existing transport:" << s;
455 t->d->passwordNeedsUpdateFromWallet =
true;
457 oldTransports.removeAll( old );
465 if ( t->id() <= 0 ) {
466 t->setId( createId() );
472 qDeleteAll( oldTransports );
473 oldTransports.clear();
476 KConfigGroup group( config,
"General" );
480 QString name = group.readEntry(
"default-transport", QString() );
481 if ( !name.isEmpty() ) {
482 Transport *t = q->transportByName( name,
false );
493 void TransportManagerPrivate::writeConfig()
495 KConfigGroup group( config,
"General" );
498 q->emitChangesCommitted();
501 void TransportManagerPrivate::fillTypes()
503 Q_ASSERT(
types.isEmpty() );
508 type.d->mType = Transport::EnumType::SMTP;
509 type.d->mName = i18nc(
"@option SMTP transport",
"SMTP" );
510 type.d->mDescription = i18n(
"An SMTP server on the Internet" );
517 type.d->mType = Transport::EnumType::Sendmail;
518 type.d->mName = i18nc(
"@option sendmail transport",
"Sendmail" );
519 type.d->mDescription = i18n(
"A local sendmail installation" );
525 using namespace Akonadi;
526 foreach (
const AgentType &atype, AgentManager::self()->
types() ) {
529 if( atype.capabilities().contains( QLatin1String(
"MailTransport" ) ) ) {
531 type.d->mType = Transport::EnumType::Akonadi;
532 type.d->mAgentType = atype;
533 type.d->mName = atype.
name();
536 kDebug() <<
"Found Akonadi type" << atype.
name();
541 QObject::connect( AgentManager::self(), SIGNAL(typeAdded(Akonadi::AgentType)),
542 q, SLOT(agentTypeAdded(Akonadi::AgentType)) );
543 QObject::connect( AgentManager::self(), SIGNAL(typeRemoved(Akonadi::AgentType)),
544 q, SLOT(agentTypeRemoved(Akonadi::AgentType)) );
547 kDebug() <<
"Have SMTP, Sendmail, and" <<
types.count() - 2 <<
"Akonadi types.";
550 void TransportManager::emitChangesCommitted()
552 d->myOwnChange =
true;
553 d->appliedChange =
false;
558 void TransportManagerPrivate::slotTransportsChanged()
560 if ( myOwnChange && appliedChange ) {
562 appliedChange =
false;
567 config->reparseConfiguration();
570 appliedChange =
true;
571 emit q->transportsChanged();
574 int TransportManagerPrivate::createId()
const
583 newId = KRandom::random();
584 }
while ( usedIds.contains( newId ) );
590 if ( d->wallet && d->wallet->isOpen() ) {
594 if ( !Wallet::isEnabled() || d->walletOpenFailed ) {
599 if ( qApp->activeWindow() ) {
600 window = qApp->activeWindow()->winId();
601 }
else if ( !QApplication::topLevelWidgets().
isEmpty() ) {
602 window = qApp->topLevelWidgets().first()->winId();
606 d->wallet = Wallet::openWallet( Wallet::NetworkWallet(), window );
609 d->walletOpenFailed =
true;
617 void TransportManagerPrivate::prepareWallet()
622 if ( !
wallet->hasFolder( WALLET_FOLDER ) ) {
623 wallet->createFolder( WALLET_FOLDER );
625 wallet->setFolder( WALLET_FOLDER );
630 foreach (
Transport *t, d->transports ) {
635 const QList<TransportJob*> copy = d->walletQueue;
636 d->walletQueue.clear();
650 foreach (
Transport *t, d->transports ) {
661 if ( !d->wallet && !d->walletOpenFailed ) {
663 if ( qApp->activeWindow() ) {
664 window = qApp->activeWindow()->winId();
665 }
else if ( !QApplication::topLevelWidgets().
isEmpty() ) {
666 window = qApp->topLevelWidgets().first()->winId();
669 d->wallet = Wallet::openWallet( Wallet::NetworkWallet(), window,
670 Wallet::Asynchronous );
672 connect( d->wallet, SIGNAL(walletOpened(
bool)), SLOT(slotWalletOpened(
bool)) );
673 d->walletAsyncOpen =
true;
675 d->walletOpenFailed =
true;
680 if ( d->wallet && !d->walletAsyncOpen ) {
685 void TransportManagerPrivate::slotWalletOpened(
bool success )
688 walletAsyncOpen =
false;
690 walletOpenFailed =
true;
699 void TransportManagerPrivate::validateDefault()
702 if ( q->isEmpty() ) {
711 void TransportManagerPrivate::migrateToWallet()
714 static bool firstRun =
true;
721 if ( !isMainInstance ) {
732 if ( names.isEmpty() ) {
737 int result = KMessageBox::questionYesNoList(
739 i18n(
"The following mail transports store their passwords in an "
740 "unencrypted configuration file.\nFor security reasons, "
741 "please consider migrating these passwords to KWallet, the "
742 "KDE Wallet management tool,\nwhich stores sensitive data "
743 "for you in a strongly encrypted file.\n"
744 "Do you want to migrate your passwords to KWallet?" ),
745 names, i18n(
"Question" ),
746 KGuiItem( i18n(
"Migrate" ) ), KGuiItem( i18n(
"Keep" ) ),
747 QString::fromAscii(
"WalletMigrate" ) );
748 if ( result != KMessageBox::Yes ) {
760 void TransportManagerPrivate::dbusServiceUnregistered()
762 QDBusConnection::sessionBus().registerService( DBUS_SERVICE_NAME );
765 void TransportManagerPrivate::agentTypeAdded(
const Akonadi::AgentType &atype )
767 using namespace Akonadi;
768 if( atype.capabilities().contains( QLatin1String(
"MailTransport" ) ) ) {
770 type.d->mType = Transport::EnumType::Akonadi;
771 type.d->mAgentType = atype;
772 type.d->mName = atype.
name();
775 kDebug() <<
"Added new Akonadi type" << atype.
name();
779 void TransportManagerPrivate::agentTypeRemoved(
const Akonadi::AgentType &atype )
781 using namespace Akonadi;
783 if( type.
type() == Transport::EnumType::Akonadi &&
785 types.removeAll( type );
786 kDebug() <<
"Removed Akonadi type" << atype.name();
791 void TransportManagerPrivate::jobResult( KJob *job )
793 walletQueue.removeAll( static_cast<TransportJob*>( job ) );
796 #include "transportmanager.moc"