File indexing completed on 2024-05-19 04:50:15
0001 /**************************************************************************************** 0002 * Copyright (c) 2007 Shane King <kde@dontletsstart.com> * 0003 * Copyright (c) 2009 Leo Franchi <lfranchi@kde.org> * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify it under * 0006 * the terms of the GNU General Public License as published by the Free Software * 0007 * Foundation; either version 2 of the License, or (at your option) any later * 0008 * version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0011 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0012 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0013 * * 0014 * You should have received a copy of the GNU General Public License along with * 0015 * this program. If not, see <http://www.gnu.org/licenses/>. * 0016 ****************************************************************************************/ 0017 0018 #define DEBUG_PREFIX "lastfm" 0019 0020 #include "LastFmServiceConfig.h" 0021 0022 #include "App.h" 0023 #include "core/logger/Logger.h" 0024 #include "core/support/Amarok.h" 0025 #include "core/support/Components.h" 0026 #include "core/support/Debug.h" 0027 0028 #include <KLocalizedString> 0029 #include <KWallet> 0030 0031 #include <QMessageBox> 0032 #include <QLabel> 0033 #include <QThread> 0034 0035 QWeakPointer<LastFmServiceConfig> LastFmServiceConfig::s_instance; 0036 0037 LastFmServiceConfigPtr 0038 LastFmServiceConfig::instance() 0039 { 0040 Q_ASSERT( QThread::currentThread() == QCoreApplication::instance()->thread() ); 0041 0042 LastFmServiceConfigPtr strongRef = s_instance.toStrongRef(); 0043 if( strongRef ) 0044 return strongRef; 0045 0046 LastFmServiceConfigPtr newStrongRef( new LastFmServiceConfig() ); 0047 s_instance = newStrongRef; 0048 return newStrongRef; 0049 } 0050 0051 LastFmServiceConfig::LastFmServiceConfig() 0052 : m_askDiag( nullptr ) 0053 , m_wallet( nullptr ) 0054 { 0055 DEBUG_BLOCK 0056 0057 KConfigGroup config = Amarok::config( configSectionName() ); 0058 m_sessionKey = config.readEntry( "sessionKey", QString() ); 0059 m_scrobble = config.readEntry( "scrobble", defaultScrobble() ); 0060 m_fetchSimilar = config.readEntry( "fetchSimilar", defaultFetchSimilar() ); 0061 m_scrobbleComposer = config.readEntry( "scrobbleComposer", defaultScrobbleComposer() ); 0062 m_useFancyRatingTags = config.readEntry( "useFancyRatingTags", defaultUseFancyRatingTags() ); 0063 m_announceCorrections = config.readEntry( "announceCorrections", defaultAnnounceCorrections() ); 0064 m_filterByLabel = config.readEntry( "filterByLabel", defaultFilterByLabel() ); 0065 m_filteredLabel = config.readEntry( "filteredLabel", defaultFilteredLabel() ); 0066 0067 if( config.hasKey( "kWalletUsage" ) ) 0068 m_kWalletUsage = KWalletUsage( config.readEntry( "kWalletUsage", int( NoPasswordEnteredYet ) ) ); 0069 else 0070 { 0071 // migrate from the old config that used "ignoreWallet" key set to yes/no 0072 if( config.readEntry( "ignoreWallet", "" ) == "yes" ) 0073 m_kWalletUsage = PasswordInAscii; 0074 else if( config.hasKey( "scrobble" ) ) 0075 // assume password was saved in KWallet if the config was once written 0076 m_kWalletUsage = PasswodInKWallet; 0077 else 0078 m_kWalletUsage = NoPasswordEnteredYet; // config not yet saved, assume unused 0079 } 0080 0081 switch( m_kWalletUsage ) 0082 { 0083 case NoPasswordEnteredYet: 0084 break; 0085 case PasswodInKWallet: 0086 openWalletToRead(); 0087 break; 0088 case PasswordInAscii: 0089 m_username = config.readEntry( "username", QString() ); 0090 m_password = config.readEntry( "password", QString() ); 0091 break; 0092 } 0093 } 0094 0095 LastFmServiceConfig::~LastFmServiceConfig() 0096 { 0097 DEBUG_BLOCK 0098 0099 if( m_askDiag ) 0100 m_askDiag->deleteLater(); 0101 if( m_wallet ) 0102 m_wallet->deleteLater(); 0103 } 0104 0105 void LastFmServiceConfig::save() 0106 { 0107 KConfigGroup config = Amarok::config( configSectionName() ); 0108 0109 // if username and password is empty, reset to NoPasswordEnteredYet; this enables 0110 // going from PasswordInAscii to PasswodInKWallet 0111 if( m_username.isEmpty() && m_password.isEmpty() ) 0112 { 0113 m_kWalletUsage = NoPasswordEnteredYet; 0114 config.deleteEntry( "username" ); // prevent possible stray credentials 0115 config.deleteEntry( "password" ); 0116 } 0117 0118 config.writeEntry( "sessionKey", m_sessionKey ); 0119 config.writeEntry( "scrobble", m_scrobble ); 0120 config.writeEntry( "fetchSimilar", m_fetchSimilar ); 0121 config.writeEntry( "scrobbleComposer", m_scrobbleComposer ); 0122 config.writeEntry( "useFancyRatingTags", m_useFancyRatingTags ); 0123 config.writeEntry( "announceCorrections", m_announceCorrections ); 0124 config.writeEntry( "kWalletUsage", int( m_kWalletUsage ) ); 0125 config.writeEntry( "filterByLabel", m_filterByLabel ); 0126 config.writeEntry( "filteredLabel", m_filteredLabel ); 0127 config.deleteEntry( "ignoreWallet" ); // remove old settings 0128 0129 switch( m_kWalletUsage ) 0130 { 0131 case NoPasswordEnteredYet: 0132 if( m_username.isEmpty() && m_password.isEmpty() ) 0133 break; // stay in this state 0134 Q_FALLTHROUGH(); 0135 case PasswodInKWallet: 0136 openWalletToWrite(); 0137 config.deleteEntry( "username" ); // prevent possible stray credentials 0138 config.deleteEntry( "password" ); 0139 break; 0140 case PasswordInAscii: 0141 config.writeEntry( "username", m_username ); 0142 config.writeEntry( "password", m_password ); 0143 break; 0144 } 0145 0146 config.sync(); 0147 emit updated(); 0148 } 0149 0150 void 0151 LastFmServiceConfig::openWalletToRead() 0152 { 0153 if( m_wallet && m_wallet->isOpen() ) 0154 { 0155 slotWalletOpenedToRead( true ); 0156 return; 0157 } 0158 0159 if( m_wallet ) 0160 disconnect( m_wallet, nullptr, this, nullptr ); 0161 else 0162 { 0163 openWalletAsync(); 0164 if( !m_wallet ) // can happen, see bug 322964 0165 { 0166 slotWalletOpenedToRead( false ); 0167 return; 0168 } 0169 } 0170 connect( m_wallet, &KWallet::Wallet::walletOpened, this, &LastFmServiceConfig::slotWalletOpenedToRead ); 0171 } 0172 0173 void 0174 LastFmServiceConfig::openWalletToWrite() 0175 { 0176 if( m_wallet && m_wallet->isOpen() ) 0177 { 0178 slotWalletOpenedToWrite( true ); 0179 return; 0180 } 0181 0182 if( m_wallet ) 0183 disconnect( m_wallet, nullptr, this, nullptr ); 0184 else 0185 { 0186 openWalletAsync(); 0187 if( !m_wallet ) // can happen, see bug 322964 0188 { 0189 slotWalletOpenedToWrite( false ); 0190 return; 0191 } 0192 } 0193 connect( m_wallet, &KWallet::Wallet::walletOpened, this, &LastFmServiceConfig::slotWalletOpenedToWrite ); 0194 } 0195 0196 void 0197 LastFmServiceConfig::openWalletAsync() 0198 { 0199 Q_ASSERT( !m_wallet ); 0200 using namespace KWallet; 0201 m_wallet = Wallet::openWallet( Wallet::NetworkWallet(), 0, Wallet::Asynchronous ); 0202 } 0203 0204 void 0205 LastFmServiceConfig::prepareOpenedWallet() 0206 { 0207 if( !m_wallet->hasFolder( "Amarok" ) ) 0208 m_wallet->createFolder( "Amarok" ); 0209 m_wallet->setFolder( "Amarok" ); 0210 } 0211 0212 void 0213 LastFmServiceConfig::slotWalletOpenedToRead( bool success ) 0214 { 0215 if( !success ) 0216 { 0217 warning() << __PRETTY_FUNCTION__ << "failed to open wallet"; 0218 QString message = i18n( "Failed to open KDE Wallet to read Last.fm credentials" ); 0219 Amarok::Logger::longMessage( message, Amarok::Logger::Warning ); 0220 if( m_wallet ) 0221 m_wallet->deleteLater(); // no point in having invalid wallet around 0222 m_wallet = nullptr; 0223 return; 0224 } 0225 0226 Q_ASSERT( m_wallet ); 0227 prepareOpenedWallet(); 0228 0229 if( m_wallet->readPassword( "lastfm_password", m_password ) > 0 ) 0230 warning() << "Failed to read lastfm password from kwallet"; 0231 QByteArray rawUsername; 0232 if( m_wallet->readEntry( "lastfm_username", rawUsername ) > 0 ) 0233 warning() << "Failed to read last.fm username from kwallet"; 0234 else 0235 m_username = QString::fromUtf8( rawUsername ); 0236 emit updated(); 0237 } 0238 0239 void 0240 LastFmServiceConfig::slotWalletOpenedToWrite( bool success ) 0241 { 0242 if( !success ) 0243 { 0244 askAboutMissingKWallet(); 0245 if( m_wallet ) 0246 m_wallet->deleteLater(); // no point in having invalid wallet around 0247 m_wallet = nullptr; 0248 return; 0249 } 0250 0251 Q_ASSERT( m_wallet ); 0252 prepareOpenedWallet(); 0253 0254 if( m_wallet->writePassword( "lastfm_password", m_password ) > 0 ) 0255 warning() << "Failed to save last.fm password to kwallet"; 0256 if( m_wallet->writeEntry( "lastfm_username", m_username.toUtf8() ) > 0 ) 0257 warning() << "Failed to save last.fm username to kwallet"; 0258 0259 m_kWalletUsage = PasswodInKWallet; 0260 KConfigGroup config = Amarok::config( configSectionName() ); 0261 config.writeEntry( "kWalletUsage", int( m_kWalletUsage ) ); 0262 config.sync(); 0263 } 0264 0265 void 0266 LastFmServiceConfig::askAboutMissingKWallet() 0267 { 0268 if ( !m_askDiag ) 0269 { 0270 m_askDiag = new QMessageBox; 0271 m_askDiag->setText( i18n( "No running KWallet found." ) ); 0272 m_askDiag->setInformativeText( i18n( "Would you like Amarok to save your Last.fm credentials in plaintext?" ) ); 0273 m_askDiag->setStandardButtons( QMessageBox::Yes | QMessageBox::No ); 0274 0275 connect( m_askDiag, &QDialog::accepted, this, &LastFmServiceConfig::slotStoreCredentialsInAscii ); 0276 // maybe connect SIGNAL(noClicked()) to a message informing the user the password will 0277 // be forgotten on Amarok restart 0278 } 0279 m_askDiag->show(); 0280 } 0281 0282 void 0283 LastFmServiceConfig::slotStoreCredentialsInAscii() //SLOT 0284 { 0285 DEBUG_BLOCK 0286 m_kWalletUsage = PasswordInAscii; 0287 save(); 0288 }