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