/** -*- c++ -*- * networkaccount.cpp * * Copyright (c) 2000-2002 Michael Haeckel * Copyright (c) 2002 Marc Mutz * * This file is based on work on pop3 and imap account implementations * by Don Sanders and Michael Haeckel * * 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 #include #include #include #include #include #include using KIO::MetaData; using KWallet::Wallet; #include namespace KMail { // for restricting number of concurrent connections to the same server static QMap 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(); mSieveConfig = SieveConfig(); 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( 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( 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"