kde-playground/kdepim-runtime/resources/imap/settings.cpp
2015-04-14 22:08:21 +00:00

329 lines
11 KiB
C++

/*
Copyright (c) 2008 Volker Krause <vkrause@kde.org>
Copyright (c) 2008 Omat Holding B.V. <info@omat.nl>
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 "settings.h"
#include "settingsadaptor.h"
#include "imapaccount.h"
#include <kwallet.h>
using KWallet::Wallet;
#include <klocale.h>
#include <kpassworddialog.h>
#include <QDBusConnection>
#include <KDE/Akonadi/Collection>
#include <KDE/Akonadi/CollectionFetchJob>
#include <KDE/Akonadi/CollectionModifyJob>
/**
* Maps the enum used to represent authentication in MailTransport (kdepimlibs)
* to the one used by the imap resource.
* @param authType the MailTransport auth enum value
* @return the corresponding KIMAP auth value.
* @note will cause fatal error if there is no mapping, so be careful not to pass invalid auth options (e.g., APOP) to this function.
*/
KIMAP::LoginJob::AuthenticationMode Settings::mapTransportAuthToKimap( MailTransport::Transport::EnumAuthenticationType::type authType )
{
// typedef these for readability
typedef MailTransport::Transport::EnumAuthenticationType MTAuth;
typedef KIMAP::LoginJob KIAuth;
switch ( authType ) {
case MTAuth::ANONYMOUS:
return KIAuth::Anonymous;
case MTAuth::PLAIN:
return KIAuth::Plain;
case MTAuth::NTLM:
return KIAuth::NTLM;
case MTAuth::LOGIN:
return KIAuth::Login;
case MTAuth::GSSAPI:
return KIAuth::GSSAPI;
case MTAuth::DIGEST_MD5:
return KIAuth::DigestMD5;
case MTAuth::CRAM_MD5:
return KIAuth::CramMD5;
case MTAuth::CLEAR:
return KIAuth::ClearText;
default:
kFatal() << "mapping from Transport::EnumAuthenticationType -> KIMAP::LoginJob::AuthenticationMode not possible";
}
return KIAuth::ClearText; // dummy value, shouldn't get here.
}
Settings::Settings( WId winId ) : SettingsBase(), m_winId( winId )
{
readConfig();
new SettingsAdaptor( this );
QDBusConnection::sessionBus().registerObject( QLatin1String( "/Settings" ), this, QDBusConnection::ExportAdaptors | QDBusConnection::ExportScriptableContents );
}
void Settings::setWinId( WId winId )
{
m_winId = winId;
}
void Settings::clearCachedPassword()
{
m_password.clear();
}
void Settings::cleanup()
{
Wallet* wallet = Wallet::openWallet( Wallet::NetworkWallet(), m_winId );
if ( wallet && wallet->isOpen() ) {
if ( wallet->hasFolder( QLatin1String("imap") ) ) {
wallet->setFolder( QLatin1String("imap") );
wallet->removeEntry( config()->name() );
}
delete wallet;
}
}
void Settings::requestPassword()
{
if ( !m_password.isEmpty() ||
( mapTransportAuthToKimap( (MailTransport::TransportBase::EnumAuthenticationType::type)authentication() ) == KIMAP::LoginJob::GSSAPI ) ) {
emit passwordRequestCompleted( m_password, false );
} else {
Wallet *wallet = Wallet::openWallet( Wallet::NetworkWallet(), m_winId, Wallet::Asynchronous );
if ( wallet ) {
connect( wallet, SIGNAL(walletOpened(bool)),
this, SLOT(onWalletOpened(bool)) );
} else {
QMetaObject::invokeMethod( this, "onWalletOpened", Qt::QueuedConnection, Q_ARG(bool, true) );
}
}
}
void Settings::onWalletOpened( bool success )
{
if ( !success ) {
emit passwordRequestCompleted( QString(), true );
} else {
Wallet *wallet = qobject_cast<Wallet*>( sender() );
bool passwordNotStoredInWallet = true;
if ( wallet && wallet->hasFolder( QLatin1String("imap") ) ) {
wallet->setFolder( QLatin1String("imap") );
wallet->readPassword( config()->name(), m_password );
passwordNotStoredInWallet = false;
}
if ( passwordNotStoredInWallet || m_password.isEmpty() )
requestManualAuth();
else
emit passwordRequestCompleted( m_password, passwordNotStoredInWallet );
if ( wallet ) {
wallet->deleteLater();
}
}
}
void Settings::requestManualAuth()
{
KPasswordDialog *dlg = new KPasswordDialog( 0 );
dlg->setModal( true );
dlg->setPrompt( i18n( "Please enter password for user '%1' on IMAP server '%2'.",
userName(), imapServer() ) );
dlg->setAttribute( Qt::WA_DeleteOnClose );
connect( dlg, SIGNAL(finished(int)), this, SLOT(onDialogFinished(int)) );
dlg->show();
}
void Settings::onDialogFinished( int result )
{
if ( result == QDialog::Accepted ) {
KPasswordDialog *dlg = qobject_cast<KPasswordDialog*>( sender() );
setPassword( dlg->password() );
emit passwordRequestCompleted( dlg->password(), false );
} else {
emit passwordRequestCompleted( QString(), true );
}
}
QString Settings::password(bool *userRejected) const
{
if ( userRejected != 0 ) {
*userRejected = false;
}
if ( !m_password.isEmpty() ||
( mapTransportAuthToKimap( (MailTransport::TransportBase::EnumAuthenticationType::type)authentication() ) == KIMAP::LoginJob::GSSAPI ) )
return m_password;
Wallet* wallet = Wallet::openWallet( Wallet::NetworkWallet(), m_winId );
if ( wallet && wallet->isOpen() ) {
if ( wallet->hasFolder( QLatin1String("imap") ) ) {
wallet->setFolder( QLatin1String("imap") );
wallet->readPassword( config()->name(), m_password );
} else {
wallet->createFolder( QLatin1String("imap") );
}
} else if ( userRejected != 0 ) {
*userRejected = true;
}
delete wallet;
return m_password;
}
QString Settings::sieveCustomPassword(bool *userRejected) const
{
if ( userRejected != 0 ) {
*userRejected = false;
}
if ( !m_customSievePassword.isEmpty() )
return m_customSievePassword;
Wallet* wallet = Wallet::openWallet( Wallet::NetworkWallet(), m_winId );
if ( wallet && wallet->isOpen() ) {
if ( wallet->hasFolder( QLatin1String("imap") ) ) {
wallet->setFolder( QLatin1String("imap") );
wallet->readPassword( QLatin1String("custom_sieve_") + config()->name(), m_customSievePassword );
} else {
wallet->createFolder( QLatin1String("imap") );
}
} else if ( userRejected != 0 ) {
*userRejected = true;
}
delete wallet;
return m_customSievePassword;
}
void Settings::setSieveCustomPassword(const QString & password)
{
if (m_customSievePassword == password)
return;
m_customSievePassword = password;
Wallet* wallet = Wallet::openWallet( Wallet::NetworkWallet(), m_winId );
if ( wallet && wallet->isOpen() ) {
if ( !wallet->hasFolder( QLatin1String("imap") ) )
wallet->createFolder( QLatin1String("imap") );
wallet->setFolder( QLatin1String("imap") );
wallet->writePassword( QLatin1String("custom_sieve_") + config()->name(), password );
kDebug() << "Wallet save: " << wallet->sync();
}
delete wallet;
}
void Settings::setPassword( const QString & password )
{
if ( password == m_password )
return;
if ( mapTransportAuthToKimap( (MailTransport::TransportBase::EnumAuthenticationType::type)authentication() ) == KIMAP::LoginJob::GSSAPI )
return;
m_password = password;
Wallet* wallet = Wallet::openWallet( Wallet::NetworkWallet(), m_winId );
if ( wallet && wallet->isOpen() ) {
if ( !wallet->hasFolder( QLatin1String("imap") ) )
wallet->createFolder( QLatin1String("imap") );
wallet->setFolder( QLatin1String("imap") );
wallet->writePassword( config()->name(), password );
kDebug() << "Wallet save: " << wallet->sync();
}
delete wallet;
}
void Settings::loadAccount( ImapAccount *account ) const
{
account->setServer( imapServer() );
if ( imapPort()>=0 ) {
account->setPort( imapPort() );
}
account->setUserName( userName() );
account->setSubscriptionEnabled( subscriptionEnabled() );
const QString encryption = safety();
if ( encryption == QLatin1String("SSL") ) {
account->setEncryptionMode( KIMAP::LoginJob::AnySslVersion );
} else if ( encryption == QLatin1String("STARTTLS") ) {
//KIMAP confused TLS and STARTTLS, TlsV1 really means "use STARTTLS"
account->setEncryptionMode( KIMAP::LoginJob::TlsV1 );
} else {
account->setEncryptionMode( KIMAP::LoginJob::Unencrypted );
}
//Some SSL Server fail to advertise an ssl version they support (AnySslVersion),
//we therefore allow overriding this in the config
//(so we don't have to make the UI unnecessarily complex for properly working servers).
const QString overrideEncryptionMode = overrideEncryption();
if (!overrideEncryptionMode.isEmpty()) {
kWarning() << "Overriding encryption mode with: " << overrideEncryptionMode;
if ( overrideEncryptionMode == QLatin1String("SSLV2") ) {
account->setEncryptionMode( KIMAP::LoginJob::SslV2 );
} else if ( overrideEncryptionMode == QLatin1String("SSLV3") ) {
account->setEncryptionMode( KIMAP::LoginJob::SslV3 );
} else if ( overrideEncryptionMode == QLatin1String("TLSV1") ) {
account->setEncryptionMode( KIMAP::LoginJob::SslV3_1 );
} else if ( overrideEncryptionMode == QLatin1String("SSL") ) {
account->setEncryptionMode( KIMAP::LoginJob::AnySslVersion );
} else if ( overrideEncryptionMode == QLatin1String("STARTTLS") ) {
account->setEncryptionMode( KIMAP::LoginJob::TlsV1 );
} else if ( overrideEncryptionMode == QLatin1String("UNENCRYPTED") ) {
account->setEncryptionMode( KIMAP::LoginJob::Unencrypted );
} else {
kWarning() << "Tried to force invalid encryption mode: " << overrideEncryptionMode;
}
}
account->setAuthenticationMode(
mapTransportAuthToKimap(
(MailTransport::TransportBase::EnumAuthenticationType::type) authentication()
)
);
account->setTimeout( sessionTimeout() );
}
QString Settings::rootRemoteId() const
{
return QLatin1String("imap://") + userName() + QLatin1Char('@') + imapServer() + QLatin1Char('/');
}
void Settings::renameRootCollection( const QString &newName )
{
Akonadi::Collection rootCollection;
rootCollection.setRemoteId( rootRemoteId() );
Akonadi::CollectionFetchJob *fetchJob =
new Akonadi::CollectionFetchJob( rootCollection, Akonadi::CollectionFetchJob::Base );
fetchJob->setProperty( "collectionName", newName );
connect( fetchJob, SIGNAL(result(KJob*)),
this, SLOT(onRootCollectionFetched(KJob*)) );
}
void Settings::onRootCollectionFetched( KJob *job )
{
const QString newName = job->property( "collectionName" ).toString();
Q_ASSERT( !newName.isEmpty() );
Akonadi::CollectionFetchJob *fetchJob = static_cast<Akonadi::CollectionFetchJob*>( job );
if ( fetchJob->collections().size() == 1 ) {
Akonadi::Collection rootCollection = fetchJob->collections().first();
rootCollection.setName( newName );
new Akonadi::CollectionModifyJob( rootCollection );
// We don't care about the result here, nothing we can/should do if the renaming fails
}
}