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.
501 lines
14 KiB
501 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 <tdewallet.h>
|
|
|
|
#include <tqapplication.h>
|
|
#include <tqlabel.h>
|
|
#include <tqlineedit.h>
|
|
#include <tqcheckbox.h>
|
|
|
|
#include <kactivelabel.h>
|
|
#include <tdeapplication.h>
|
|
#include <tdeconfig.h>
|
|
#include <kdebug.h>
|
|
#include <kdialogbase.h>
|
|
#include <tdelocale.h>
|
|
#include <tdemessagebox.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 TDEConfig and TDEWallet */
|
|
const TQString configGroup;
|
|
/** Is the password being remembered? */
|
|
bool remembered;
|
|
/** The current password in the TDEConfig file, or TQString() if no password there */
|
|
TQString passwordFromTDEConfig;
|
|
/** 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( TDEWallet::Wallet* ) ) );
|
|
}
|
|
|
|
void walletReceived( TDEWallet::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;
|
|
TDEWallet::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 TDEWallet instead.
|
|
TQString pwd;
|
|
if ( mPassword.d->remembered && !mPassword.d->passwordFromTDEConfig.isNull() )
|
|
{
|
|
pwd = mPassword.d->passwordFromTDEConfig;
|
|
mPassword.set( pwd );
|
|
return pwd;
|
|
}
|
|
|
|
if ( mWallet && mWallet->readPassword( mPassword.d->configGroup, pwd ) == 0 && !pwd.isNull() )
|
|
return pwd;
|
|
|
|
if ( mPassword.d->remembered && !mPassword.d->passwordFromTDEConfig.isNull() )
|
|
return mPassword.d->passwordFromTDEConfig;
|
|
|
|
return TQString();
|
|
}
|
|
|
|
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 = mView->m_password->password();
|
|
if ( mView->m_save_passwd->isChecked() )
|
|
mPassword.set( result );
|
|
|
|
finished( result );
|
|
}
|
|
|
|
void slotCancelPressed()
|
|
{
|
|
finished( TQString() );
|
|
}
|
|
|
|
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 ( TDEApplication *app = TDEApplication::kApplication() )
|
|
app->ref();
|
|
}
|
|
~KopetePasswordSetRequest()
|
|
{
|
|
if ( TDEApplication *app = TDEApplication::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->passwordFromTDEConfig = TQString();
|
|
mPassword.writeConfig();
|
|
return true;
|
|
}
|
|
|
|
if ( TDEWallet::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( "TDEWalletFallbackToTDEConfig" ) ) != KMessageBox::Continue )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
mPassword.d->remembered = true;
|
|
mPassword.d->passwordFromTDEConfig = mNewPass;
|
|
mPassword.writeConfig();
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
TQString mNewPass;
|
|
};
|
|
|
|
class KopetePasswordClearRequest : public KopetePasswordRequest
|
|
{
|
|
public:
|
|
KopetePasswordClearRequest( Kopete::Password &pass )
|
|
: KopetePasswordRequest( 0, pass )
|
|
{
|
|
if ( TDEApplication *app = TDEApplication::kApplication() )
|
|
app->ref();
|
|
}
|
|
~KopetePasswordClearRequest()
|
|
{
|
|
if ( TDEApplication *app = TDEApplication::kApplication() )
|
|
app->deref();
|
|
kdDebug( 14010 ) << k_funcinfo << "job complete" << endl;
|
|
}
|
|
void processRequest()
|
|
{
|
|
if ( clearPassword() )
|
|
{
|
|
mPassword.setWrong( true );
|
|
mPassword.d->cachedValue = TQString();
|
|
}
|
|
|
|
delete this;
|
|
}
|
|
bool clearPassword()
|
|
{
|
|
kdDebug( 14010 ) << k_funcinfo << " clearing password" << endl;
|
|
|
|
mPassword.d->remembered = false;
|
|
mPassword.d->passwordFromTDEConfig = TQString();
|
|
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()
|
|
{
|
|
TDEConfig *config = TDEGlobal::config();
|
|
config->setGroup( d->configGroup );
|
|
|
|
TQString passwordCrypted = config->readEntry( "Password" );
|
|
if ( passwordCrypted.isNull() )
|
|
d->passwordFromTDEConfig = TQString();
|
|
else
|
|
d->passwordFromTDEConfig = KStringHandler::obscure( passwordCrypted );
|
|
|
|
d->remembered = config->readBoolEntry( "RememberPassword", false );
|
|
d->isWrong = config->readBoolEntry( "PasswordIsWrong", false );
|
|
}
|
|
|
|
void Kopete::Password::writeConfig()
|
|
{
|
|
TDEConfig *config = TDEGlobal::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->passwordFromTDEConfig.isNull() )
|
|
config->writeEntry( "Password", KStringHandler::obscure( d->passwordFromTDEConfig ) );
|
|
else
|
|
config->deleteEntry( "Password" );
|
|
|
|
config->writeEntry( "RememberPassword", d->remembered );
|
|
config->writeEntry( "PasswordIsWrong", d->isWrong );
|
|
}
|
|
|
|
int Kopete::Password::preferredImageSize()
|
|
{
|
|
return IconSize(TDEIcon::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();
|
|
}
|
|
|
|
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"
|