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 "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 switch ( authenticationType() ) {
00140 case EnumAuthenticationType::LOGIN:
00141 return QLatin1String( "LOGIN" );
00142 case EnumAuthenticationType::PLAIN:
00143 return QLatin1String( "PLAIN" );
00144 case EnumAuthenticationType::CRAM_MD5:
00145 return QLatin1String( "CRAM-MD5" );
00146 case EnumAuthenticationType::DIGEST_MD5:
00147 return QLatin1String( "DIGEST-MD5" );
00148 case EnumAuthenticationType::NTLM:
00149 return QLatin1String( "NTLM" );
00150 case EnumAuthenticationType::GSSAPI:
00151 return QLatin1String( "GSSAPI" );
00152 }
00153 Q_ASSERT( false );
00154 return QString();
00155 }
00156
00157 void Transport::usrReadConfig()
00158 {
00159 TransportBase::usrReadConfig();
00160
00161 setHost( host().trimmed() );
00162
00163 if ( d->oldName.isEmpty() ) {
00164 d->oldName = name();
00165 }
00166
00167
00168 {
00169 using namespace Akonadi;
00170 d->transportType = TransportType();
00171 d->transportType.d->mType = type();
00172 kDebug() << "type" << type();
00173 if( type() == EnumType::Akonadi ) {
00174 const AgentInstance instance = AgentManager::self()->instance( host() );
00175 if( !instance.isValid() ) {
00176 kWarning() << "Akonadi transport with invalid resource instance.";
00177 }
00178 d->transportType.d->mAgentType = instance.type();
00179 kDebug() << "agent type" << instance.type().name() << "id" << instance.type().identifier();
00180 }
00181
00182
00183 const TransportType::List &types = TransportManager::self()->types();
00184 int index = types.indexOf( d->transportType );
00185 if( index != -1 ) {
00186 d->transportType = types[ index ];
00187 } else {
00188 kWarning() << "Type unknown to manager.";
00189 d->transportType.d->mName = i18nc( "An unknown transport type", "Unknown" );
00190 }
00191 }
00192
00193
00194 if ( !storePassword() || d->passwordLoaded ) {
00195 return;
00196 }
00197
00198
00199 KConfigGroup group( config(), currentGroup() );
00200 if ( group.hasKey( "password" ) ) {
00201 d->password = KStringHandler::obscure( group.readEntry( "password" ) );
00202 } else if ( group.hasKey( "password-kmail" ) ) {
00203 d->password = Legacy::decryptKMail( group.readEntry( "password-kmail" ) );
00204 } else if ( group.hasKey( "password-knode" ) ) {
00205 d->password = Legacy::decryptKNode( group.readEntry( "password-knode" ) );
00206 }
00207
00208 if ( !d->password.isEmpty() ) {
00209 d->passwordLoaded = true;
00210 if ( Wallet::isEnabled() ) {
00211 d->needsWalletMigration = true;
00212 } else {
00213 d->storePasswordInFile = true;
00214 }
00215 } else {
00216
00217 if ( Wallet::isOpen( Wallet::NetworkWallet() ) ) {
00218
00219
00220
00221
00222 QTimer::singleShot( 0, this, SLOT(readPassword()) );
00223 }
00224 }
00225 }
00226
00227 void Transport::usrWriteConfig()
00228 {
00229 if ( requiresAuthentication() && storePassword() && d->passwordDirty ) {
00230 Wallet *wallet = TransportManager::self()->wallet();
00231 if ( !wallet || wallet->writePassword( QString::number( id() ), d->password ) != 0 ) {
00232
00233 if ( d->storePasswordInFile || KMessageBox::warningYesNo(
00234 0,
00235 i18n( "KWallet is not available. It is strongly recommended to use "
00236 "KWallet for managing your passwords.\n"
00237 "However, the password can be stored in the configuration "
00238 "file instead. The password is stored in an obfuscated format, "
00239 "but should not be considered secure from decryption efforts "
00240 "if access to the configuration file is obtained.\n"
00241 "Do you want to store the password for server '%1' in the "
00242 "configuration file?", name() ),
00243 i18n( "KWallet Not Available" ),
00244 KGuiItem( i18n( "Store Password" ) ),
00245 KGuiItem( i18n( "Do Not Store Password" ) ) ) == KMessageBox::Yes ) {
00246
00247 KConfigGroup group( config(), currentGroup() );
00248 group.writeEntry( "password", KStringHandler::obscure( d->password ) );
00249 d->storePasswordInFile = true;
00250 }
00251 }
00252 d->passwordDirty = false;
00253 }
00254
00255 TransportBase::usrWriteConfig();
00256 TransportManager::self()->emitChangesCommitted();
00257 if ( name() != d->oldName ) {
00258 emit TransportManager::self()->transportRenamed( id(), d->oldName, name() );
00259 d->oldName = name();
00260 }
00261 }
00262
00263 void Transport::readPassword()
00264 {
00265
00266 if ( !requiresAuthentication() ) {
00267 return;
00268 }
00269 d->passwordLoaded = true;
00270
00271
00272 if ( Wallet::folderDoesNotExist( Wallet::NetworkWallet(), WALLET_FOLDER ) ||
00273 Wallet::keyDoesNotExist( Wallet::NetworkWallet(), WALLET_FOLDER,
00274 QString::number( id() ) ) ) {
00275
00276 if ( Wallet::folderDoesNotExist( Wallet::NetworkWallet(), KMAIL_WALLET_FOLDER ) ||
00277 Wallet::keyDoesNotExist( Wallet::NetworkWallet(), KMAIL_WALLET_FOLDER,
00278 QString::fromLatin1( "transport-%1" ).arg( id() ) ) ) {
00279 return;
00280 }
00281 kDebug() << "migrating password from kmail wallet";
00282 KWallet::Wallet *wallet = TransportManager::self()->wallet();
00283 if ( wallet ) {
00284 wallet->setFolder( KMAIL_WALLET_FOLDER );
00285 wallet->readPassword( QString::fromLatin1( "transport-%1" ).arg( id() ), d->password );
00286 wallet->removeEntry( QString::fromLatin1( "transport-%1" ).arg( id() ) );
00287 wallet->setFolder( WALLET_FOLDER );
00288 d->passwordDirty = true;
00289 writeConfig();
00290 }
00291 return;
00292 }
00293
00294
00295 KWallet::Wallet *wallet = TransportManager::self()->wallet();
00296 if ( wallet ) {
00297 wallet->readPassword( QString::number( id() ), d->password );
00298 }
00299 }
00300
00301 bool Transport::needsWalletMigration() const
00302 {
00303 return d->needsWalletMigration;
00304 }
00305
00306 void Transport::migrateToWallet()
00307 {
00308 kDebug() << "migrating" << id() << "to wallet";
00309 d->needsWalletMigration = false;
00310 KConfigGroup group( config(), currentGroup() );
00311 group.deleteEntry( "password" );
00312 group.deleteEntry( "password-kmail" );
00313 group.deleteEntry( "password-knode" );
00314 d->passwordDirty = true;
00315 d->storePasswordInFile = false;
00316 writeConfig();
00317 }
00318
00319 Transport *Transport::clone() const
00320 {
00321 QString id = currentGroup().mid( 10 );
00322 return new Transport( id );
00323 }
00324
00325 TransportType Transport::transportType() const
00326 {
00327 if( !d->transportType.isValid() ) {
00328 kWarning() << "Invalid transport type.";
00329 }
00330 return d->transportType;
00331 }
00332
00333 void Transport::setTransportType( const TransportType &type )
00334 {
00335 Q_ASSERT( type.isValid() );
00336 d->transportType = type;
00337 setType( type.type() );
00338 }
00339
00340 #include "transport.moc"