You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdenetwork/kopete/libkopete/kopetepassword.cpp

503 lines
14 KiB

/*
kopetepassword.cpp - Kopete Password
Copyright (c) 2004 by Richard Smith <kde@metafoo.co.uk>
Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org>
*************************************************************************
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
*************************************************************************
*/
#include "kopeteuiglobal.h"
#include "kopetepassword.h"
#include "kopetepassworddialog.h"
#include "kopetewalletmanager.h"
#include <kwallet.h>
#include <tqapplication.h>
#include <tqlabel.h>
#include <tqlineedit.h>
#include <tqcheckbox.h>
#include <kactivelabel.h>
#include <kapplication.h>
#include <kconfig.h>
#include <kdebug.h>
#include <kdialogbase.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kiconloader.h>
#include <kpassdlg.h>
#include <kstringhandler.h>
class Kopete::Password::Private
{
public:
Private( const TQString &group, uint maxLen, bool blanksAllowed )
: refCount( 1 ), configGroup( group ), remembered( false ), maximumLength( maxLen ),
isWrong( false ), allowBlankPassword( blanksAllowed )
{
}
Private *incRef()
{
++refCount;
return this;
}
void decRef()
{
if( --refCount == 0 )
delete this;
}
/** Reference count */
int refCount;
/** Group to use for KConfig and KWallet */
const TQString configGroup;
/** Is the password being remembered? */
bool remembered;
/** The current password in the KConfig file, or TQString::null if no password there */
TQString passwordFromKConfig;
/** The maximum length allowed for this password, or -1 if there is no limit */
uint maximumLength;
/** Is the current password known to be wrong? */
bool isWrong;
/** Are we allowed to have blank passwords? */
bool allowBlankPassword;
/** The cached password */
TQString cachedValue;
};
/**
* Implementation detail of Kopete::Password: manages a single password request
* @internal
* @author Richard Smith <kde@metafoo.co.uk>
*/
class KopetePasswordRequest : public KopetePasswordRequestBase
{
public:
KopetePasswordRequest( TQObject *owner, Kopete::Password &pass )
: TQObject( owner ), mPassword( pass ), mWallet( 0 )
{
}
/**
* Start the request - ask for the wallet
*/
void begin()
{
kdDebug( 14010 ) << k_funcinfo << endl;
Kopete::WalletManager::self()->openWallet( this, TQT_SLOT( walletReceived( KWallet::Wallet* ) ) );
}
void walletReceived( KWallet::Wallet *wallet )
{
kdDebug( 14010 ) << k_funcinfo << endl;
mWallet = wallet;
processRequest();
}
/**
* Got wallet; now carry out whatever action this request represents
*/
virtual void processRequest() = 0;
void slotOkPressed() {}
void slotCancelPressed() {}
protected:
Kopete::Password mPassword;
KWallet::Wallet *mWallet;
};
/**
* Implementation detail of Kopete::Password: manages a single password retrieval request
* @internal
* @author Richard Smith <kde@metafoo.co.uk>
*/
class KopetePasswordGetRequest : public KopetePasswordRequest
{
public:
KopetePasswordGetRequest( TQObject *owner, Kopete::Password &pass )
: KopetePasswordRequest( owner, pass )
{
}
TQString grabPassword()
{
// Before trying to read from the wallet, check if the config file holds a password.
// If so, remove it from the config and set it through KWallet instead.
TQString pwd;
if ( mPassword.d->remembered && !mPassword.d->passwordFromKConfig.isNull() )
{
pwd = mPassword.d->passwordFromKConfig;
mPassword.set( pwd );
return pwd;
}
if ( mWallet && mWallet->readPassword( mPassword.d->configGroup, pwd ) == 0 && !pwd.isNull() )
return pwd;
if ( mPassword.d->remembered && !mPassword.d->passwordFromKConfig.isNull() )
return mPassword.d->passwordFromKConfig;
return TQString::null;
}
void finished( const TQString &result )
{
mPassword.d->cachedValue = result;
emit requestFinished( result );
delete this;
}
};
class KopetePasswordGetRequestPrompt : public KopetePasswordGetRequest
{
public:
KopetePasswordGetRequestPrompt( TQObject *owner, Kopete::Password &pass, const TQPixmap &image, const TQString &prompt, Kopete::Password::PasswordSource source )
: KopetePasswordGetRequest( owner, pass ), mImage( image ), mPrompt( prompt ), mSource( source ), mView( 0 )
{
}
void processRequest()
{
TQString result = grabPassword();
if ( mSource == Kopete::Password::FromUser || result.isNull() )
doPasswordDialog();
else
finished( result );
}
void doPasswordDialog()
{
kdDebug( 14010 ) << k_funcinfo << endl;
KDialogBase *passwdDialog = new KDialogBase( Kopete::UI::Global::mainWidget(), "passwdDialog", true, i18n( "Password Required" ),
KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok, true );
mView = new KopetePasswordDialog( passwdDialog );
passwdDialog->setMainWidget( mView );
mView->m_text->setText( mPrompt );
mView->m_image->setPixmap( mImage );
/* Do not put the default password, or it will confuse those which doesn't echo anything for the password
mView->m_password->insert( password );
*/
int maxLength = mPassword.maximumLength();
if ( maxLength != 0 )
mView->m_password->setMaxLength( maxLength );
mView->m_password->setFocus();
// FIXME: either document what these are for or remove them - lilac
mView->adjustSize();
passwdDialog->adjustSize();
connect( passwdDialog, TQT_SIGNAL( okClicked() ), TQT_SLOT( slotOkPressed() ) );
connect( passwdDialog, TQT_SIGNAL( cancelClicked() ), TQT_SLOT( slotCancelPressed() ) );
connect( this, TQT_SIGNAL( destroyed() ), passwdDialog, TQT_SLOT( deleteLater() ) );
passwdDialog->show();
}
void slotOkPressed()
{
TQString result = TQString::fromLocal8Bit( mView->m_password->password() );
if ( mView->m_save_passwd->isChecked() )
mPassword.set( result );
finished( result );
}
void slotCancelPressed()
{
finished( TQString::null );
}
private:
TQPixmap mImage;
TQString mPrompt;
Kopete::Password::PasswordSource mSource;
unsigned int mMaxLength;
KopetePasswordDialog *mView;
};
class KopetePasswordGetRequestNoPrompt : public KopetePasswordGetRequest
{
public:
KopetePasswordGetRequestNoPrompt( TQObject *owner, Kopete::Password &pass )
: KopetePasswordGetRequest( owner, pass )
{
}
void processRequest()
{
finished( grabPassword() );
}
};
/**
* Implementation detail of Kopete::Password: manages a single password change request
* @internal
* @author Richard Smith <kde@metafoo.co.uk>
*/
class KopetePasswordSetRequest : public KopetePasswordRequest
{
public:
KopetePasswordSetRequest( Kopete::Password &pass, const TQString &newPass )
: KopetePasswordRequest( 0, pass ), mNewPass( newPass )
{
if ( KApplication *app = KApplication::kApplication() )
app->ref();
}
~KopetePasswordSetRequest()
{
if ( KApplication *app = KApplication::kApplication() )
app->deref();
kdDebug( 14010 ) << k_funcinfo << "job complete" << endl;
}
void processRequest()
{
if ( setPassword() )
{
mPassword.setWrong( false );
mPassword.d->cachedValue = mNewPass;
}
delete this;
}
bool setPassword()
{
kdDebug( 14010 ) << k_funcinfo << " setting password for " << mPassword.d->configGroup << endl;
if ( mWallet && mWallet->writePassword( mPassword.d->configGroup, mNewPass ) == 0 )
{
mPassword.d->remembered = true;
mPassword.d->passwordFromKConfig = TQString::null;
mPassword.writeConfig();
return true;
}
if ( KWallet::Wallet::isEnabled() )
{
// If we end up here, the wallet is enabled, but failed somehow.
// Ask the user what to do now.
//NOTE: This will start a nested event loop. However, this is fine; the only code we
// call after this point is in Kopete::Password, so as long as we've not been deleted
// everything should work out OK. We have no parent TQObject, so we should survive.
if ( KMessageBox::warningContinueCancel( Kopete::UI::Global::mainWidget(),
i18n( "<qt>Kopete is unable to save your password securely in your wallet;<br>"
"do you want to save the password in the <b>unsafe</b> configuration file instead?</qt>" ),
i18n( "Unable to Store Secure Password" ),
KGuiItem( i18n( "Store &Unsafe" ), TQString::fromLatin1( "unlock" ) ),
TQString::fromLatin1( "KWalletFallbackToKConfig" ) ) != KMessageBox::Continue )
{
return false;
}
}
mPassword.d->remembered = true;
mPassword.d->passwordFromKConfig = mNewPass;
mPassword.writeConfig();
return true;
}
private:
TQString mNewPass;
};
class KopetePasswordClearRequest : public KopetePasswordRequest
{
public:
KopetePasswordClearRequest( Kopete::Password &pass )
: KopetePasswordRequest( 0, pass )
{
if ( KApplication *app = KApplication::kApplication() )
app->ref();
}
~KopetePasswordClearRequest()
{
if ( KApplication *app = KApplication::kApplication() )
app->deref();
kdDebug( 14010 ) << k_funcinfo << "job complete" << endl;
}
void processRequest()
{
if ( clearPassword() )
{
mPassword.setWrong( true );
mPassword.d->cachedValue = TQString::null;
}
delete this;
}
bool clearPassword()
{
kdDebug( 14010 ) << k_funcinfo << " clearing password" << endl;
mPassword.d->remembered = false;
mPassword.d->passwordFromKConfig = TQString::null;
mPassword.writeConfig();
if ( mWallet )
mWallet->removeEntry( mPassword.d->configGroup );
return true;
}
};
Kopete::Password::Password( const TQString &configGroup, uint maximumLength, const char *name )
: TQObject( 0, name ), d( new Private( configGroup, maximumLength, false ) )
{
readConfig();
}
Kopete::Password::Password( const TQString &configGroup, uint maximumLength,
bool allowBlankPassword, const char *name )
: TQObject( 0, name ), d( new Private( configGroup, maximumLength, allowBlankPassword ) )
{
readConfig();
}
Kopete::Password::Password( Password &other, const char *name )
: TQObject( 0, name ), d( other.d->incRef() )
{
}
Kopete::Password::~Password()
{
d->decRef();
}
Kopete::Password &Kopete::Password::operator=( Password &other )
{
if ( d == other.d ) return *this;
d->decRef();
d = other.d->incRef();
return *this;
}
void Kopete::Password::readConfig()
{
KConfig *config = KGlobal::config();
config->setGroup( d->configGroup );
TQString passwordCrypted = config->readEntry( "Password" );
if ( passwordCrypted.isNull() )
d->passwordFromKConfig = TQString::null;
else
d->passwordFromKConfig = KStringHandler::obscure( passwordCrypted );
d->remembered = config->readBoolEntry( "RememberPassword", false );
d->isWrong = config->readBoolEntry( "PasswordIsWrong", false );
}
void Kopete::Password::writeConfig()
{
KConfig *config = KGlobal::config();
if(!config->hasGroup(d->configGroup))
{
//### (KOPETE)
// if the kopete account has been removed, we have no way to know it.
// but we don't want in any case to recreate the group.
// see Bug 106460
// (the problem is that when we remove the account, we remove the password
// also, which cause a call to this function )
return;
}
config->setGroup( d->configGroup );
if ( d->remembered && !d->passwordFromKConfig.isNull() )
config->writeEntry( "Password", KStringHandler::obscure( d->passwordFromKConfig ) );
else
config->deleteEntry( "Password" );
config->writeEntry( "RememberPassword", d->remembered );
config->writeEntry( "PasswordIsWrong", d->isWrong );
}
int Kopete::Password::preferredImageSize()
{
return IconSize(KIcon::Toolbar);
}
bool Kopete::Password::allowBlankPassword()
{
return d->allowBlankPassword;
}
uint Kopete::Password::maximumLength()
{
return d->maximumLength;
}
void Kopete::Password::setMaximumLength( uint max )
{
d->maximumLength = max;
}
bool Kopete::Password::isWrong()
{
return d->isWrong;
}
void Kopete::Password::setWrong( bool bWrong )
{
d->isWrong = bWrong;
writeConfig();
if ( bWrong ) d->cachedValue = TQString::null;
}
void Kopete::Password::requestWithoutPrompt( TQObject *returnObj, const char *slot )
{
KopetePasswordRequest *request = new KopetePasswordGetRequestNoPrompt( returnObj, *this );
// call connect on returnObj so we can still connect if 'slot' is protected/private
returnObj->connect( request, TQT_SIGNAL( requestFinished( const TQString & ) ), slot );
request->begin();
}
void Kopete::Password::request( TQObject *returnObj, const char *slot, const TQPixmap &image, const TQString &prompt, Kopete::Password::PasswordSource source )
{
KopetePasswordRequest *request = new KopetePasswordGetRequestPrompt( returnObj, *this, image, prompt, source );
returnObj->connect( request, TQT_SIGNAL( requestFinished( const TQString & ) ), slot );
request->begin();
}
TQString Kopete::Password::cachedValue()
{
return d->cachedValue;
}
void Kopete::Password::set( const TQString &pass )
{
// if we're being told to forget the password, and we aren't remembering one,
// don't try to open the wallet. fixes bug #71804.
if( pass.isNull() && !d->allowBlankPassword )
{
if( remembered() )
clear();
return;
}
KopetePasswordRequest *request = new KopetePasswordSetRequest( *this, pass );
request->begin();
}
void Kopete::Password::clear()
{
KopetePasswordClearRequest *request = new KopetePasswordClearRequest( *this );
request->begin();
}
bool Kopete::Password::remembered()
{
return d->remembered;
}
#include "kopetepassword.moc"
// vim: set noet ts=4 sts=4 sw=4: