• Skip to content
  • Skip to link menu
KDE 4.0 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   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   // check if the job is waiting for the wallet
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     // see if we happen to have that one already
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   // read default transport
00313   KConfigGroup group( d->config, "General" );
00314   d->defaultTransportId = group.readEntry( "default-transport", 0 );
00315   if ( d->defaultTransportId == 0 ) {
00316     // migrated default transport contains the name instead
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; // prevent us from reading our changes again
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   // FIXME: this deletes existing transport objects!
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; // 0 is default for unknown
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   // flush the wallet queue
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   // check if there is anything to do at all
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   // async wallet opening
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   // check if we tried this already
00489   static bool firstRun = true;
00490   if ( !firstRun )
00491     return;
00492   firstRun = false;
00493 
00494   // check if we are the main instance
00495   if ( !d->isMainInstance )
00496     return;
00497 
00498   // check if migration is needed
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   // ask user if he wants to migrate
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   // perform migration
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"

mailtransport

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

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • kabc
  • kblog
  • kcal
  • kimap
  • kioslave
  •   imap4
  •   mbox
  • kldap
  • kmime
  • kpimidentities
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.5.5
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