diff --git a/mailtransport/transport.cpp b/mailtransport/transport.cpp index e21d46537..351f932ce 100644 --- a/mailtransport/transport.cpp +++ b/mailtransport/transport.cpp @@ -1,250 +1,266 @@ /* 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 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(); } } } 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 ); } diff --git a/mailtransport/transport.h b/mailtransport/transport.h index c9b5af6ea..c3d56e32d 100644 --- a/mailtransport/transport.h +++ b/mailtransport/transport.h @@ -1,112 +1,125 @@ /* 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 { 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: void readPassword(); private: TransportPrivate *const d; }; } #endif diff --git a/mailtransport/transportconfigdialog.cpp b/mailtransport/transportconfigdialog.cpp index 80f2093be..0e48bd6c9 100644 --- a/mailtransport/transportconfigdialog.cpp +++ b/mailtransport/transportconfigdialog.cpp @@ -1,387 +1,390 @@ /* Copyright (c) 2006 - 2007 Volker Krause Copyright (c) 2007 KovoKs Based on KMail code by: Copyright (c) 2001-2002 Michael Haeckel 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 "transportconfigdialog.h" #include "transport.h" #include "transportmanager.h" #include "servertest.h" #include "mailtransport_defs.h" #include "ui_smtpsettings.h" #include "ui_sendmailsettings.h" #include #include #include #include #include namespace { class BusyCursorHelper : public QObject { public: inline BusyCursorHelper( QObject *parent ) : QObject( parent ) { qApp->setOverrideCursor( Qt::BusyCursor ); } inline ~BusyCursorHelper() { qApp->restoreOverrideCursor(); } }; } using namespace MailTransport; class MailTransport::TransportConfigDialog::Private { public: Transport *transport; Ui::SMTPSettings smtp; Ui::SendmailSettings sendmail; KConfigDialogManager *manager; KLineEdit *passwordEdit; ServerTest *serverTest; QButtonGroup *encryptionGroup; QButtonGroup *authGroup; // detected authentication capabilities QList noEncCapa, sslCapa, tlsCapa; bool serverTestFailed; void resetAuthCapabilities() { noEncCapa.clear(); noEncCapa << Transport::EnumAuthenticationType::LOGIN << Transport::EnumAuthenticationType::PLAIN << Transport::EnumAuthenticationType::CRAM_MD5 << Transport::EnumAuthenticationType::DIGEST_MD5 << Transport::EnumAuthenticationType::NTLM << Transport::EnumAuthenticationType::GSSAPI; sslCapa = tlsCapa = noEncCapa; if ( authGroup ) { updateAuthCapbilities(); } } void updateAuthCapbilities() { Q_ASSERT( transport->type() == Transport::EnumType::SMTP ); if ( serverTestFailed ) { return; } QList capa = noEncCapa; if ( smtp.ssl->isChecked() ) { capa = sslCapa; } else if ( smtp.tls->isChecked() ) { capa = tlsCapa; } for ( int i = 0; i < authGroup->buttons().count(); ++i ) { authGroup->buttons().at( i )->setEnabled( capa.contains( i ) ); } if ( capa.count() == 0 ) { smtp.noAuthPossible->setVisible( true ); smtp.kcfg_requiresAuthentication->setChecked( false ); smtp.kcfg_requiresAuthentication->setEnabled( false ); } else { smtp.noAuthPossible->setVisible( false ); smtp.kcfg_requiresAuthentication->setEnabled( true ); } } }; TransportConfigDialog::TransportConfigDialog( Transport *transport, QWidget *parent ) : KDialog( parent ), d( new Private ) { Q_ASSERT( transport ); d->transport = transport; d->passwordEdit = 0; d->serverTest = 0; d->encryptionGroup = 0; d->authGroup = 0; d->resetAuthCapabilities(); setButtons( Ok|Cancel|User3 ); showButton( User3, false ); setButtonText( User3, i18n( "Use Sendmail" ) ); connect( this, SIGNAL( user3Clicked() ), SLOT( slotUser3() ) ); connect( this, SIGNAL(okClicked()), SLOT(save()) ); connect( TransportManager::self(), SIGNAL(passwordsChanged()), SLOT(passwordsLoaded()) ); switch ( transport->type() ) { case Transport::EnumType::SMTP: { showButton( User3, true ); d->smtp.setupUi( mainWidget() ); d->passwordEdit = d->smtp.password; d->encryptionGroup = new QButtonGroup( this ); d->encryptionGroup->addButton( d->smtp.none ); d->encryptionGroup->addButton( d->smtp.ssl ); d->encryptionGroup->addButton( d->smtp.tls ); d->authGroup = new QButtonGroup( this ); d->authGroup->addButton( d->smtp.login ); d->authGroup->addButton( d->smtp.plain ); d->authGroup->addButton( d->smtp.crammd5 ); d->authGroup->addButton( d->smtp.digestmd5 ); d->authGroup->addButton( d->smtp.gssapi ); d->authGroup->addButton( d->smtp.ntlm ); if ( KProtocolInfo::capabilities( SMTP_PROTOCOL ).contains( QLatin1String( "SASL" ) ) == 0 ) { d->smtp.ntlm->hide(); d->smtp.gssapi->hide(); } connect( d->smtp.checkCapabilities, SIGNAL(clicked()), SLOT(checkSmtpCapabilities()) ); connect( d->smtp.kcfg_host, SIGNAL(textChanged(QString)), SLOT(hostNameChanged(QString)) ); connect( d->smtp.kcfg_encryption, SIGNAL(clicked(int)), SLOT(encryptionChanged(int)) ); connect( d->smtp.kcfg_requiresAuthentication, SIGNAL( toggled(bool) ), SLOT( ensureValidAuthSelection() ) ); break; } case Transport::EnumType::Sendmail: { d->sendmail.setupUi( mainWidget() ); connect( d->sendmail.chooseButton, SIGNAL(clicked()), SLOT(chooseSendmail()) ); connect( d->sendmail.kcfg_host, SIGNAL(textChanged(QString)), SLOT(hostNameChanged(QString)) ); } } // load the password if necessary if ( d->passwordEdit ) { if ( d->transport->isComplete() ) { d->passwordEdit->setText( d->transport->password() ); } else { if ( d->transport->requiresAuthentication() ) { TransportManager::self()->loadPasswordsAsync(); } } } d->manager = new KConfigDialogManager( this, transport ); d->manager->updateWidgets(); hostNameChanged( d->transport->host() ); } TransportConfigDialog::~ TransportConfigDialog() { delete d; } void TransportConfigDialog::checkSmtpCapabilities() { Q_ASSERT( d->transport->type() == Transport::EnumType::SMTP ); d->serverTest = new ServerTest( this ); d->serverTest->setProtocol( SMTP_PROTOCOL ); d->serverTest->setServer( d->smtp.kcfg_host->text().trimmed() ); if ( d->smtp.kcfg_specifyHostname->isChecked() ) { d->serverTest->setFakeHostname( d->smtp.kcfg_localHostname->text() ); } d->serverTest->setProgressBar( d->smtp.checkCapabilitiesProgress ); BusyCursorHelper *busyCursorHelper = new BusyCursorHelper( d->serverTest ); connect( d->serverTest, SIGNAL(finished( QList< int > )), SLOT(slotFinished( QList< int > ))); connect( d->serverTest, SIGNAL(finished( QList< int > )), busyCursorHelper, SLOT(deleteLater()) ); d->smtp.checkCapabilities->setEnabled( false ); d->serverTest->start(); d->serverTestFailed = false; } void TransportConfigDialog::save() { d->manager->updateSettings(); if ( d->passwordEdit ) { d->transport->setPassword( d->passwordEdit->text() ); } // enforce unique name QStringList existingNames; foreach ( Transport *t, TransportManager::self()->transports() ) { if ( t->id() != d->transport->id() ) { existingNames << t->name(); } } int suffix = 1; QString origName = d->transport->name(); while ( existingNames.contains( d->transport->name() ) ) { d->transport->setName( i18nc( "%1: name; %2: number appended to it to make " "it unique among a list of names", "%1 #%2", origName, suffix ) ); ++suffix; } d->transport->writeConfig(); } void TransportConfigDialog::slotUser3() { reject(); emit sendmailClicked(); } void TransportConfigDialog::chooseSendmail() { Q_ASSERT( d->transport->type() == Transport::EnumType::Sendmail ); KFileDialog dialog( KUrl( "/" ), QString(), this ); dialog.setCaption( i18n( "Choose sendmail Location" ) ); if ( dialog.exec() == QDialog::Accepted ) { KUrl url = dialog.selectedUrl(); if ( url.isEmpty() == true ) { return; } if ( !url.isLocalFile() ) { KMessageBox::sorry( this, i18n( "Only local files allowed." ) ); return; } d->sendmail.kcfg_host->setText( url.path() ); } } void TransportConfigDialog::passwordsLoaded() { Q_ASSERT( d->passwordEdit ); + // Load the password from the original to our cloned copy + d->transport->updatePasswordState(); + if ( d->passwordEdit->text().isEmpty() ) { d->passwordEdit->setText( d->transport->password() ); } } static void checkHighestEnabledButton( QButtonGroup *group ) { Q_ASSERT( group ); for ( int i = group->buttons().count() - 1; i >= 0; --i ) { QAbstractButton *b = group->buttons().at( i ); if ( b && b->isEnabled() ) { b->animateClick(); return; } } } void TransportConfigDialog::slotFinished( QList results ) { d->smtp.checkCapabilities->setEnabled( true ); d->serverTest->deleteLater(); // If the servertest did not find any useable authentication modes, assume the // connection failed and don't disable any of the radioboxes. if ( results.isEmpty() ) { d->serverTestFailed = true; return; } // encryption method d->smtp.none->setEnabled( results.contains( Transport::EnumEncryption::None ) ); d->smtp.ssl->setEnabled( results.contains( Transport::EnumEncryption::SSL ) ); d->smtp.tls->setEnabled( results.contains( Transport::EnumEncryption::TLS ) ); checkHighestEnabledButton( d->encryptionGroup ); d->noEncCapa = d->serverTest->normalProtocols(); if ( d->smtp.tls->isEnabled() ) { d->tlsCapa = d->serverTest->tlsProtocols(); } else { d->tlsCapa.clear(); } d->sslCapa = d->serverTest->secureProtocols(); d->updateAuthCapbilities(); checkHighestEnabledButton( d->authGroup ); } void TransportConfigDialog::hostNameChanged( const QString &text ) { // sanitize hostname... if ( d->transport->type() == Transport::EnumType::Sendmail ) { d->sendmail.kcfg_host->blockSignals( true ); d->sendmail.kcfg_host->setText( text.trimmed() ); d->sendmail.kcfg_host->blockSignals( false ); } else if ( d->transport->type() == Transport::EnumType::SMTP ) { d->smtp.kcfg_host->blockSignals( true ); d->smtp.kcfg_host->setText( text.trimmed() ); d->smtp.kcfg_host->blockSignals( false ); } d->resetAuthCapabilities(); enableButton( Ok, !text.isEmpty() ); for ( int i = 0; d->encryptionGroup && i < d->encryptionGroup->buttons().count(); i++ ) { d->encryptionGroup->buttons().at( i )->setEnabled( true ); } } void TransportConfigDialog::ensureValidAuthSelection() { // adjust available authentication methods d->updateAuthCapbilities(); foreach ( QAbstractButton *b, d->authGroup->buttons() ) { if ( b->isChecked() && !b->isEnabled() ) { checkHighestEnabledButton( d->authGroup ); break; } } } void TransportConfigDialog::encryptionChanged( int enc ) { Q_ASSERT( d->transport->type() == Transport::EnumType::SMTP ); kDebug() << enc; // adjust port if ( enc == Transport::EnumEncryption::SSL ) { if ( d->smtp.kcfg_port->value() == SMTP_PORT ) { d->smtp.kcfg_port->setValue( SMTPS_PORT ); } } else { if ( d->smtp.kcfg_port->value() == SMTPS_PORT ) { d->smtp.kcfg_port->setValue( SMTP_PORT ); } } ensureValidAuthSelection(); } #include "transportconfigdialog.moc" diff --git a/mailtransport/transportmanager.h b/mailtransport/transportmanager.h index 73bd40327..4d750873b 100644 --- a/mailtransport/transportmanager.h +++ b/mailtransport/transportmanager.h @@ -1,252 +1,254 @@ /* 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_TRANSPORTMANAGER_H #define MAILTRANSPORT_TRANSPORTMANAGER_H #include #include #include class KJob; namespace KWallet { class Wallet; } namespace MailTransport { class Transport; class TransportJob; /** Takes care of loading and storing mail transport settings and creating of transport jobs. */ class MAILTRANSPORT_EXPORT TransportManager : public QObject { Q_OBJECT Q_CLASSINFO( "D-Bus Interface", "org.kde.pim.TransportManager" ) friend class Transport; friend class Private; public: class Private; /** Destructor. */ virtual ~TransportManager(); /** Returns the TransportManager instance. */ static TransportManager *self(); /** Tries to load passwords asynchronously from KWallet if needed. The passwordsChanged() signal is emitted once the passwords have been loaded. Nothing happens if the passwords were already available. */ void loadPasswordsAsync(); /** Returns the Transport object with the given id. @param id The identifier of the Transport. @param def if set to true, the default transport will be returned if the specified Transport object could not be found, 0 otherwise. @returns A Transport object for immediate use. It might become invalid as soon as the event loop is entered again due to remote changes. If you need to store a Transport object, store the transport identifier instead. */ Transport *transportById( int id, bool def = true ) const; /** Returns the transport object with the given name. @param name The transport name. @param def if set to true, the default transport will be returned if the specified Transport object could not be found, 0 otherwise. @returns A Transport object for immediate use, see transportById() for limitations. */ Transport *transportByName( const QString &name, bool def = true ) const; /** Returns a list of all available transports. Note: The Transport objects become invalid as soon as a change occur, so they are only suitable for immediate use. */ QListtransports() const; /** Creates a new, empty Transport object. The object is owned by the caller. If you want to add the Transport permanently (eg. after configuring it) call addTransport(). */ Transport *createTransport() const; /** Adds the given transport. The object ownership is transferred to TransportMananger, ie. you must not delete @p transport. @param transport The Transport object to add. */ void addTransport( Transport *transport ); /** Creates a mail transport job for the given transport identifier. Returns 0 if the specified transport is invalid. @param transportId The transport identifier. */ TransportJob *createTransportJob( int transportId ); /** Creates a mail transport job for the given transport identifer, or transport name. Returns 0 if the specified transport is invalid. @param transport A string defining a mail transport. */ TransportJob *createTransportJob( const QString &transport ); /** Executes the given transport job. This is the preferred way to start transport jobs. It takes care of asynchronously loading passwords from KWallet if necessary. @param job The completely configured transport job to execute. */ void schedule( TransportJob *job ); /** Tries to create a transport based on KEMailSettings. If the data in KEMailSettings is incomplete, no transport is created. */ void createDefaultTransport(); public Q_SLOTS: /** Returns true if there are no mail transports at all. */ Q_SCRIPTABLE bool isEmpty() const; /** Returns a list of transport identifiers. */ Q_SCRIPTABLE QList transportIds() const; /** Returns a list of transport names. */ Q_SCRIPTABLE QStringList transportNames() const; /** Returns the default transport name. */ Q_SCRIPTABLE QString defaultTransportName() const; /** Returns the default transport identifier. Invalid if there are no transports at all. */ Q_SCRIPTABLE int defaultTransportId() const; /** Sets the default transport. The change will be in effect immediately. @param id The identifier of the new default transport. */ Q_SCRIPTABLE void setDefaultTransport( int id ); /** Deletes the specified transport. @param id The identifier of the mail transport to remove. */ Q_SCRIPTABLE void removeTransport( int id ); Q_SIGNALS: /** Emitted when transport settings have changed (by this or any other TransportManager instance). */ Q_SCRIPTABLE void transportsChanged(); /** Internal signal to synchronize all TransportManager instances. This signal is emitted by the instance writing the changes. You probably want to use transportsChanged() instead. */ Q_SCRIPTABLE void changesCommitted(); /** Emitted when passwords have been loaded from the wallet. + If you made a deep copy of a transport, you should call updatePasswordState() + for the cloned transport to ensure its password is updated as well. */ void passwordsChanged(); /** Emitted when a transport is deleted. @param id The identifier of the deleted transport. @param name The name of the deleted transport. */ void transportRemoved( int id, const QString &name ); /** Emitted when a transport has been renamed. @param id The identifier of the renamed transport. @param oldName The old name. @param newName The new name. */ void transportRenamed( int id, const QString &oldName, const QString &newName ); protected: /** Returns a pointer to an open wallet if available, 0 otherwise. The wallet is opened synchronously if necessary. */ KWallet::Wallet *wallet(); /** Loads all passwords synchronously. */ void loadPasswords(); TransportManager(); private: void readConfig(); void writeConfig(); void emitChangesCommitted(); int createId() const; void prepareWallet(); void validateDefault(); void migrateToWallet(); private Q_SLOTS: void slotTransportsChanged(); void slotWalletOpened( bool success ); void dbusServiceOwnerChanged( const QString &service, const QString &oldOwner, const QString &newOwner ); void jobResult( KJob *job ); private: Private *const d; }; } #endif