mailtransport
transport.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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
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
00178
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
00190 if ( !storePassword() ) {
00191 return;
00192 }
00193
00194 if ( d->passwordLoaded ) {
00195 if ( d->passwordNeedsUpdateFromWallet ) {
00196 d->passwordNeedsUpdateFromWallet = false;
00197
00198 if ( Wallet::isOpen( Wallet::NetworkWallet() ) ) {
00199
00200
00201
00202
00203 QTimer::singleShot( 0, this, SLOT(readPassword()) );
00204 } else {
00205 d->passwordLoaded = false;
00206 }
00207 }
00208
00209 return;
00210 }
00211
00212
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
00231 if ( Wallet::isOpen( Wallet::NetworkWallet() ) ) {
00232
00233
00234
00235
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
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
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
00280 if ( !requiresAuthentication() ) {
00281 return;
00282 }
00283 d->passwordLoaded = true;
00284
00285
00286 if ( Wallet::folderDoesNotExist( Wallet::NetworkWallet(), WALLET_FOLDER ) ||
00287 Wallet::keyDoesNotExist( Wallet::NetworkWallet(), WALLET_FOLDER,
00288 QString::number( id() ) ) ) {
00289
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 wallet->setFolder( KMAIL_WALLET_FOLDER );
00299 wallet->readPassword( QString::fromLatin1( "transport-%1" ).arg( id() ), d->password );
00300 wallet->removeEntry( QString::fromLatin1( "transport-%1" ).arg( id() ) );
00301 wallet->setFolder( WALLET_FOLDER );
00302 d->passwordDirty = true;
00303 writeConfig();
00304 }
00305 return;
00306 }
00307
00308
00309 KWallet::Wallet *wallet = TransportManager::self()->wallet();
00310 if ( wallet ) {
00311 wallet->readPassword( QString::number( id() ), d->password );
00312 }
00313 }
00314
00315 bool Transport::needsWalletMigration() const
00316 {
00317 return d->needsWalletMigration;
00318 }
00319
00320 void Transport::migrateToWallet()
00321 {
00322 kDebug() << "migrating" << id() << "to wallet";
00323 d->needsWalletMigration = false;
00324 KConfigGroup group( config(), currentGroup() );
00325 group.deleteEntry( "password" );
00326 group.deleteEntry( "password-kmail" );
00327 group.deleteEntry( "password-knode" );
00328 d->passwordDirty = true;
00329 d->storePasswordInFile = false;
00330 writeConfig();
00331 }
00332
00333 Transport *Transport::clone() const
00334 {
00335 QString id = currentGroup().mid( 10 );
00336 return new Transport( id );
00337 }
00338
00339 TransportType Transport::transportType() const
00340 {
00341 if ( !d->transportType.isValid() ) {
00342 kWarning() << "Invalid transport type.";
00343 }
00344 return d->transportType;
00345 }
00346
00347 void Transport::setTransportType( const TransportType &type )
00348 {
00349 Q_ASSERT( type.isValid() );
00350 d->transportType = type;
00351 setType( type.type() );
00352 }
00353
00354 #include "transport.moc"