diff --git a/mailtransport/transport.cpp b/mailtransport/transport.cpp index 351f932ce..52e62e52e 100644 --- a/mailtransport/transport.cpp +++ b/mailtransport/transport.cpp @@ -1,266 +1,273 @@ /* Copyright (c) 2006 - 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "transport.h" #include "transportmanager.h" #include "mailtransport_defs.h" #include "legacydecrypt.h" +#include #include #include #include #include #include #include using namespace MailTransport; using namespace KWallet; /** * Private class that helps to provide binary compatibility between releases. * @internal */ class TransportPrivate { public: QString password; bool passwordLoaded; bool passwordDirty; bool storePasswordInFile; bool needsWalletMigration; QString oldName; }; Transport::Transport( const QString &cfgGroup ) : TransportBase( cfgGroup ), d( new TransportPrivate ) { kDebug() << cfgGroup; d->passwordLoaded = false; d->passwordDirty = false; d->storePasswordInFile = false; d->needsWalletMigration = false; readConfig(); } Transport::~Transport() { delete d; } bool Transport::isValid() const { return ( id() > 0 ) && !host().isEmpty() && port() <= 65536; } QString Transport::password() { if ( !d->passwordLoaded && requiresAuthentication() && storePassword() && d->password.isEmpty() ) { TransportManager::self()->loadPasswords(); d->password = TransportManager::self()->transportById( id(), false )->password(); } return d->password; } void Transport::setPassword( const QString &passwd ) { d->passwordLoaded = true; if ( d->password == passwd ) { return; } d->passwordDirty = true; d->password = passwd; } void Transport::updatePasswordState() { Transport *original = TransportManager::self()->transportById( id(), false ); if ( original == this ) { kWarning() << "Tried to update password state of non-cloned transport."; return; } if ( original ) { d->password = original->d->password; d->passwordLoaded = original->d->passwordLoaded; d->passwordDirty = original->d->passwordDirty; } else kWarning() << "Transport with this ID not managed by transport manager."; } bool Transport::isComplete() const { return !requiresAuthentication() || !storePassword() || d->passwordLoaded; } QString Transport::authenticationTypeString() const { switch ( authenticationType() ) { case EnumAuthenticationType::LOGIN: return QLatin1String( "LOGIN" ); case EnumAuthenticationType::PLAIN: return QLatin1String( "PLAIN" ); case EnumAuthenticationType::CRAM_MD5: return QLatin1String( "CRAM-MD5" ); case EnumAuthenticationType::DIGEST_MD5: return QLatin1String( "DIGEST-MD5" ); case EnumAuthenticationType::NTLM: return QLatin1String( "NTLM" ); case EnumAuthenticationType::GSSAPI: return QLatin1String( "GSSAPI" ); } Q_ASSERT( false ); return QString(); } void Transport::usrReadConfig() { TransportBase::usrReadConfig(); setHost( host().trimmed() ); if ( d->oldName.isEmpty() ) { d->oldName = name(); } // we have everything we need if ( !storePassword() || d->passwordLoaded ) { return; } // try to find a password in the config file otherwise KConfigGroup group( config(), currentGroup() ); if ( group.hasKey( "password" ) ) { d->password = KStringHandler::obscure( group.readEntry( "password" ) ); } else if ( group.hasKey( "password-kmail" ) ) { d->password = Legacy::decryptKMail( group.readEntry( "password-kmail" ) ); } else if ( group.hasKey( "password-knode" ) ) { d->password = Legacy::decryptKNode( group.readEntry( "password-knode" ) ); } if ( !d->password.isEmpty() ) { d->passwordLoaded = true; if ( Wallet::isEnabled() ) { d->needsWalletMigration = true; } else { d->storePasswordInFile = true; } } else { // read password if wallet is open, defer otherwise if ( Wallet::isOpen( Wallet::NetworkWallet() ) ) { - readPassword(); + // Don't read the password right away because this can lead + // to reentrancy problems in KDBusServiceStarter when an application + // run in Kontact creates the transports (due to a QEventLoop in the + // synchronous KWallet openWallet call). + QTimer::singleShot(0, this, SLOT(readPassword())); } } } void Transport::usrWriteConfig() { if ( requiresAuthentication() && storePassword() && d->passwordDirty ) { Wallet *wallet = TransportManager::self()->wallet(); if ( !wallet || wallet->writePassword( QString::number( id() ), d->password ) != 0 ) { // wallet saving failed, ask if we should store in the config file instead if ( d->storePasswordInFile || KMessageBox::warningYesNo( 0, i18n( "KWallet is not available. It is strongly recommended to use " "KWallet for managing your passwords.\n" "However, the password can be stored in the configuration " "file instead. The password is stored in an obfuscated format, " "but should not be considered secure from decryption efforts " "if access to the configuration file is obtained.\n" "Do you want to store the password for server '%1' in the " "configuration file?", name() ), i18n( "KWallet Not Available" ), KGuiItem( i18n( "Store Password" ) ), KGuiItem( i18n( "Do Not Store Password" ) ) ) == KMessageBox::Yes ) { // write to config file KConfigGroup group( config(), currentGroup() ); group.writeEntry( "password", KStringHandler::obscure( d->password ) ); d->storePasswordInFile = true; } } d->passwordDirty = false; } TransportBase::usrWriteConfig(); TransportManager::self()->emitChangesCommitted(); if ( name() != d->oldName ) { emit TransportManager::self()->transportRenamed( id(), d->oldName, name() ); d->oldName = name(); } } void Transport::readPassword() { // no need to load a password if the account doesn't require auth if ( !requiresAuthentication() ) { return; } d->passwordLoaded = true; // check whether there is a chance to find our password at all if ( Wallet::folderDoesNotExist( Wallet::NetworkWallet(), WALLET_FOLDER ) || Wallet::keyDoesNotExist( Wallet::NetworkWallet(), WALLET_FOLDER, QString::number( id() ) ) ) { // try migrating password from kmail if ( Wallet::folderDoesNotExist( Wallet::NetworkWallet(), KMAIL_WALLET_FOLDER ) || Wallet::keyDoesNotExist( Wallet::NetworkWallet(), KMAIL_WALLET_FOLDER, QString::fromLatin1( "transport-%1" ).arg( id() ) ) ) { return; } kDebug() << "migrating password from kmail wallet"; KWallet::Wallet *wallet = TransportManager::self()->wallet(); if ( wallet ) { wallet->setFolder( KMAIL_WALLET_FOLDER ); wallet->readPassword( QString::fromLatin1( "transport-%1" ).arg( id() ), d->password ); wallet->removeEntry( QString::fromLatin1( "transport-%1" ).arg( id() ) ); wallet->setFolder( WALLET_FOLDER ); d->passwordDirty = true; writeConfig(); } return; } // finally try to open the wallet and read the password KWallet::Wallet *wallet = TransportManager::self()->wallet(); if ( wallet ) { wallet->readPassword( QString::number( id() ), d->password ); } } bool Transport::needsWalletMigration() const { return d->needsWalletMigration; } void Transport::migrateToWallet() { kDebug() << "migrating" << id() << "to wallet"; d->needsWalletMigration = false; KConfigGroup group( config(), currentGroup() ); group.deleteEntry( "password" ); d->passwordDirty = true; d->storePasswordInFile = false; writeConfig(); } Transport *Transport::clone() const { QString id = currentGroup().mid( 10 ); return new Transport( id ); } + +#include "transport.moc" diff --git a/mailtransport/transport.h b/mailtransport/transport.h index c3d56e32d..0c27170d8 100644 --- a/mailtransport/transport.h +++ b/mailtransport/transport.h @@ -1,125 +1,126 @@ /* Copyright (c) 2006 - 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef MAILTRANSPORT_TRANSPORT_H #define MAILTRANSPORT_TRANSPORT_H #include #include class TransportPrivate; namespace MailTransport { /** Represents the settings of a specific mail transport. To create a new empty Transport object, use TransportManager::createTransport(). */ class MAILTRANSPORT_EXPORT Transport : public TransportBase { + Q_OBJECT friend class TransportManager; public: /** Destructor */ virtual ~Transport(); typedef QList List; /** Returns true if this transport is valid, ie. has all necessary data set. */ bool isValid() const; /** Returns the password of this transport. */ QString password(); /** Sets the password of this transport. @param passwd The new password. */ void setPassword( const QString &passwd ); /** This function syncronizes the password of this transport with the password of the transport with the same ID that is managed by the transport manager. This is only useful for cloned transports, since their passwords don't automatically get updated when calling TransportManager::loadPasswordsAsync() or TransportManager::loadPasswords(). @sa clone() */ void updatePasswordState(); /** Returns true if all settings have been loaded. This is the way to find out if the password has already been loaded from the wallet. */ bool isComplete() const; /** Returns a string representation of the authentication type. */ QString authenticationTypeString() const; /** Returns a deep copy of this Transport object which will no longer be automatically updated. Use this if you need to store a Transport object over a longer time. However it is recommended to store transport identifiers instead if possible. @sa updatePasswordState() */ Transport *clone() const; protected: /** Creates a Transport object. Should only be used by TransportManager. @param cfgGroup The KConfig group to read its data from. */ Transport( const QString &cfgGroup ); virtual void usrReadConfig(); virtual void usrWriteConfig(); /** Returns true if the password was not stored in the wallet. */ bool needsWalletMigration() const; /** Try to migrate the password from the config file to the wallet. */ void migrateToWallet(); - private: + private Q_SLOTS: void readPassword(); private: TransportPrivate *const d; }; } #endif