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 "legacydecrypt.h"
00022 #include "mailtransport_defs.h"
00023 #include "transportmanager.h"
00024 #include "transporttype_p.h"
00025
00026 #include <QTimer>
00027
00028 #include <KConfigGroup>
00029 #include <KDebug>
00030 #include <KLocalizedString>
00031 #include <KMessageBox>
00032 #include <KStringHandler>
00033 #include <KWallet/Wallet>
00034
00035 #include <akonadi/agentinstance.h>
00036 #include <akonadi/agentmanager.h>
00037
00038 using namespace MailTransport;
00039 using namespace KWallet;
00040
00045 class TransportPrivate
00046 {
00047 public:
00048 TransportType transportType;
00049 QString password;
00050 bool passwordLoaded;
00051 bool passwordDirty;
00052 bool storePasswordInFile;
00053 bool needsWalletMigration;
00054 QString oldName;
00055 };
00056
00057 Transport::Transport( const QString &cfgGroup ) :
00058 TransportBase( cfgGroup ), d( new TransportPrivate )
00059 {
00060 kDebug() << cfgGroup;
00061 d->passwordLoaded = false;
00062 d->passwordDirty = false;
00063 d->storePasswordInFile = false;
00064 d->needsWalletMigration = false;
00065 readConfig();
00066 }
00067
00068 Transport::~Transport()
00069 {
00070 delete d;
00071 }
00072
00073 bool Transport::isValid() const
00074 {
00075 return ( id() > 0 ) && !host().isEmpty() && port() <= 65536;
00076 }
00077
00078 QString Transport::password()
00079 {
00080 if ( !d->passwordLoaded && requiresAuthentication() && storePassword() &&
00081 d->password.isEmpty() ) {
00082 TransportManager::self()->loadPasswords();
00083 d->password = TransportManager::self()->transportById( id(), false )->password();
00084 }
00085 return d->password;
00086 }
00087
00088 void Transport::setPassword( const QString &passwd )
00089 {
00090 d->passwordLoaded = true;
00091 if ( d->password == passwd ) {
00092 return;
00093 }
00094 d->passwordDirty = true;
00095 d->password = passwd;
00096 }
00097
00098 void Transport::forceUniqueName()
00099 {
00100 QStringList existingNames;
00101 foreach ( Transport *t, TransportManager::self()->transports() ) {
00102 if ( t->id() != id() ) {
00103 existingNames << t->name();
00104 }
00105 }
00106 int suffix = 1;
00107 QString origName = name();
00108 while ( existingNames.contains( name() ) ) {
00109 setName( i18nc( "%1: name; %2: number appended to it to make "
00110 "it unique among a list of names", "%1 #%2", origName, suffix ) );
00111 ++suffix;
00112 }
00113
00114 }
00115
00116 void Transport::updatePasswordState()
00117 {
00118 Transport *original = TransportManager::self()->transportById( id(), false );
00119 if ( original == this ) {
00120 kWarning() << "Tried to update password state of non-cloned transport.";
00121 return;
00122 }
00123 if ( original ) {
00124 d->password = original->d->password;
00125 d->passwordLoaded = original->d->passwordLoaded;
00126 d->passwordDirty = original->d->passwordDirty;
00127 } else {
00128 kWarning() << "Transport with this ID not managed by transport manager.";
00129 }
00130 }
00131
00132 bool Transport::isComplete() const
00133 {
00134 return !requiresAuthentication() || !storePassword() || d->passwordLoaded;
00135 }
00136
00137 QString Transport::authenticationTypeString() const
00138 {
00139 return Transport::authenticationTypeString( authenticationType() );
00140 }
00141
00142 QString Transport::authenticationTypeString( int type )
00143 {
00144 switch ( type ) {
00145 case EnumAuthenticationType::LOGIN:
00146 return QLatin1String( "LOGIN" );
00147 case EnumAuthenticationType::PLAIN:
00148 return QLatin1String( "PLAIN" );
00149 case EnumAuthenticationType::CRAM_MD5:
00150 return QLatin1String( "CRAM-MD5" );
00151 case EnumAuthenticationType::DIGEST_MD5:
00152 return QLatin1String( "DIGEST-MD5" );
00153 case EnumAuthenticationType::NTLM:
00154 return QLatin1String( "NTLM" );
00155 case EnumAuthenticationType::GSSAPI:
00156 return QLatin1String( "GSSAPI" );
00157 case EnumAuthenticationType::CLEAR:
00158 return i18nc( "Authentication method", "Clear text" );
00159 case EnumAuthenticationType::APOP:
00160 return QLatin1String( "APOP" );
00161 case EnumAuthenticationType::ANONYMOUS:
00162 return i18nc( "Authentication method", "Anonymous" );
00163 }
00164 Q_ASSERT( false );
00165 return QString();
00166 }
00167
00168 void Transport::usrReadConfig()
00169 {
00170 TransportBase::usrReadConfig();
00171
00172 setHost( host().trimmed() );
00173
00174 if ( d->oldName.isEmpty() ) {
00175 d->oldName = name();
00176 }
00177
00178
00179 {
00180 using namespace Akonadi;
00181 d->transportType = TransportType();
00182 d->transportType.d->mType = type();
00183 kDebug() << "type" << type();
00184 if ( type() == EnumType::Akonadi ) {
00185 const AgentInstance instance = AgentManager::self()->instance( host() );
00186 if ( !instance.isValid() ) {
00187 kWarning() << "Akonadi transport with invalid resource instance.";
00188 }
00189 d->transportType.d->mAgentType = instance.type();
00190 kDebug() << "agent type" << instance.type().name() << "id" << instance.type().identifier();
00191 }
00192
00193
00194 const TransportType::List &types = TransportManager::self()->types();
00195 int index = types.indexOf( d->transportType );
00196 if ( index != -1 ) {
00197 d->transportType = types[ index ];
00198 } else {
00199 kWarning() << "Type unknown to manager.";
00200 d->transportType.d->mName = i18nc( "An unknown transport type", "Unknown" );
00201 }
00202 }
00203
00204
00205 if ( !storePassword() || d->passwordLoaded ) {
00206 return;
00207 }
00208
00209
00210 KConfigGroup group( config(), currentGroup() );
00211 if ( group.hasKey( "password" ) ) {
00212 d->password = KStringHandler::obscure( group.readEntry( "password" ) );
00213 } else if ( group.hasKey( "password-kmail" ) ) {
00214 d->password = Legacy::decryptKMail( group.readEntry( "password-kmail" ) );
00215 } else if ( group.hasKey( "password-knode" ) ) {
00216 d->password = Legacy::decryptKNode( group.readEntry( "password-knode" ) );
00217 }
00218
00219 if ( !d->password.isEmpty() ) {
00220 d->passwordLoaded = true;
00221 if ( Wallet::isEnabled() ) {
00222 d->needsWalletMigration = true;
00223 } else {
00224 d->storePasswordInFile = true;
00225 }
00226 } else {
00227
00228 if ( Wallet::isOpen( Wallet::NetworkWallet() ) ) {
00229
00230
00231
00232
00233 QTimer::singleShot( 0, this, SLOT(readPassword()) );
00234 }
00235 }
00236 }
00237
00238 void Transport::usrWriteConfig()
00239 {
00240 if ( requiresAuthentication() && storePassword() && d->passwordDirty ) {
00241 Wallet *wallet = TransportManager::self()->wallet();
00242 if ( !wallet || wallet->writePassword( QString::number( id() ), d->password ) != 0 ) {
00243
00244 if ( d->storePasswordInFile || KMessageBox::warningYesNo(
00245 0,
00246 i18n( "KWallet is not available. It is strongly recommended to use "
00247 "KWallet for managing your passwords.\n"
00248 "However, the password can be stored in the configuration "
00249 "file instead. The password is stored in an obfuscated format, "
00250 "but should not be considered secure from decryption efforts "
00251 "if access to the configuration file is obtained.\n"
00252 "Do you want to store the password for server '%1' in the "
00253 "configuration file?", name() ),
00254 i18n( "KWallet Not Available" ),
00255 KGuiItem( i18n( "Store Password" ) ),
00256 KGuiItem( i18n( "Do Not Store Password" ) ) ) == KMessageBox::Yes ) {
00257
00258 KConfigGroup group( config(), currentGroup() );
00259 group.writeEntry( "password", KStringHandler::obscure( d->password ) );
00260 d->storePasswordInFile = true;
00261 }
00262 }
00263 d->passwordDirty = false;
00264 }
00265
00266 TransportBase::usrWriteConfig();
00267 TransportManager::self()->emitChangesCommitted();
00268 if ( name() != d->oldName ) {
00269 emit TransportManager::self()->transportRenamed( id(), d->oldName, name() );
00270 d->oldName = name();
00271 }
00272 }
00273
00274 void Transport::readPassword()
00275 {
00276
00277 if ( !requiresAuthentication() ) {
00278 return;
00279 }
00280 d->passwordLoaded = true;
00281
00282
00283 if ( Wallet::folderDoesNotExist( Wallet::NetworkWallet(), WALLET_FOLDER ) ||
00284 Wallet::keyDoesNotExist( Wallet::NetworkWallet(), WALLET_FOLDER,
00285 QString::number( id() ) ) ) {
00286
00287 if ( Wallet::folderDoesNotExist( Wallet::NetworkWallet(), KMAIL_WALLET_FOLDER ) ||
00288 Wallet::keyDoesNotExist( Wallet::NetworkWallet(), KMAIL_WALLET_FOLDER,
00289 QString::fromLatin1( "transport-%1" ).arg( id() ) ) ) {
00290 return;
00291 }
00292 kDebug() << "migrating password from kmail wallet";
00293 KWallet::Wallet *wallet = TransportManager::self()->wallet();
00294 if ( wallet ) {
00295 wallet->setFolder( KMAIL_WALLET_FOLDER );
00296 wallet->readPassword( QString::fromLatin1( "transport-%1" ).arg( id() ), d->password );
00297 wallet->removeEntry( QString::fromLatin1( "transport-%1" ).arg( id() ) );
00298 wallet->setFolder( WALLET_FOLDER );
00299 d->passwordDirty = true;
00300 writeConfig();
00301 }
00302 return;
00303 }
00304
00305
00306 KWallet::Wallet *wallet = TransportManager::self()->wallet();
00307 if ( wallet ) {
00308 wallet->readPassword( QString::number( id() ), d->password );
00309 }
00310 }
00311
00312 bool Transport::needsWalletMigration() const
00313 {
00314 return d->needsWalletMigration;
00315 }
00316
00317 void Transport::migrateToWallet()
00318 {
00319 kDebug() << "migrating" << id() << "to wallet";
00320 d->needsWalletMigration = false;
00321 KConfigGroup group( config(), currentGroup() );
00322 group.deleteEntry( "password" );
00323 group.deleteEntry( "password-kmail" );
00324 group.deleteEntry( "password-knode" );
00325 d->passwordDirty = true;
00326 d->storePasswordInFile = false;
00327 writeConfig();
00328 }
00329
00330 Transport *Transport::clone() const
00331 {
00332 QString id = currentGroup().mid( 10 );
00333 return new Transport( id );
00334 }
00335
00336 TransportType Transport::transportType() const
00337 {
00338 if ( !d->transportType.isValid() ) {
00339 kWarning() << "Invalid transport type.";
00340 }
00341 return d->transportType;
00342 }
00343
00344 void Transport::setTransportType( const TransportType &type )
00345 {
00346 Q_ASSERT( type.isValid() );
00347 d->transportType = type;
00348 setType( type.type() );
00349 }
00350
00351 #include "transport.moc"