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