• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • Sitemap
  • Contact Us
 

mailtransport

transportmanager.cpp

00001 /*
00002     Copyright (c) 2006 - 2007 Volker Krause <vkrause@kde.org>
00003 
00004     This library is free software; you can redistribute it and/or modify it
00005     under the terms of the GNU Library General Public License as published by
00006     the Free Software Foundation; either version 2 of the License, or (at your
00007     option) any later version.
00008 
00009     This library is distributed in the hope that it will be useful, but WITHOUT
00010     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00011     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00012     License for more details.
00013 
00014     You should have received a copy of the GNU Library General Public License
00015     along with this library; see the file COPYING.LIB.  If not, write to the
00016     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017     02110-1301, USA.
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 {
00051   public:
00052     Private() {}
00053     ~Private() {
00054       delete config;
00055       qDeleteAll( transports );
00056     }
00057 
00058     KConfig *config;
00059     QList<Transport *> transports;
00060     bool myOwnChange;
00061     KWallet::Wallet *wallet;
00062     bool walletOpenFailed;
00063     bool walletAsyncOpen;
00064     int defaultTransportId;
00065     bool isMainInstance;
00066     QList<TransportJob *> walletQueue;
00067 };
00068 
00069 class StaticTransportManager : public TransportManager
00070 {
00071   public:
00072     StaticTransportManager() : TransportManager() {}
00073 };
00074 
00075 StaticTransportManager *sSelf = 0;
00076 
00077 static void destroyStaticTransportManager() {
00078   delete sSelf;
00079 }
00080 
00081 TransportManager::TransportManager()
00082   : QObject(), d( new Private )
00083 {
00084   KGlobal::locale()->insertCatalog( QLatin1String( "libmailtransport" ) );
00085   qAddPostRoutine( destroyStaticTransportManager );
00086   d->myOwnChange = false;
00087   d->wallet = 0;
00088   d->walletOpenFailed = false;
00089   d->walletAsyncOpen = false;
00090   d->defaultTransportId = -1;
00091   d->config = new KConfig( QLatin1String( "mailtransports" ) );
00092 
00093   QDBusConnection::sessionBus().registerObject( DBUS_OBJECT_PATH, this,
00094       QDBusConnection::ExportScriptableSlots |
00095               QDBusConnection::ExportScriptableSignals );
00096 
00097   QDBusConnection::sessionBus().connect( QString(), QString(),
00098                               DBUS_INTERFACE_NAME, DBUS_CHANGE_SIGNAL,
00099                               this, SLOT(slotTransportsChanged()) );
00100 
00101   d->isMainInstance =
00102           QDBusConnection::sessionBus().registerService( DBUS_SERVICE_NAME );
00103   connect( QDBusConnection::sessionBus().interface(),
00104            SIGNAL(serviceOwnerChanged(QString,QString,QString)),
00105            SLOT(dbusServiceOwnerChanged(QString,QString,QString)) );
00106 }
00107 
00108 TransportManager::~TransportManager()
00109 {
00110   qRemovePostRoutine( destroyStaticTransportManager );
00111   delete d;
00112 }
00113 
00114 TransportManager *TransportManager::self()
00115 {
00116   if ( !sSelf ) {
00117     sSelf = new StaticTransportManager;
00118     sSelf->readConfig();
00119   }
00120   return sSelf;
00121 }
00122 
00123 Transport *TransportManager::transportById( int id, bool def ) const
00124 {
00125   foreach ( Transport *t, d->transports ) {
00126     if ( t->id() == id ) {
00127       return t;
00128     }
00129   }
00130 
00131   if ( def || ( id == 0 && d->defaultTransportId != id ) ) {
00132     return transportById( d->defaultTransportId, false );
00133   }
00134   return 0;
00135 }
00136 
00137 Transport *TransportManager::transportByName( const QString &name, bool def ) const
00138 {
00139   foreach ( Transport *t, d->transports ) {
00140     if ( t->name() == name ) {
00141       return t;
00142     }
00143   }
00144   if ( def ) {
00145     return transportById( 0, false );
00146   }
00147   return 0;
00148 }
00149 
00150 QList< Transport * > TransportManager::transports() const
00151 {
00152   return d->transports;
00153 }
00154 
00155 Transport *TransportManager::createTransport() const
00156 {
00157   int id = createId();
00158   Transport *t = new Transport( QString::number( id ) );
00159   t->setId( id );
00160   return t;
00161 }
00162 
00163 void TransportManager::addTransport( Transport *transport )
00164 {
00165   if ( d->transports.contains( transport ) ) {
00166     return;
00167   }
00168 
00169   d->transports.append( transport );
00170   validateDefault();
00171   emitChangesCommitted();
00172 }
00173 
00174 void TransportManager::schedule( TransportJob *job )
00175 {
00176   connect( job, SIGNAL(result(KJob*)), SLOT(jobResult(KJob*)) );
00177 
00178   // check if the job is waiting for the wallet
00179   if ( !job->transport()->isComplete() ) {
00180     kDebug() << "job waits for wallet:" << job;
00181     d->walletQueue << job;
00182     loadPasswordsAsync();
00183     return;
00184   }
00185 
00186   job->start();
00187 }
00188 
00189 void TransportManager::createDefaultTransport()
00190 {
00191   KEMailSettings kes;
00192   Transport *t = createTransport();
00193   t->setName( i18n( "Default Transport" ) );
00194   t->setHost( kes.getSetting( KEMailSettings::OutServer ) );
00195   if ( t->isValid() ) {
00196     t->writeConfig();
00197     addTransport( t );
00198   } else {
00199     kWarning() << "KEMailSettings does not contain a valid transport.";
00200   }
00201 }
00202 
00203 TransportJob *TransportManager::createTransportJob( int transportId )
00204 {
00205   Transport *t = transportById( transportId, false );
00206   if ( !t ) {
00207     return 0;
00208   }
00209   switch ( t->type() ) {
00210   case Transport::EnumType::SMTP:
00211     return new SmtpJob( t->clone(), this );
00212   case Transport::EnumType::Sendmail:
00213     return new SendmailJob( t->clone(), this );
00214   }
00215   Q_ASSERT( false );
00216   return 0;
00217 }
00218 
00219 TransportJob *TransportManager::createTransportJob( const QString &transport )
00220 {
00221   bool ok = false;
00222   Transport *t = 0;
00223 
00224   int transportId = transport.toInt( &ok );
00225   if ( ok ) {
00226     t = transportById( transportId );
00227   }
00228 
00229   if ( !t ) {
00230     t = transportByName( transport, false );
00231   }
00232 
00233   if ( t ) {
00234     return createTransportJob( t->id() );
00235   }
00236 
00237   return 0;
00238 }
00239 
00240 bool TransportManager::isEmpty() const
00241 {
00242   return d->transports.isEmpty();
00243 }
00244 
00245 QList<int> TransportManager::transportIds() const
00246 {
00247   QList<int> rv;
00248   foreach ( Transport *t, d->transports ) {
00249     rv << t->id();
00250   }
00251   return rv;
00252 }
00253 
00254 QStringList TransportManager::transportNames() const
00255 {
00256   QStringList rv;
00257   foreach ( Transport *t, d->transports ) {
00258     rv << t->name();
00259   }
00260   return rv;
00261 }
00262 
00263 QString TransportManager::defaultTransportName() const
00264 {
00265   Transport *t = transportById( d->defaultTransportId, false );
00266   if ( t ) {
00267     return t->name();
00268   }
00269   return QString();
00270 }
00271 
00272 int TransportManager::defaultTransportId() const
00273 {
00274   return d->defaultTransportId;
00275 }
00276 
00277 void TransportManager::setDefaultTransport( int id )
00278 {
00279   if ( id == d->defaultTransportId || !transportById( id, false ) ) {
00280     return;
00281   }
00282   d->defaultTransportId = id;
00283   writeConfig();
00284 }
00285 
00286 void TransportManager::removeTransport( int id )
00287 {
00288   Transport *t = transportById( id, false );
00289   if ( !t ) {
00290     return;
00291   }
00292   emit transportRemoved( t->id(), t->name() );
00293   d->transports.removeAll( t );
00294   validateDefault();
00295   QString group = t->currentGroup();
00296   delete t;
00297   d->config->deleteGroup( group );
00298   writeConfig();
00299 }
00300 
00301 void TransportManager::readConfig()
00302 {
00303   QList<Transport *> oldTransports = d->transports;
00304   d->transports.clear();
00305 
00306   QRegExp re( QLatin1String( "^Transport (.+)$" ) );
00307   QStringList groups = d->config->groupList().filter( re );
00308   foreach ( const QString &s, groups ) {
00309     re.indexIn( s );
00310     Transport *t = 0;
00311 
00312     // see if we happen to have that one already
00313     foreach ( Transport *old, oldTransports ) {
00314       if ( old->currentGroup() == QLatin1String( "Transport " ) + re.cap( 1 ) ) {
00315         kDebug() << "reloading existing transport:" << s;
00316         t = old;
00317         t->readConfig();
00318         oldTransports.removeAll( old );
00319         break;
00320       }
00321     }
00322 
00323     if ( !t ) {
00324       t = new Transport( re.cap( 1 ) );
00325     }
00326     if ( t->id() <= 0 ) {
00327       t->setId( createId() );
00328       t->writeConfig();
00329     }
00330     d->transports.append( t );
00331   }
00332 
00333   qDeleteAll( oldTransports );
00334   oldTransports.clear();
00335 
00336   // read default transport
00337   KConfigGroup group( d->config, "General" );
00338   d->defaultTransportId = group.readEntry( "default-transport", 0 );
00339   if ( d->defaultTransportId == 0 ) {
00340     // migrated default transport contains the name instead
00341     QString name = group.readEntry( "default-transport", QString() );
00342     if ( !name.isEmpty() ) {
00343       Transport *t = transportByName( name, false );
00344       if ( t ) {
00345         d->defaultTransportId = t->id();
00346         writeConfig();
00347       }
00348     }
00349   }
00350   validateDefault();
00351   migrateToWallet();
00352 }
00353 
00354 void TransportManager::writeConfig()
00355 {
00356   KConfigGroup group( d->config, "General" );
00357   group.writeEntry( "default-transport", d->defaultTransportId );
00358   d->config->sync();
00359   emitChangesCommitted();
00360 }
00361 
00362 void TransportManager::emitChangesCommitted()
00363 {
00364   d->myOwnChange = true; // prevent us from reading our changes again
00365   emit transportsChanged();
00366   emit changesCommitted();
00367 }
00368 
00369 void TransportManager::slotTransportsChanged()
00370 {
00371   if ( d->myOwnChange ) {
00372     d->myOwnChange = false;
00373     return;
00374   }
00375 
00376   kDebug();
00377   d->config->reparseConfiguration();
00378   // FIXME: this deletes existing transport objects!
00379   readConfig();
00380   emit transportsChanged();
00381 }
00382 
00383 int TransportManager::createId() const
00384 {
00385   QList<int> usedIds;
00386   foreach ( Transport *t, d->transports ) {
00387     usedIds << t->id();
00388   }
00389   usedIds << 0; // 0 is default for unknown
00390   int newId;
00391   do {
00392       newId = KRandom::random();
00393   } while ( usedIds.contains( newId ) );
00394   return newId;
00395 }
00396 
00397 KWallet::Wallet * TransportManager::wallet()
00398 {
00399   if ( d->wallet && d->wallet->isOpen() ) {
00400     return d->wallet;
00401   }
00402 
00403   if ( !Wallet::isEnabled() || d->walletOpenFailed ) {
00404     return 0;
00405   }
00406 
00407   WId window = 0;
00408   if ( qApp->activeWindow() ) {
00409     window = qApp->activeWindow()->winId();
00410   } else if ( !QApplication::topLevelWidgets().isEmpty() ) {
00411     window = qApp->topLevelWidgets().first()->winId();
00412   }
00413 
00414   delete d->wallet;
00415   d->wallet = Wallet::openWallet( Wallet::NetworkWallet(), window );
00416 
00417   if ( !d->wallet ) {
00418     d->walletOpenFailed = true;
00419     return 0;
00420   }
00421 
00422   prepareWallet();
00423   return d->wallet;
00424 }
00425 
00426 void TransportManager::prepareWallet()
00427 {
00428   if ( !d->wallet ) {
00429     return;
00430   }
00431   if ( !d->wallet->hasFolder( WALLET_FOLDER ) ) {
00432     d->wallet->createFolder( WALLET_FOLDER );
00433   }
00434   d->wallet->setFolder( WALLET_FOLDER );
00435 }
00436 
00437 void TransportManager::loadPasswords()
00438 {
00439   foreach ( Transport *t, d->transports ) {
00440     t->readPassword();
00441   }
00442 
00443   // flush the wallet queue
00444   foreach ( TransportJob *job, d->walletQueue ) {
00445     job->start();
00446   }
00447   d->walletQueue.clear();
00448 
00449   emit passwordsChanged();
00450 }
00451 
00452 void TransportManager::loadPasswordsAsync()
00453 {
00454   kDebug();
00455 
00456   // check if there is anything to do at all
00457   bool found = false;
00458   foreach ( Transport *t, d->transports ) {
00459     if ( !t->isComplete() ) {
00460       found = true;
00461       break;
00462     }
00463   }
00464   if ( !found ) {
00465     return;
00466   }
00467 
00468   // async wallet opening
00469   if ( !d->wallet && !d->walletOpenFailed ) {
00470     WId window = 0;
00471     if ( qApp->activeWindow() ) {
00472       window = qApp->activeWindow()->winId();
00473     } else if ( !QApplication::topLevelWidgets().isEmpty() ) {
00474       window = qApp->topLevelWidgets().first()->winId();
00475     }
00476 
00477     d->wallet = Wallet::openWallet( Wallet::NetworkWallet(), window,
00478                                     Wallet::Asynchronous );
00479     if ( d->wallet ) {
00480       connect( d->wallet, SIGNAL(walletOpened(bool)), SLOT(slotWalletOpened(bool)) );
00481       d->walletAsyncOpen = true;
00482     } else {
00483       d->walletOpenFailed = true;
00484       loadPasswords();
00485     }
00486     return;
00487   }
00488   if ( d->wallet && !d->walletAsyncOpen ) {
00489     loadPasswords();
00490   }
00491 }
00492 
00493 void TransportManager::slotWalletOpened( bool success )
00494 {
00495   kDebug();
00496   d->walletAsyncOpen = false;
00497   if ( !success ) {
00498     d->walletOpenFailed = true;
00499     delete d->wallet;
00500     d->wallet = 0;
00501   } else {
00502     prepareWallet();
00503   }
00504   loadPasswords();
00505 }
00506 
00507 void TransportManager::validateDefault()
00508 {
00509   if ( !transportById( d->defaultTransportId, false ) ) {
00510     if ( isEmpty() ) {
00511       d->defaultTransportId = -1;
00512     } else {
00513       d->defaultTransportId = d->transports.first()->id();
00514       writeConfig();
00515     }
00516   }
00517 }
00518 
00519 void TransportManager::migrateToWallet()
00520 {
00521   // check if we tried this already
00522   static bool firstRun = true;
00523   if ( !firstRun ) {
00524     return;
00525   }
00526   firstRun = false;
00527 
00528   // check if we are the main instance
00529   if ( !d->isMainInstance ) {
00530     return;
00531   }
00532 
00533   // check if migration is needed
00534   QStringList names;
00535   foreach ( Transport *t, d->transports ) {
00536     if ( t->needsWalletMigration() ) {
00537       names << t->name();
00538     }
00539   }
00540   if ( names.isEmpty() ) {
00541     return;
00542   }
00543 
00544   // ask user if he wants to migrate
00545   int result = KMessageBox::questionYesNoList(
00546     0,
00547     i18n( "The following mail transports store their passwords in an "
00548           "unencrypted configuration file.\nFor security reasons, "
00549           "please consider migrating these passwords to KWallet, the "
00550           "KDE Wallet management tool,\nwhich stores sensitive data "
00551           "for you in a strongly encrypted file.\n"
00552           "Do you want to migrate your passwords to KWallet?" ),
00553     names, i18n( "Question" ),
00554     KGuiItem( i18n( "Migrate" ) ), KGuiItem( i18n( "Keep" ) ),
00555     QString::fromAscii( "WalletMigrate" ) );
00556   if ( result != KMessageBox::Yes ) {
00557     return;
00558   }
00559 
00560   // perform migration
00561   foreach ( Transport *t, d->transports ) {
00562     if ( t->needsWalletMigration() ) {
00563       t->migrateToWallet();
00564     }
00565   }
00566 }
00567 
00568 void TransportManager::dbusServiceOwnerChanged( const QString &service,
00569                                                 const QString &oldOwner,
00570                                                 const QString &newOwner )
00571 {
00572   Q_UNUSED( oldOwner );
00573   if ( service == DBUS_SERVICE_NAME && newOwner.isEmpty() ) {
00574     QDBusConnection::sessionBus().registerService( DBUS_SERVICE_NAME );
00575   }
00576 }
00577 
00578 void TransportManager::jobResult( KJob *job )
00579 {
00580   d->walletQueue.removeAll( static_cast<TransportJob*>( job ) );
00581 }
00582 
00583 #include "transportmanager.moc"

mailtransport

Skip menu "mailtransport"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  • kabc
  • kblog
  • kcal
  • kimap
  • kioslave
  •   imap4
  •   mbox
  • kldap
  • kmime
  • kpimidentities
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.5.6
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal