mailtransport
transport.cpp
00001 /* 00002 Copyright (c) 2006 - 2007 Volker Krause <vkrause@kde.org> 00003 00004 This library is free software; you can redistribute it and/or modify it 00005 under the terms of the GNU Library General Public License as published by 00006 the Free Software Foundation; either version 2 of the License, or (at your 00007 option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, but WITHOUT 00010 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00011 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00012 License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to the 00016 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00017 02110-1301, USA. 00018 */ 00019 00020 #include "transport.h" 00021 #include "transport_p.h" 00022 #include "legacydecrypt.h" 00023 #include "mailtransport_defs.h" 00024 #include "transportmanager.h" 00025 #include "transporttype_p.h" 00026 00027 #include <QTimer> 00028 00029 #include <KConfigGroup> 00030 #include <KDebug> 00031 #include <KLocalizedString> 00032 #include <KMessageBox> 00033 #include <KStringHandler> 00034 #include <KWallet/Wallet> 00035 00036 #include <akonadi/agentinstance.h> 00037 #include <akonadi/agentmanager.h> 00038 00039 using namespace MailTransport; 00040 using namespace KWallet; 00041 00042 Transport::Transport( const QString &cfgGroup ) : 00043 TransportBase( cfgGroup ), d( new TransportPrivate ) 00044 { 00045 kDebug() << cfgGroup; 00046 d->passwordLoaded = false; 00047 d->passwordDirty = false; 00048 d->storePasswordInFile = false; 00049 d->needsWalletMigration = false; 00050 d->passwordNeedsUpdateFromWallet = false; 00051 readConfig(); 00052 } 00053 00054 Transport::~Transport() 00055 { 00056 delete d; 00057 } 00058 00059 bool Transport::isValid() const 00060 { 00061 return ( id() > 0 ) && !host().isEmpty() && port() <= 65536; 00062 } 00063 00064 QString Transport::password() 00065 { 00066 if ( !d->passwordLoaded && requiresAuthentication() && storePassword() && 00067 d->password.isEmpty() ) { 00068 readPassword(); 00069 } 00070 return d->password; 00071 } 00072 00073 void Transport::setPassword( const QString &passwd ) 00074 { 00075 d->passwordLoaded = true; 00076 if ( d->password == passwd ) { 00077 return; 00078 } 00079 d->passwordDirty = true; 00080 d->password = passwd; 00081 } 00082 00083 void Transport::forceUniqueName() 00084 { 00085 QStringList existingNames; 00086 foreach ( Transport *t, TransportManager::self()->transports() ) { 00087 if ( t->id() != id() ) { 00088 existingNames << t->name(); 00089 } 00090 } 00091 int suffix = 1; 00092 QString origName = name(); 00093 while ( existingNames.contains( name() ) ) { 00094 setName( i18nc( "%1: name; %2: number appended to it to make " 00095 "it unique among a list of names", "%1 #%2", origName, suffix ) ); 00096 ++suffix; 00097 } 00098 00099 } 00100 00101 void Transport::updatePasswordState() 00102 { 00103 Transport *original = TransportManager::self()->transportById( id(), false ); 00104 if ( original == this ) { 00105 kWarning() << "Tried to update password state of non-cloned transport."; 00106 return; 00107 } 00108 if ( original ) { 00109 d->password = original->d->password; 00110 d->passwordLoaded = original->d->passwordLoaded; 00111 d->passwordDirty = original->d->passwordDirty; 00112 } else { 00113 kWarning() << "Transport with this ID not managed by transport manager."; 00114 } 00115 } 00116 00117 bool Transport::isComplete() const 00118 { 00119 return !requiresAuthentication() || !storePassword() || d->passwordLoaded; 00120 } 00121 00122 QString Transport::authenticationTypeString() const 00123 { 00124 return Transport::authenticationTypeString( authenticationType() ); 00125 } 00126 00127 QString Transport::authenticationTypeString( int type ) 00128 { 00129 switch ( type ) { 00130 case EnumAuthenticationType::LOGIN: 00131 return QLatin1String( "LOGIN" ); 00132 case EnumAuthenticationType::PLAIN: 00133 return QLatin1String( "PLAIN" ); 00134 case EnumAuthenticationType::CRAM_MD5: 00135 return QLatin1String( "CRAM-MD5" ); 00136 case EnumAuthenticationType::DIGEST_MD5: 00137 return QLatin1String( "DIGEST-MD5" ); 00138 case EnumAuthenticationType::NTLM: 00139 return QLatin1String( "NTLM" ); 00140 case EnumAuthenticationType::GSSAPI: 00141 return QLatin1String( "GSSAPI" ); 00142 case EnumAuthenticationType::CLEAR: 00143 return i18nc( "Authentication method", "Clear text" ); 00144 case EnumAuthenticationType::APOP: 00145 return QLatin1String( "APOP" ); 00146 case EnumAuthenticationType::ANONYMOUS: 00147 return i18nc( "Authentication method", "Anonymous" ); 00148 } 00149 Q_ASSERT( false ); 00150 return QString(); 00151 } 00152 00153 void Transport::usrReadConfig() 00154 { 00155 TransportBase::usrReadConfig(); 00156 00157 setHost( host().trimmed() ); 00158 00159 if ( d->oldName.isEmpty() ) { 00160 d->oldName = name(); 00161 } 00162 00163 // Set TransportType. 00164 { 00165 using namespace Akonadi; 00166 d->transportType = TransportType(); 00167 d->transportType.d->mType = type(); 00168 kDebug() << "type" << type(); 00169 if ( type() == EnumType::Akonadi ) { 00170 const AgentInstance instance = AgentManager::self()->instance( host() ); 00171 if ( !instance.isValid() ) { 00172 kWarning() << "Akonadi transport with invalid resource instance."; 00173 } 00174 d->transportType.d->mAgentType = instance.type(); 00175 kDebug() << "agent type" << instance.type().name() << "id" << instance.type().identifier(); 00176 } 00177 // Now we have the type and possibly agentType. Get the name, description 00178 // etc. from TransportManager. 00179 const TransportType::List &types = TransportManager::self()->types(); 00180 int index = types.indexOf( d->transportType ); 00181 if ( index != -1 ) { 00182 d->transportType = types[ index ]; 00183 } else { 00184 kWarning() << "Type unknown to manager."; 00185 d->transportType.d->mName = i18nc( "An unknown transport type", "Unknown" ); 00186 } 00187 } 00188 00189 // we have everything we need 00190 if ( !storePassword() ) { 00191 return; 00192 } 00193 00194 if ( d->passwordLoaded ) { 00195 if ( d->passwordNeedsUpdateFromWallet ) { 00196 d->passwordNeedsUpdateFromWallet = false; 00197 // read password if wallet is open, defer otherwise 00198 if ( Wallet::isOpen( Wallet::NetworkWallet() ) ) { 00199 // Don't read the password right away because this can lead 00200 // to reentrancy problems in KDBusServiceStarter when an application 00201 // run in Kontact creates the transports (due to a QEventLoop in the 00202 // synchronous KWallet openWallet call). 00203 QTimer::singleShot( 0, this, SLOT(readPassword()) ); 00204 } else { 00205 d->passwordLoaded = false; 00206 } 00207 } 00208 00209 return; 00210 } 00211 00212 // try to find a password in the config file otherwise 00213 KConfigGroup group( config(), currentGroup() ); 00214 if ( group.hasKey( "password" ) ) { 00215 d->password = KStringHandler::obscure( group.readEntry( "password" ) ); 00216 } else if ( group.hasKey( "password-kmail" ) ) { 00217 d->password = Legacy::decryptKMail( group.readEntry( "password-kmail" ) ); 00218 } else if ( group.hasKey( "password-knode" ) ) { 00219 d->password = Legacy::decryptKNode( group.readEntry( "password-knode" ) ); 00220 } 00221 00222 if ( !d->password.isEmpty() ) { 00223 d->passwordLoaded = true; 00224 if ( Wallet::isEnabled() ) { 00225 d->needsWalletMigration = true; 00226 } else { 00227 d->storePasswordInFile = true; 00228 } 00229 } else { 00230 // read password if wallet is open, defer otherwise 00231 if ( Wallet::isOpen( Wallet::NetworkWallet() ) ) { 00232 // Don't read the password right away because this can lead 00233 // to reentrancy problems in KDBusServiceStarter when an application 00234 // run in Kontact creates the transports (due to a QEventLoop in the 00235 // synchronous KWallet openWallet call). 00236 QTimer::singleShot( 0, this, SLOT(readPassword()) ); 00237 } 00238 } 00239 } 00240 00241 void Transport::usrWriteConfig() 00242 { 00243 if ( requiresAuthentication() && storePassword() && d->passwordDirty ) { 00244 Wallet *wallet = TransportManager::self()->wallet(); 00245 if ( !wallet || wallet->writePassword( QString::number( id() ), d->password ) != 0 ) { 00246 // wallet saving failed, ask if we should store in the config file instead 00247 if ( d->storePasswordInFile || KMessageBox::warningYesNo( 00248 0, 00249 i18n( "KWallet is not available. It is strongly recommended to use " 00250 "KWallet for managing your passwords.\n" 00251 "However, the password can be stored in the configuration " 00252 "file instead. The password is stored in an obfuscated format, " 00253 "but should not be considered secure from decryption efforts " 00254 "if access to the configuration file is obtained.\n" 00255 "Do you want to store the password for server '%1' in the " 00256 "configuration file?", name() ), 00257 i18n( "KWallet Not Available" ), 00258 KGuiItem( i18n( "Store Password" ) ), 00259 KGuiItem( i18n( "Do Not Store Password" ) ) ) == KMessageBox::Yes ) { 00260 // write to config file 00261 KConfigGroup group( config(), currentGroup() ); 00262 group.writeEntry( "password", KStringHandler::obscure( d->password ) ); 00263 d->storePasswordInFile = true; 00264 } 00265 } 00266 d->passwordDirty = false; 00267 } 00268 00269 TransportBase::usrWriteConfig(); 00270 TransportManager::self()->emitChangesCommitted(); 00271 if ( name() != d->oldName ) { 00272 emit TransportManager::self()->transportRenamed( id(), d->oldName, name() ); 00273 d->oldName = name(); 00274 } 00275 } 00276 00277 void Transport::readPassword() 00278 { 00279 // no need to load a password if the account doesn't require auth 00280 if ( !requiresAuthentication() ) { 00281 return; 00282 } 00283 d->passwordLoaded = true; 00284 00285 // check whether there is a chance to find our password at all 00286 if ( Wallet::folderDoesNotExist( Wallet::NetworkWallet(), WALLET_FOLDER ) || 00287 Wallet::keyDoesNotExist( Wallet::NetworkWallet(), WALLET_FOLDER, 00288 QString::number( id() ) ) ) { 00289 // try migrating password from kmail 00290 if ( Wallet::folderDoesNotExist( Wallet::NetworkWallet(), KMAIL_WALLET_FOLDER ) || 00291 Wallet::keyDoesNotExist( Wallet::NetworkWallet(), KMAIL_WALLET_FOLDER, 00292 QString::fromLatin1( "transport-%1" ).arg( id() ) ) ) { 00293 return; 00294 } 00295 kDebug() << "migrating password from kmail wallet"; 00296 KWallet::Wallet *wallet = TransportManager::self()->wallet(); 00297 if ( wallet ) { 00298 QString pwd; 00299 wallet->setFolder( KMAIL_WALLET_FOLDER ); 00300 if ( wallet->readPassword( QString::fromLatin1( "transport-%1" ).arg( id() ), pwd ) == 0 ) { 00301 setPassword( pwd ); 00302 writeConfig(); 00303 } else { 00304 d->password.clear(); 00305 d->passwordLoaded = false; 00306 } 00307 wallet->removeEntry( QString::fromLatin1( "transport-%1" ).arg( id() ) ); 00308 wallet->setFolder( WALLET_FOLDER ); 00309 } 00310 return; 00311 } 00312 00313 // finally try to open the wallet and read the password 00314 KWallet::Wallet *wallet = TransportManager::self()->wallet(); 00315 if ( wallet ) { 00316 QString pwd; 00317 if ( wallet->readPassword( QString::number( id() ), pwd ) == 0 ) { 00318 setPassword( pwd ); 00319 } else { 00320 d->password.clear(); 00321 d->passwordLoaded = false; 00322 } 00323 } 00324 } 00325 00326 bool Transport::needsWalletMigration() const 00327 { 00328 return d->needsWalletMigration; 00329 } 00330 00331 void Transport::migrateToWallet() 00332 { 00333 kDebug() << "migrating" << id() << "to wallet"; 00334 d->needsWalletMigration = false; 00335 KConfigGroup group( config(), currentGroup() ); 00336 group.deleteEntry( "password" ); 00337 group.deleteEntry( "password-kmail" ); 00338 group.deleteEntry( "password-knode" ); 00339 d->passwordDirty = true; 00340 d->storePasswordInFile = false; 00341 writeConfig(); 00342 } 00343 00344 Transport *Transport::clone() const 00345 { 00346 QString id = currentGroup().mid( 10 ); 00347 return new Transport( id ); 00348 } 00349 00350 TransportType Transport::transportType() const 00351 { 00352 if ( !d->transportType.isValid() ) { 00353 kWarning() << "Invalid transport type."; 00354 } 00355 return d->transportType; 00356 } 00357 00358 void Transport::setTransportType( const TransportType &type ) 00359 { 00360 Q_ASSERT( type.isValid() ); 00361 d->transportType = type; 00362 setType( type.type() ); 00363 } 00364 00365 #include "transport.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Apr 30 2012 21:49:03 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Apr 30 2012 21:49:03 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.