00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "transportmanager.h"
00021 #include "mailtransport_defs.h"
00022 #include "transport.h"
00023 #include "smtpjob.h"
00024 #include "sendmailjob.h"
00025
00026 #include <kconfig.h>
00027 #include <kdebug.h>
00028 #include <kemailsettings.h>
00029 #include <klocale.h>
00030 #include <kmessagebox.h>
00031 #include <krandom.h>
00032 #include <kurl.h>
00033 #include <kwallet.h>
00034 #include <kconfiggroup.h>
00035
00036 #include <QApplication>
00037 #include <QtDBus/QDBusConnection>
00038 #include <QtDBus/QDBusConnectionInterface>
00039 #include <QRegExp>
00040 #include <QStringList>
00041
00042 using namespace MailTransport;
00043 using namespace KWallet;
00044
00049 class TransportManager::Private {
00050 public:
00051 ~Private() {
00052 qRemovePostRoutine(cleanupTransportManager);
00053 cleanupTransportManager();
00054 }
00055 KConfig *config;
00056 QList<Transport*> transports;
00057 bool myOwnChange;
00058 KWallet::Wallet *wallet;
00059 bool walletOpenFailed;
00060 bool walletAsyncOpen;
00061 int defaultTransportId;
00062 bool isMainInstance;
00063 QList<TransportJob*> walletQueue;
00064
00065 static TransportManager *sSelf;
00066 static void cleanupTransportManager()
00067 {
00068 delete sSelf;
00069 sSelf = 0;
00070 }
00071 };
00072 TransportManager *TransportManager::Private::sSelf = 0;
00073
00074 TransportManager::TransportManager() :
00075 QObject(), d( new Private )
00076 {
00077 d->myOwnChange = false;
00078 d->wallet = 0;
00079 d->walletOpenFailed = false;
00080 d->walletAsyncOpen = false;
00081 d->defaultTransportId = -1;
00082 d->config = new KConfig( QLatin1String("mailtransports") );
00083
00084 QDBusConnection::sessionBus().registerObject( DBUS_OBJECT_PATH, this,
00085 QDBusConnection::ExportScriptableSlots |
00086 QDBusConnection::ExportScriptableSignals );
00087
00088 QDBusConnection::sessionBus().connect( QString(), QString(),
00089 DBUS_INTERFACE_NAME, DBUS_CHANGE_SIGNAL,
00090 this, SLOT(slotTransportsChanged()) );
00091
00092 d->isMainInstance =
00093 QDBusConnection::sessionBus().registerService( DBUS_SERVICE_NAME );
00094 connect( QDBusConnection::sessionBus().interface(),
00095 SIGNAL(serviceOwnerChanged(QString,QString,QString)),
00096 SLOT(dbusServiceOwnerChanged(QString,QString,QString)) );
00097 }
00098
00099 TransportManager::~TransportManager()
00100 {
00101 delete d->config;
00102 qDeleteAll( d->transports );
00103 }
00104
00105 TransportManager* TransportManager::self()
00106 {
00107 static TransportManager::Private p;
00108 if(!p.sSelf) {
00109 p.sSelf = new TransportManager;
00110 p.sSelf->readConfig();
00111 qAddPostRoutine(Private::cleanupTransportManager);
00112 }
00113 return p.sSelf;
00114 }
00115
00116 Transport* TransportManager::transportById(int id, bool def) const
00117 {
00118 foreach ( Transport* t, d->transports )
00119 if ( t->id() == id )
00120 return t;
00121
00122 if ( def || (id == 0 && d->defaultTransportId != id) )
00123 return transportById( d->defaultTransportId, false );
00124 return 0;
00125 }
00126
00127 Transport* TransportManager::transportByName(const QString & name, bool def) const
00128 {
00129 foreach ( Transport* t, d->transports )
00130 if ( t->name() == name )
00131 return t;
00132 if ( def )
00133 return transportById( 0, false );
00134 return 0;
00135 }
00136
00137 QList< Transport * > TransportManager::transports() const
00138 {
00139 return d->transports;
00140 }
00141
00142 Transport* TransportManager::createTransport() const
00143 {
00144 int id = createId();
00145 Transport *t = new Transport( QString::number( id ) );
00146 t->setId( id );
00147 return t;
00148 }
00149
00150 void TransportManager::addTransport(Transport * transport)
00151 {
00152 Q_ASSERT( !d->transports.contains( transport ) );
00153 d->transports.append( transport );
00154 validateDefault();
00155 emitChangesCommitted();
00156 }
00157
00158 void TransportManager::schedule(TransportJob * job)
00159 {
00160 connect( job, SIGNAL(result(KJob*)), SLOT(jobResult(KJob*)) );
00161
00162
00163 if ( !job->transport()->isComplete() ) {
00164 kDebug(5324) << "job waits for wallet:" << job;
00165 d->walletQueue << job;
00166 loadPasswordsAsync();
00167 return;
00168 }
00169
00170 job->start();
00171 }
00172
00173 void TransportManager::createDefaultTransport()
00174 {
00175 KEMailSettings kes;
00176 Transport *t = createTransport();
00177 t->setName( i18n("Default Transport") );
00178 t->setHost( kes.getSetting( KEMailSettings::OutServer ) );
00179 if ( t->isValid() ) {
00180 t->writeConfig();
00181 addTransport( t );
00182 } else
00183 kWarning()
00184 << "KEMailSettings does not contain a valid transport.";
00185 }
00186
00187 TransportJob* TransportManager::createTransportJob( int transportId )
00188 {
00189 Transport *t = transportById( transportId, false );
00190 if ( !t )
00191 return 0;
00192 switch ( t->type() ) {
00193 case Transport::EnumType::SMTP:
00194 return new SmtpJob( t->clone(), this );
00195 case Transport::EnumType::Sendmail:
00196 return new SendmailJob( t->clone(), this );
00197 }
00198 Q_ASSERT( false );
00199 return 0;
00200 }
00201
00202 TransportJob* TransportManager::createTransportJob(const QString & transport)
00203 {
00204 bool ok = false;
00205 Transport *t = 0;
00206
00207 int transportId = transport.toInt( &ok );
00208 if ( ok )
00209 t = transportById( transportId );
00210
00211 if ( !t )
00212 t = transportByName( transport, false );
00213
00214 if ( t )
00215 return createTransportJob( t->id() );
00216
00217 Q_ASSERT( false );
00218 return 0;
00219 }
00220
00221 bool TransportManager::isEmpty() const
00222 {
00223 return d->transports.isEmpty();
00224 }
00225
00226 QList<int> TransportManager::transportIds() const
00227 {
00228 QList<int> rv;
00229 foreach ( Transport *t, d->transports )
00230 rv << t->id();
00231 return rv;
00232 }
00233
00234 QStringList TransportManager::transportNames() const
00235 {
00236 QStringList rv;
00237 foreach ( Transport *t, d->transports )
00238 rv << t->name();
00239 return rv;
00240 }
00241
00242 QString TransportManager::defaultTransportName() const
00243 {
00244 Transport* t = transportById( d->defaultTransportId, false );
00245 if ( t )
00246 return t->name();
00247 return QString();
00248 }
00249
00250 int TransportManager::defaultTransportId() const
00251 {
00252 return d->defaultTransportId;
00253 }
00254
00255 void TransportManager::setDefaultTransport(int id)
00256 {
00257 if ( id == d->defaultTransportId || !transportById( id, false ) )
00258 return;
00259 d->defaultTransportId = id;
00260 writeConfig();
00261 }
00262
00263 void TransportManager::removeTransport(int id)
00264 {
00265 Transport *t = transportById( id, false );
00266 if ( !t )
00267 return;
00268 emit transportRemoved( t->id(), t->name() );
00269 d->transports.removeAll( t );
00270 validateDefault();
00271 QString group = t->currentGroup();
00272 delete t;
00273 d->config->deleteGroup( group );
00274 writeConfig();
00275 }
00276
00277 void TransportManager::readConfig()
00278 {
00279 QList<Transport*> oldTransports = d->transports;
00280 d->transports.clear();
00281
00282 QRegExp re( QLatin1String("^Transport (.+)$") );
00283 QStringList groups = d->config->groupList().filter( re );
00284 foreach ( QString s, groups ) {
00285 re.indexIn( s );
00286 Transport *t = 0;
00287
00288
00289 foreach ( Transport *old, oldTransports ) {
00290 if ( old->currentGroup() == QLatin1String("Transport ") + re.cap( 1 ) ) {
00291 kDebug(5324)
00292 << "reloading existing transport:" << s;
00293 t = old;
00294 t->readConfig();
00295 oldTransports.removeAll( old );
00296 break;
00297 }
00298 }
00299
00300 if ( !t )
00301 t = new Transport( re.cap( 1 ) );
00302 if ( t->id() <= 0 ) {
00303 t->setId( createId() );
00304 t->writeConfig();
00305 }
00306 d->transports.append( t );
00307 }
00308
00309 qDeleteAll( oldTransports );
00310 oldTransports.clear();
00311
00312
00313 KConfigGroup group( d->config, "General" );
00314 d->defaultTransportId = group.readEntry( "default-transport", 0 );
00315 if ( d->defaultTransportId == 0 ) {
00316
00317 QString name = group.readEntry( "default-transport", QString() );
00318 if ( !name.isEmpty() ) {
00319 Transport *t = transportByName( name, false );
00320 if ( t ) {
00321 d->defaultTransportId = t->id();
00322 writeConfig();
00323 }
00324 }
00325 }
00326 validateDefault();
00327 migrateToWallet();
00328 }
00329
00330 void TransportManager::writeConfig()
00331 {
00332 KConfigGroup group( d->config, "General" );
00333 group.writeEntry( "default-transport", d->defaultTransportId );
00334 d->config->sync();
00335 emitChangesCommitted();
00336 }
00337
00338 void TransportManager::emitChangesCommitted()
00339 {
00340 d->myOwnChange = true;
00341 emit transportsChanged();
00342 emit changesCommitted();
00343 }
00344
00345 void TransportManager::slotTransportsChanged()
00346 {
00347 if ( d->myOwnChange ) {
00348 d->myOwnChange = false;
00349 return;
00350 }
00351
00352 kDebug(5324) ;
00353 d->config->reparseConfiguration();
00354
00355 readConfig();
00356 emit transportsChanged();
00357 }
00358
00359 int TransportManager::createId() const
00360 {
00361 QList<int> usedIds;
00362 foreach ( Transport *t, d->transports )
00363 usedIds << t->id();
00364 usedIds << 0;
00365 int newId;
00366 do {
00367 newId = KRandom::random();
00368 } while ( usedIds.contains( newId ) );
00369 return newId;
00370 }
00371
00372 KWallet::Wallet * TransportManager::wallet()
00373 {
00374 if ( d->wallet && d->wallet->isOpen() )
00375 return d->wallet;
00376
00377 if ( !Wallet::isEnabled() || d->walletOpenFailed )
00378 return 0;
00379
00380 WId window = 0;
00381 if ( qApp->activeWindow() )
00382 window = qApp->activeWindow()->winId();
00383 else if ( !QApplication::topLevelWidgets().isEmpty() )
00384 window = qApp->topLevelWidgets().first()->winId();
00385
00386 delete d->wallet;
00387 d->wallet = Wallet::openWallet( Wallet::NetworkWallet(), window );
00388
00389 if ( !d->wallet ) {
00390 d->walletOpenFailed = true;
00391 return 0;
00392 }
00393
00394 prepareWallet();
00395 return d->wallet;
00396 }
00397
00398 void TransportManager::prepareWallet()
00399 {
00400 if ( !d->wallet )
00401 return;
00402 if ( !d->wallet->hasFolder( WALLET_FOLDER ) )
00403 d->wallet->createFolder( WALLET_FOLDER );
00404 d->wallet->setFolder( WALLET_FOLDER );
00405 }
00406
00407 void TransportManager::loadPasswords()
00408 {
00409 foreach ( Transport *t, d->transports )
00410 t->readPassword();
00411
00412
00413 foreach ( TransportJob *job, d->walletQueue ) {
00414 job->start();
00415 }
00416 d->walletQueue.clear();
00417
00418 emit passwordsChanged();
00419 }
00420
00421 void TransportManager::loadPasswordsAsync()
00422 {
00423 kDebug(5324) ;
00424
00425
00426 bool found = false;
00427 foreach ( Transport *t, d->transports ) {
00428 if ( !t->isComplete() ) {
00429 found = true;
00430 break;
00431 }
00432 }
00433 if ( !found )
00434 return;
00435
00436
00437 if ( !d->wallet && !d->walletOpenFailed ) {
00438 WId window = 0;
00439 if ( qApp->activeWindow() )
00440 window = qApp->activeWindow()->winId();
00441 else if ( !QApplication::topLevelWidgets().isEmpty() )
00442 window = qApp->topLevelWidgets().first()->winId();
00443
00444 d->wallet = Wallet::openWallet( Wallet::NetworkWallet(), window,
00445 Wallet::Asynchronous );
00446 if ( d->wallet ) {
00447 connect( d->wallet, SIGNAL(walletOpened(bool)), SLOT(slotWalletOpened(bool)) );
00448 d->walletAsyncOpen = true;
00449 }
00450 else {
00451 d->walletOpenFailed = true;
00452 loadPasswords();
00453 }
00454 return;
00455 }
00456 if ( d->wallet && !d->walletAsyncOpen )
00457 loadPasswords();
00458 }
00459
00460 void TransportManager::slotWalletOpened( bool success )
00461 {
00462 kDebug(5324) ;
00463 d->walletAsyncOpen = false;
00464 if ( !success ) {
00465 d->walletOpenFailed = true;
00466 delete d->wallet;
00467 d->wallet = 0;
00468 } else {
00469 prepareWallet();
00470 }
00471 loadPasswords();
00472 }
00473
00474 void TransportManager::validateDefault()
00475 {
00476 if ( !transportById( d->defaultTransportId, false ) ) {
00477 if ( isEmpty() ) {
00478 d->defaultTransportId = -1;
00479 } else {
00480 d->defaultTransportId = d->transports.first()->id();
00481 writeConfig();
00482 }
00483 }
00484 }
00485
00486 void TransportManager::migrateToWallet()
00487 {
00488
00489 static bool firstRun = true;
00490 if ( !firstRun )
00491 return;
00492 firstRun = false;
00493
00494
00495 if ( !d->isMainInstance )
00496 return;
00497
00498
00499 QStringList names;
00500 foreach ( Transport *t, d->transports )
00501 if ( t->needsWalletMigration() )
00502 names << t->name();
00503 if ( names.isEmpty() )
00504 return;
00505
00506
00507 int result = KMessageBox::questionYesNoList( 0,
00508 i18n("The following mail transports store passwords in the configuration "
00509 "file instead in KWallet.\nIt is recommended to use KWallet for "
00510 "password storage for security reasons.\n"
00511 "Do you want to migrate your passwords to KWallet?"),
00512 names, i18n("Question"),
00513 KGuiItem( i18n( "Migrate" ) ), KGuiItem( i18n( "Keep" ) ),
00514 QString::fromAscii( "WalletMigrate" ) );
00515 if ( result != KMessageBox::Yes )
00516 return;
00517
00518
00519 foreach ( Transport *t, d->transports )
00520 if ( t->needsWalletMigration() )
00521 t->migrateToWallet();
00522 }
00523
00524 void TransportManager::dbusServiceOwnerChanged(const QString & service, const QString & oldOwner, const QString & newOwner)
00525 {
00526 Q_UNUSED( oldOwner );
00527 if ( service == DBUS_SERVICE_NAME && newOwner.isEmpty() )
00528 QDBusConnection::sessionBus().registerService( DBUS_SERVICE_NAME );
00529 }
00530
00531 void TransportManager::jobResult(KJob * job)
00532 {
00533 d->walletQueue.removeAll( static_cast<TransportJob*>( job ) );
00534 }
00535
00536 #include "transportmanager.moc"