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 }