You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

394 lines
12 KiB

/** -*- c++ -*-
* networkaccount.cpp
*
* Copyright (c) 2000-2002 Michael Haeckel <haeckel@kde.org>
* Copyright (c) 2002 Marc Mutz <mutz@kde.org>
*
* This file is based on work on pop3 and imap account implementations
* by Don Sanders <sanders@kde.org> and Michael Haeckel <haeckel@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "networkaccount.h"
#include "accountmanager.h"
#include "kmkernel.h"
#include "globalsettings.h"
#include <kconfiggroup.h>
#include <kio/global.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kstringhandler.h>
#include <kdebug.h>
#include <kwallet.h>
using KIO::MetaData;
using KWallet::Wallet;
#include <climits>
namespace KMail {
// for restricting number of concurrent connections to the same server
static QMap<QString, int> s_serverConnections;
NetworkAccount::NetworkAccount( AccountManager * parent, const QString & name, uint id )
: KMAccount( parent, name, id ),
mSlave( 0 ),
mAuth( "*" ),
mPort( 0 ),
mStorePasswd( false ),
mUseSSL( false ),
mUseTLS( false ),
mAskAgain( false ),
mPasswdDirty( false ),
mStorePasswdInConfig( false )
{
}
NetworkAccount::~NetworkAccount() {
}
void NetworkAccount::init() {
KMAccount::init();
mLogin.clear();
mPasswd.clear();
mAuth = "*";
mHost.clear();
mPort = defaultPort();
mStorePasswd = false;
mUseSSL = false;
mUseTLS = false;
mAskAgain = false;
}
//
//
// Getters and Setters
//
//
void NetworkAccount::setLogin( const QString & login ) {
mLogin = login;
}
QString NetworkAccount::passwd() const {
if ( storePasswd() && mPasswd.isEmpty() )
mOwner->readPasswords();
return KStringHandler::obscure( mPasswd );
}
void NetworkAccount::setPasswd( const QString & passwd, bool storeInConfig ) {
if ( mPasswd != KStringHandler::obscure( passwd ) ) {
mPasswd = KStringHandler::obscure( passwd );
mPasswdDirty = true;
}
setStorePasswd( storeInConfig );
}
void NetworkAccount::clearPasswd() {
setPasswd( "", false );
}
void NetworkAccount::setAuth( const QString & auth ) {
mAuth = auth;
}
void NetworkAccount::setStorePasswd( bool store ) {
if( mStorePasswd != store && store )
mPasswdDirty = true;
mStorePasswd = store;
if ( !store )
mStorePasswdInConfig = false;
}
void NetworkAccount::setHost( const QString & host ) {
mHost = host;
}
void NetworkAccount::setPort( unsigned short int port ) {
mPort = port;
}
void NetworkAccount::setUseSSL( bool use ) {
mUseSSL = use;
}
void NetworkAccount::setUseTLS( bool use ) {
mUseTLS = use;
}
void NetworkAccount::setSieveConfig( const SieveConfig & config ) {
mSieveConfig = config;
}
//
//
// read/write config
//
//
void NetworkAccount::readConfig( KConfigGroup & config ) {
KMAccount::readConfig( config );
setLogin( config.readEntry( "login" ) );
if ( config.readEntry( "store-passwd", false ) ) {
mStorePasswd = true;
QString encpasswd = config.readEntry( "pass" );
if ( encpasswd.isEmpty() ) {
encpasswd = config.readEntry( "passwd" );
if ( !encpasswd.isEmpty() ) encpasswd = importPassword( encpasswd );
}
if ( !encpasswd.isEmpty() ) {
setPasswd( KStringHandler::obscure( encpasswd ), true );
mOldPassKey = encpasswd;
mPasswdDirty = false; // set by setPasswd() on first read
mStorePasswdInConfig = true;
} else {
// read password if wallet is already open, otherwise defer to on-demand loading
if ( Wallet::isOpen( Wallet::NetworkWallet() ) )
readPassword();
}
} else {
setPasswd( "", false );
}
setHost( config.readEntry( "host" ) );
unsigned int port = config.readEntry( "port", (uint)defaultPort() );
if ( port > USHRT_MAX ) port = defaultPort();
setPort( port );
setAuth( config.readEntry( "auth", "*" ) );
setUseSSL( config.readEntry( "use-ssl", false ) );
setUseTLS( config.readEntry( "use-tls", false ) );
mSieveConfig.readConfig( config );
}
void NetworkAccount::writeConfig( KConfigGroup & config ) {
KMAccount::writeConfig( config );
if ( storePasswd() ) {
// write password to the wallet if possible and necessary
bool passwdStored = false;
//If the password is different from the one stored in the config,
//try to store the new password in the wallet again.
//This ensures a malicious user can't just write a dummy pass key in the
//config, which would get overwritten by the real password and therefore
//leak out of the more secure wallet.
if ( mStorePasswdInConfig &&
KStringHandler::obscure( mOldPassKey ) != passwd() )
mStorePasswdInConfig = false;
//If the password should be written to the wallet, do that
if ( !mStorePasswdInConfig ) {
Wallet *wallet = kmkernel->wallet();
//If the password is dirty, try to store it in the wallet
if ( mPasswdDirty ) {
if ( wallet && wallet->writePassword( "account-" + QString::number(mId), passwd() ) == 0 )
passwdStored = true;
}
//If the password isn't dirty, it is already stored in the wallet.
else if ( wallet )
passwdStored = true;
//If the password is stored in the wallet, it isn't dirty or stored in the config
if ( passwdStored ) {
mPasswdDirty = false;
mStorePasswdInConfig = false;
}
}
else
passwdStored = config.hasKey("pass");
// if wallet is not available, write to config file, since the account
// manager deletes this group, we need to write it always
bool writeInConfigNow = !passwdStored && mStorePasswdInConfig;
if ( !passwdStored && !mStorePasswdInConfig ) {
int answer = KMessageBox::warningYesNo( 0,
i18n("KWallet is not available. It is strongly recommended to use "
"KWallet for managing your passwords.\n"
"However, KMail can store the password in its 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 account '%1' in the "
"configuration file?", name() ),
i18n("KWallet Not Available"),
KGuiItem( i18n("Store Password") ),
KGuiItem( i18n("Do Not Store Password") ) );
if (answer == KMessageBox::Yes)
writeInConfigNow = true;
if (answer == KMessageBox::No)
mStorePasswd = false;
}
if ( writeInConfigNow ) {
config.writeEntry( "pass", KStringHandler::obscure( passwd() ) );
mOldPassKey = KStringHandler::obscure( passwd() );
mStorePasswdInConfig = true;
}
}
// delete password from the wallet if password storage is disabled
if (!storePasswd() && !Wallet::keyDoesNotExist(
Wallet::NetworkWallet(), "kmail", "account-" + QString::number(mId))) {
Wallet *wallet = kmkernel->wallet();
if (wallet)
wallet->removeEntry( "account-" + QString::number(mId) );
}
// delete password from config file if it is stored in the wallet or
// not stored at all
if ( !mStorePasswdInConfig )
config.deleteEntry( "pass" );
config.writeEntry( "store-passwd", storePasswd() );
config.writeEntry( "login", login() );
config.writeEntry( "host", host() );
config.writeEntry( "port", static_cast<unsigned int>( port() ) );
config.writeEntry( "auth", auth() );
config.writeEntry( "use-ssl", useSSL() );
config.writeEntry( "use-tls", useTLS() );
mSieveConfig.writeConfig( config );
}
//
//
// Network processing
//
//
KUrl NetworkAccount::getUrl() const {
KUrl url;
url.setProtocol( protocol() );
url.setUser( login() );
url.setPass( passwd() );
url.setHost( host() );
url.setPort( port() );
return url;
}
MetaData NetworkAccount::slaveConfig() const {
MetaData m;
m.insert( "tls", useTLS() ? "on" : "off" );
return m;
}
void NetworkAccount::pseudoAssign( const KMAccount * a ) {
KMAccount::pseudoAssign( a );
const NetworkAccount * n = dynamic_cast<const NetworkAccount*>( a );
if ( !n ) return;
setLogin( n->login() );
setPasswd( n->passwd(), n->storePasswd() );
setHost( n->host() );
setPort( n->port() );
setAuth( n->auth() );
setUseSSL( n->useSSL() );
setUseTLS( n->useTLS() );
setSieveConfig( n->sieveConfig() );
}
void NetworkAccount::readPassword() {
if ( !storePasswd() )
return;
// ### workaround for broken Wallet::keyDoesNotExist() which returns wrong
// results for new entries without closing and reopening the wallet
if ( Wallet::isOpen( Wallet::NetworkWallet() ) )
{
Wallet *wallet = kmkernel->wallet();
if (!wallet || !wallet->hasEntry( "account-" + QString::number(mId) ) )
return;
}
else
{
if (Wallet::keyDoesNotExist( Wallet::NetworkWallet(), "kmail", "account-" + QString::number(mId) ) )
return;
}
if ( kmkernel->wallet() ) {
QString passwd;
kmkernel->wallet()->readPassword( "account-" + QString::number(mId), passwd );
setPasswd( passwd, true );
mPasswdDirty = false;
}
}
void NetworkAccount::setCheckingMail( bool checking )
{
mCheckingMail = checking;
if ( host().isEmpty() )
return;
if ( checking ) {
if ( s_serverConnections.find( host() ) != s_serverConnections.end() )
s_serverConnections[host()] += 1;
else
s_serverConnections[host()] = 1;
kDebug(5006) <<"check mail started - connections for host"
<< host() << "now is"
<< s_serverConnections[host()];
} else {
if ( s_serverConnections.find( host() ) != s_serverConnections.end() &&
s_serverConnections[host()] > 0 ) {
s_serverConnections[host()] -= 1;
kDebug(5006) <<"connections to server" << host()
<< "now" << s_serverConnections[host()];
}
}
}
bool NetworkAccount::mailCheckCanProceed() const
{
bool offlineMode = KMKernel::isOffline();
kDebug(5006) <<"for host" << host()
<< "current connections="
<< (s_serverConnections.find(host())==s_serverConnections.end() ? 0 : s_serverConnections[host()])
<< "and limit is" << GlobalSettings::self()->maxConnectionsPerHost();
bool connectionLimitForHostReached = !host().isEmpty()
&& GlobalSettings::self()->maxConnectionsPerHost() > 0
&& s_serverConnections.find( host() ) != s_serverConnections.end()
&& s_serverConnections[host()] >= GlobalSettings::self()->maxConnectionsPerHost();
kDebug(5006) <<"connection limit reached:"
<< connectionLimitForHostReached;
return ( !connectionLimitForHostReached && !offlineMode );
}
void NetworkAccount::resetConnectionList( NetworkAccount* acct )
{
s_serverConnections[ acct->host() ] = 0;
}
} // namespace KMail
#include "networkaccount.moc"