kmail

networkaccount.cpp

Go to the documentation of this file.
00001 
00026 #ifdef HAVE_CONFIG_H
00027 #include <config.h>
00028 #endif
00029 
00030 #include "networkaccount.h"
00031 #include "accountmanager.h"
00032 #include "kmkernel.h"
00033 #include "globalsettings.h"
00034 
00035 #include <kconfig.h>
00036 #include <kio/global.h>
00037 #include <klocale.h>
00038 #include <kmessagebox.h>
00039 #include <kdebug.h>
00040 #include <kwallet.h>
00041 using KIO::MetaData;
00042 using KWallet::Wallet;
00043 
00044 #include <climits>
00045 
00046 namespace KMail {
00047 
00048     
00049  // for restricting number of concurrent connections to the same server
00050   static QMap<QString, int> s_serverConnections;
00051 
00052   NetworkAccount::NetworkAccount( AccountManager * parent, const QString & name, uint id )
00053     : KMAccount( parent, name, id ),
00054       mSlave( 0 ),
00055       mAuth( "*" ),
00056       mPort( 0 ),
00057       mStorePasswd( false ),
00058       mUseSSL( false ),
00059       mUseTLS( false ),
00060       mAskAgain( false ),
00061       mPasswdDirty( false ),
00062       mStorePasswdInConfig( false )
00063   {
00064 
00065   }
00066 
00067   NetworkAccount::~NetworkAccount() {
00068 
00069   }
00070 
00071   void NetworkAccount::init() {
00072     KMAccount::init();
00073 
00074     mSieveConfig = SieveConfig();
00075     mLogin = QString::null;
00076     mPasswd = QString::null;
00077     mAuth = "*";
00078     mHost = QString::null;
00079     mPort = defaultPort();
00080     mStorePasswd = false;
00081     mUseSSL = false;
00082     mUseTLS = false;
00083     mAskAgain = false;
00084   }
00085 
00086   //
00087   //
00088   // Getters and Setters
00089   //
00090   //
00091 
00092   void NetworkAccount::setLogin( const QString & login ) {
00093     mLogin = login;
00094   }
00095 
00096   QString NetworkAccount::passwd() const {
00097     if ( storePasswd() && mPasswd.isEmpty() )
00098       mOwner->readPasswords();
00099     return decryptStr( mPasswd );
00100   }
00101 
00102   void NetworkAccount::setPasswd( const QString & passwd, bool storeInConfig ) {
00103     if ( mPasswd != encryptStr( passwd ) ) {
00104       mPasswd = encryptStr( passwd );
00105       mPasswdDirty = true;
00106     }
00107     setStorePasswd( storeInConfig );
00108   }
00109 
00110   void NetworkAccount::clearPasswd() {
00111     setPasswd( "", false );
00112   }
00113 
00114   void NetworkAccount::setAuth( const QString & auth ) {
00115     mAuth = auth;
00116   }
00117 
00118   void NetworkAccount::setStorePasswd( bool store ) {
00119     if( mStorePasswd != store && store )
00120       mPasswdDirty = true;
00121     mStorePasswd = store;
00122   }
00123 
00124   void NetworkAccount::setHost( const QString & host ) {
00125     mHost = host;
00126   }
00127 
00128   void NetworkAccount::setPort( unsigned short int port ) {
00129     mPort = port;
00130   }
00131 
00132   void NetworkAccount::setUseSSL( bool use ) {
00133     mUseSSL = use;
00134   }
00135 
00136   void NetworkAccount::setUseTLS( bool use ) {
00137     mUseTLS = use;
00138   }
00139 
00140   void NetworkAccount::setSieveConfig( const SieveConfig & config ) {
00141     mSieveConfig = config;
00142   }
00143 
00144   //
00145   //
00146   // read/write config
00147   //
00148   //
00149 
00150   void NetworkAccount::readConfig( /*const*/ KConfig/*Base*/ & config ) {
00151     KMAccount::readConfig( config );
00152 
00153     setLogin( config.readEntry( "login" ) );
00154 
00155     if ( config.readNumEntry( "store-passwd", false ) ) { // ### s/Num/Bool/
00156       mStorePasswd = true;
00157       QString encpasswd = config.readEntry( "pass" );
00158       if ( encpasswd.isEmpty() ) {
00159         encpasswd = config.readEntry( "passwd" );
00160         if ( !encpasswd.isEmpty() ) encpasswd = importPassword( encpasswd );
00161       }
00162 
00163       if ( !encpasswd.isEmpty() ) {
00164         setPasswd( decryptStr( encpasswd ), true );
00165         // migrate to KWallet if available
00166         if ( Wallet::isEnabled() ) {
00167           config.deleteEntry( "pass" );
00168           config.deleteEntry( "passwd" );
00169           mPasswdDirty = true;
00170           mStorePasswdInConfig = false;
00171         } else {
00172           mPasswdDirty = false; // set by setPasswd() on first read
00173           mStorePasswdInConfig = true;
00174         }
00175       } else {
00176         // read password if wallet is already open, otherwise defer to on-demand loading
00177         if ( Wallet::isOpen( Wallet::NetworkWallet() ) )
00178           readPassword();
00179       }
00180 
00181     } else {
00182       setPasswd( "", false );
00183     }
00184 
00185     setHost( config.readEntry( "host" ) );
00186 
00187     unsigned int port = config.readUnsignedNumEntry( "port", defaultPort() );
00188     if ( port > USHRT_MAX ) port = defaultPort();
00189     setPort( port );
00190 
00191     setAuth( config.readEntry( "auth", "*" ) );
00192     setUseSSL( config.readBoolEntry( "use-ssl", false ) );
00193     setUseTLS( config.readBoolEntry( "use-tls", false ) );
00194 
00195     mSieveConfig.readConfig( config );
00196   }
00197 
00198   void NetworkAccount::writeConfig( KConfig/*Base*/ & config ) /*const*/ {
00199     KMAccount::writeConfig( config );
00200 
00201     config.writeEntry( "login", login() );
00202     config.writeEntry( "store-passwd", storePasswd() );
00203 
00204     if ( storePasswd() ) {
00205       // write password to the wallet if possbile and necessary
00206       bool passwdStored = false;
00207       if ( mPasswdDirty ) {
00208         Wallet *wallet = kmkernel->wallet();
00209         if ( wallet && wallet->writePassword( "account-" + QString::number(mId), passwd() ) == 0 ) {
00210           passwdStored = true;
00211           mPasswdDirty = false;
00212           mStorePasswdInConfig = false;
00213         }
00214       } else {
00215         passwdStored = !mStorePasswdInConfig; // already in the wallet
00216       }
00217       // if wallet is not available, write to config file, since the account
00218       // manager deletes this group, we need to write it always
00219       if ( !passwdStored && ( mStorePasswdInConfig || KMessageBox::warningYesNo( 0,
00220            i18n("KWallet is not available. It is strongly recommended to use "
00221                 "KWallet for managing your passwords.\n"
00222                 "However, KMail can store the password in its configuration "
00223                 "file instead. The password is stored in an obfuscated format, "
00224                 "but should not be considered secure from decryption efforts "
00225                 "if access to the configuration file is obtained.\n"
00226                 "Do you want to store the password for account '%1' in the "
00227                 "configuration file?").arg( name() ),
00228            i18n("KWallet Not Available"),
00229            KGuiItem( i18n("Store Password") ),
00230            KGuiItem( i18n("Do Not Store Password") ) )
00231            == KMessageBox::Yes ) ) {
00232         config.writeEntry( "pass", encryptStr( passwd() ) );
00233         mStorePasswdInConfig = true;
00234       }
00235     }
00236 
00237     // delete password from the wallet if password storage is disabled
00238     if (!storePasswd() && !Wallet::keyDoesNotExist(
00239         Wallet::NetworkWallet(), "kmail", "account-" + QString::number(mId))) {
00240       Wallet *wallet = kmkernel->wallet();
00241       if (wallet)
00242         wallet->removeEntry( "account-" + QString::number(mId) );
00243     }
00244 
00245     config.writeEntry( "host", host() );
00246     config.writeEntry( "port", static_cast<unsigned int>( port() ) );
00247     config.writeEntry( "auth", auth() );
00248     config.writeEntry( "use-ssl", useSSL() );
00249     config.writeEntry( "use-tls", useTLS() );
00250 
00251     mSieveConfig.writeConfig( config );
00252   }
00253 
00254   //
00255   //
00256   // Network processing
00257   //
00258   //
00259 
00260   KURL NetworkAccount::getUrl() const {
00261     KURL url;
00262     url.setProtocol( protocol() );
00263     url.setUser( login() );
00264     url.setPass( passwd() );
00265     url.setHost( host() );
00266     url.setPort( port() );
00267     return url;
00268   }
00269 
00270   MetaData NetworkAccount::slaveConfig() const {
00271     MetaData m;
00272     m.insert( "tls", useTLS() ? "on" : "off" );
00273     return m;
00274   }
00275 
00276   void NetworkAccount::pseudoAssign( const KMAccount * a ) {
00277     KMAccount::pseudoAssign( a );
00278 
00279     const NetworkAccount * n = dynamic_cast<const NetworkAccount*>( a );
00280     if ( !n ) return;
00281 
00282     setLogin( n->login() );
00283     setPasswd( n->passwd(), n->storePasswd() );
00284     setHost( n->host() );
00285     setPort( n->port() );
00286     setAuth( n->auth() );
00287     setUseSSL( n->useSSL() );
00288     setUseTLS( n->useTLS() );
00289     setSieveConfig( n->sieveConfig() );
00290   }
00291 
00292   void NetworkAccount::readPassword() {
00293     if ( !storePasswd() )
00294       return;
00295 
00296     // ### workaround for broken Wallet::keyDoesNotExist() which returns wrong
00297     // results for new entries without closing and reopening the wallet
00298     if ( Wallet::isOpen( Wallet::NetworkWallet() ) )
00299     {
00300        Wallet *wallet = kmkernel->wallet();
00301        if (!wallet || !wallet->hasEntry( "account-" + QString::number(mId) ) )
00302          return;
00303     }
00304     else
00305     {
00306        if (Wallet::keyDoesNotExist( Wallet::NetworkWallet(), "kmail", "account-" + QString::number(mId) ) )
00307          return;
00308     }
00309 
00310     if ( kmkernel->wallet() ) {
00311       QString passwd;
00312       kmkernel->wallet()->readPassword( "account-" + QString::number(mId), passwd );
00313       setPasswd( passwd, true );
00314       mPasswdDirty = false;
00315     }
00316   }
00317 
00318   void NetworkAccount::setCheckingMail( bool checking )
00319   {
00320       mCheckingMail = checking;
00321       if ( host().isEmpty() )
00322           return;
00323     if ( checking ) {
00324         if ( s_serverConnections.find( host() ) != s_serverConnections.end() )
00325             s_serverConnections[host()] += 1;
00326         else
00327             s_serverConnections[host()] = 1;
00328         kdDebug(5006) << "check mail started - connections for host "
00329                 << host() << " now is "
00330                 << s_serverConnections[host()] << endl;
00331     } else {
00332             if ( s_serverConnections.find( host() ) != s_serverConnections.end() &&
00333                 s_serverConnections[host()] > 0 ) {
00334                 s_serverConnections[host()] -= 1;
00335                 kdDebug(5006) << "connections to server " << host()
00336                         << " now " << s_serverConnections[host()] << endl;
00337             }
00338     }
00339 }
00340   
00341   bool NetworkAccount::mailCheckCanProceed() const
00342   {
00343       bool offlineMode = KMKernel::isOffline();
00344 
00345       kdDebug(5006) << "for host " << host()
00346               << " current connections="
00347               << (s_serverConnections.find(host())==s_serverConnections.end() ? 0 : s_serverConnections[host()])
00348               << " and limit is " << GlobalSettings::self()->maxConnectionsPerHost()
00349               << endl;
00350       bool connectionLimitForHostReached = !host().isEmpty()
00351               && GlobalSettings::self()->maxConnectionsPerHost() > 0
00352               && s_serverConnections.find( host() ) != s_serverConnections.end()
00353               && s_serverConnections[host()] >= GlobalSettings::self()->maxConnectionsPerHost();
00354       kdDebug(5006) << "connection limit reached: "
00355               << connectionLimitForHostReached << endl;
00356       
00357       return ( !connectionLimitForHostReached && !offlineMode );
00358   }
00359 
00360   void NetworkAccount::resetConnectionList( NetworkAccount* acct )
00361   {
00362     s_serverConnections[ acct->host() ] = 0;
00363   }
00364 
00365 } // namespace KMail
00366 
00367 #include "networkaccount.moc"