2011-11-14 09:56:55 +00:00
|
|
|
/******************************************************************************
|
|
|
|
* Copyright (C) 2011 Frank Osterfeld <frank.osterfeld@gmail.com> *
|
|
|
|
* *
|
|
|
|
* This program is distributed in the hope that it will be useful, but *
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
|
|
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. For licensing and distribution *
|
|
|
|
* details, check the accompanying file 'COPYING'. *
|
|
|
|
*****************************************************************************/
|
|
|
|
#include "keychain_p.h"
|
2012-07-27 21:10:47 +00:00
|
|
|
#include "keychain_dbus_p.h"
|
2011-11-14 09:56:55 +00:00
|
|
|
|
|
|
|
#include <QSettings>
|
|
|
|
|
|
|
|
using namespace QKeychain;
|
|
|
|
|
2012-07-27 21:10:47 +00:00
|
|
|
JobExecutor::JobExecutor()
|
|
|
|
: QObject( 0 )
|
|
|
|
, m_runningJob( 0 )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void JobExecutor::enqueue( Job* job ) {
|
|
|
|
m_queue.append( job );
|
|
|
|
startNextIfNoneRunning();
|
|
|
|
}
|
|
|
|
|
|
|
|
void JobExecutor::startNextIfNoneRunning() {
|
|
|
|
if ( m_queue.isEmpty() || m_runningJob )
|
|
|
|
return;
|
|
|
|
QPointer<Job> next;
|
|
|
|
while ( !next && !m_queue.isEmpty() ) {
|
|
|
|
next = m_queue.first();
|
|
|
|
m_queue.pop_front();
|
|
|
|
}
|
|
|
|
if ( next ) {
|
|
|
|
connect( next, SIGNAL(finished(QKeychain::Job*)), this, SLOT(jobFinished(QKeychain::Job*)) );
|
|
|
|
connect( next, SIGNAL(destroyed(QObject*)), this, SLOT(jobDestroyed(QObject*)) );
|
|
|
|
m_runningJob = next;
|
|
|
|
if ( ReadPasswordJob* rpj = qobject_cast<ReadPasswordJob*>( m_runningJob ) )
|
|
|
|
rpj->d->scheduledStart();
|
|
|
|
else if ( WritePasswordJob* wpj = qobject_cast<WritePasswordJob*>( m_runningJob) )
|
|
|
|
wpj->d->scheduledStart();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void JobExecutor::jobDestroyed( QObject* object ) {
|
|
|
|
Q_UNUSED( object ) // for release mode
|
|
|
|
Q_ASSERT( object == m_runningJob );
|
|
|
|
m_runningJob->disconnect( this );
|
|
|
|
m_runningJob = 0;
|
|
|
|
startNextIfNoneRunning();
|
|
|
|
}
|
|
|
|
|
|
|
|
void JobExecutor::jobFinished( Job* job ) {
|
|
|
|
Q_UNUSED( job ) // for release mode
|
|
|
|
Q_ASSERT( job == m_runningJob );
|
|
|
|
m_runningJob->disconnect( this );
|
|
|
|
m_runningJob = 0;
|
|
|
|
startNextIfNoneRunning();
|
|
|
|
}
|
|
|
|
|
|
|
|
JobExecutor* JobExecutor::s_instance = 0;
|
|
|
|
|
|
|
|
JobExecutor* JobExecutor::instance() {
|
|
|
|
if ( !s_instance )
|
|
|
|
s_instance = new JobExecutor;
|
|
|
|
return s_instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ReadPasswordJobPrivate::doStart() {
|
|
|
|
JobExecutor::instance()->enqueue( q );
|
|
|
|
}
|
|
|
|
|
|
|
|
void ReadPasswordJobPrivate::scheduledStart() {
|
2012-05-08 08:47:38 +00:00
|
|
|
iface = new org::kde::KWallet( QLatin1String("org.kde.kwalletd"), QLatin1String("/modules/kwalletd"), QDBusConnection::sessionBus(), this );
|
|
|
|
const QDBusPendingReply<int> reply = iface->open( QLatin1String("kdewallet"), 0, q->service() );
|
|
|
|
QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher( reply, this );
|
|
|
|
connect( watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletOpenFinished(QDBusPendingCallWatcher*)) );
|
|
|
|
}
|
|
|
|
|
2012-07-27 21:10:47 +00:00
|
|
|
void ReadPasswordJobPrivate::kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) {
|
2012-05-08 08:47:38 +00:00
|
|
|
watcher->deleteLater();
|
|
|
|
const QDBusPendingReply<int> reply = *watcher;
|
|
|
|
if ( reply.isError() ) {
|
|
|
|
const QDBusError err = reply.error();
|
2012-05-08 15:23:26 +00:00
|
|
|
if ( err.type() == QDBusError::ServiceUnknown ) //KWalletd not running
|
|
|
|
q->emitFinishedWithError( NoBackendAvailable, tr("No keychain service available") );
|
|
|
|
else
|
|
|
|
q->emitFinishedWithError( OtherError, tr("Could not open wallet: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
|
2012-05-08 08:47:38 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
walletHandle = reply.value();
|
|
|
|
|
2012-05-08 15:38:14 +00:00
|
|
|
if ( walletHandle < 0 ) {
|
|
|
|
q->emitFinishedWithError( AccessDenied, tr("Access to keychain denied") );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-05-08 08:47:38 +00:00
|
|
|
const QDBusPendingReply<int> nextReply = iface->entryType( walletHandle, q->service(), key, q->service() );
|
|
|
|
QDBusPendingCallWatcher* nextWatcher = new QDBusPendingCallWatcher( nextReply, this );
|
|
|
|
connect( nextWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletEntryTypeFinished(QDBusPendingCallWatcher*)) );
|
|
|
|
}
|
|
|
|
|
2012-07-27 21:10:47 +00:00
|
|
|
void ReadPasswordJobPrivate::kwalletEntryTypeFinished( QDBusPendingCallWatcher* watcher ) {
|
2012-05-08 08:47:38 +00:00
|
|
|
watcher->deleteLater();
|
|
|
|
if ( watcher->isError() ) {
|
|
|
|
const QDBusError err = watcher->error();
|
|
|
|
q->emitFinishedWithError( OtherError, tr("Could not determine data type: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QDBusPendingReply<int> reply = *watcher;
|
|
|
|
|
|
|
|
dataType = reply.value() == 1/*Password*/ ? Text : Binary;
|
|
|
|
|
|
|
|
const QDBusPendingCall nextReply = dataType == Text
|
|
|
|
? QDBusPendingCall( iface->readPassword( walletHandle, q->service(), key, q->service() ) )
|
|
|
|
: QDBusPendingCall( iface->readEntry( walletHandle, q->service(), key, q->service() ) );
|
|
|
|
QDBusPendingCallWatcher* nextWatcher = new QDBusPendingCallWatcher( nextReply, this );
|
|
|
|
connect( nextWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletReadFinished(QDBusPendingCallWatcher*)) );
|
|
|
|
}
|
|
|
|
|
2012-07-27 21:10:47 +00:00
|
|
|
void ReadPasswordJobPrivate::kwalletReadFinished( QDBusPendingCallWatcher* watcher ) {
|
2012-05-08 08:47:38 +00:00
|
|
|
watcher->deleteLater();
|
|
|
|
if ( watcher->isError() ) {
|
|
|
|
const QDBusError err = watcher->error();
|
|
|
|
q->emitFinishedWithError( OtherError, tr("Could not read password: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( dataType == Binary ) {
|
|
|
|
QDBusPendingReply<QByteArray> reply = *watcher;
|
|
|
|
data = reply.value();
|
|
|
|
} else {
|
|
|
|
QDBusPendingReply<QString> reply = *watcher;
|
|
|
|
data = reply.value().toUtf8();
|
|
|
|
}
|
|
|
|
q->emitFinished();
|
2011-11-14 09:56:55 +00:00
|
|
|
}
|
|
|
|
|
2012-07-27 21:10:47 +00:00
|
|
|
void WritePasswordJobPrivate::doStart() {
|
|
|
|
JobExecutor::instance()->enqueue( q );
|
|
|
|
}
|
|
|
|
|
|
|
|
void WritePasswordJobPrivate::scheduledStart() {
|
2012-05-07 16:21:22 +00:00
|
|
|
iface = new org::kde::KWallet( QLatin1String("org.kde.kwalletd"), QLatin1String("/modules/kwalletd"), QDBusConnection::sessionBus(), this );
|
|
|
|
const QDBusPendingReply<int> reply = iface->open( QLatin1String("kdewallet"), 0, q->service() );
|
|
|
|
QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher( reply, this );
|
|
|
|
connect( watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletOpenFinished(QDBusPendingCallWatcher*)) );
|
|
|
|
}
|
|
|
|
|
2012-07-27 21:10:47 +00:00
|
|
|
void WritePasswordJobPrivate::kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) {
|
2012-05-07 16:21:22 +00:00
|
|
|
watcher->deleteLater();
|
|
|
|
QDBusPendingReply<int> reply = *watcher;
|
|
|
|
if ( reply.isError() ) {
|
|
|
|
const QDBusError err = reply.error();
|
|
|
|
q->emitFinishedWithError( OtherError, tr("Could not open wallet: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const int handle = reply.value();
|
|
|
|
|
2012-05-08 15:38:14 +00:00
|
|
|
if ( handle < 0 ) {
|
|
|
|
q->emitFinishedWithError( AccessDenied, tr("Access to keychain denied") );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-05-07 16:21:22 +00:00
|
|
|
QDBusPendingReply<int> nextReply;
|
|
|
|
|
|
|
|
if ( !textData.isEmpty() )
|
|
|
|
nextReply = iface->writePassword( handle, q->service(), key, textData, q->service() );
|
|
|
|
else if ( !binaryData.isEmpty() )
|
|
|
|
nextReply = iface->writeEntry( handle, q->service(), key, binaryData, q->service() );
|
|
|
|
else
|
|
|
|
nextReply = iface->removeEntry( handle, q->service(), key, q->service() );
|
|
|
|
|
|
|
|
QDBusPendingCallWatcher* nextWatcher = new QDBusPendingCallWatcher( nextReply, this );
|
|
|
|
connect( nextWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletWriteFinished(QDBusPendingCallWatcher*)) );
|
|
|
|
}
|
|
|
|
|
2012-07-27 21:10:47 +00:00
|
|
|
void WritePasswordJobPrivate::kwalletWriteFinished( QDBusPendingCallWatcher* watcher ) {
|
2012-05-07 16:21:22 +00:00
|
|
|
watcher->deleteLater();
|
|
|
|
QDBusPendingReply<int> reply = *watcher;
|
|
|
|
if ( reply.isError() ) {
|
|
|
|
const QDBusError err = reply.error();
|
|
|
|
q->emitFinishedWithError( OtherError, tr("Could not open wallet: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
q->emitFinished();
|
2011-11-14 09:56:55 +00:00
|
|
|
}
|