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