Page MenuHome GnuPG

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/crypto/certificateresolver.h b/crypto/certificateresolver.h
index 6a362aa02..c19a4ed28 100644
--- a/crypto/certificateresolver.h
+++ b/crypto/certificateresolver.h
@@ -1,106 +1,106 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/certificateresolver.h
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2007 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#ifndef __KLEOPATRA_CRYPTO_CERTIFICATERESOLVER_H__
#define __KLEOPATRA_CRYPTO_CERTIFICATERESOLVER_H__
#include <utils/pimpl_ptr.h>
#include <gpgme++/key.h>
-#include <KMime/kmime_header_parsing.h>
+#include <kmime/kmime_header_parsing.h>
#include <KSharedConfig>
#include <vector>
class KConfig;
namespace GpgME {
class Key;
}
namespace Kleo {
namespace Crypto {
class SigningPreferences {
public:
virtual ~SigningPreferences() {}
virtual GpgME::Key preferredCertificate( GpgME::Protocol protocol ) = 0;
virtual void setPreferredCertificate( GpgME::Protocol protocol, const GpgME::Key& certificate ) = 0;
};
class RecipientPreferences {
public:
virtual ~RecipientPreferences() {}
virtual GpgME::Key preferredCertificate( const KMime::Types::Mailbox& recipient, GpgME::Protocol protocol ) = 0;
virtual void setPreferredCertificate( const KMime::Types::Mailbox& recipient, GpgME::Protocol protocol, const GpgME::Key& certificate ) = 0;
};
class KConfigBasedRecipientPreferences : public RecipientPreferences {
public:
explicit KConfigBasedRecipientPreferences( KSharedConfigPtr config );
~KConfigBasedRecipientPreferences();
GpgME::Key preferredCertificate( const KMime::Types::Mailbox& recipient, GpgME::Protocol protocol );
void setPreferredCertificate( const KMime::Types::Mailbox& recipient, GpgME::Protocol protocol, const GpgME::Key& certificate );
private:
Q_DISABLE_COPY( KConfigBasedRecipientPreferences )
class Private;
kdtools::pimpl_ptr<Private> d;
};
class KConfigBasedSigningPreferences : public SigningPreferences {
public:
explicit KConfigBasedSigningPreferences( KSharedConfigPtr config );
~KConfigBasedSigningPreferences();
GpgME::Key preferredCertificate( GpgME::Protocol protocol );
void setPreferredCertificate( GpgME::Protocol protocol, const GpgME::Key& certificate );
private:
Q_DISABLE_COPY( KConfigBasedSigningPreferences )
class Private;
kdtools::pimpl_ptr<Private> d;
};
class CertificateResolver {
public:
static std::vector< std::vector<GpgME::Key> > resolveRecipients( const std::vector<KMime::Types::Mailbox> & recipients, GpgME::Protocol proto );
static std::vector<GpgME::Key> resolveRecipient( const KMime::Types::Mailbox & recipient, GpgME::Protocol proto );
static std::vector< std::vector<GpgME::Key> > resolveSigners( const std::vector<KMime::Types::Mailbox> & signers, GpgME::Protocol proto );
static std::vector<GpgME::Key> resolveSigner( const KMime::Types::Mailbox & signer, GpgME::Protocol proto );
};
}
}
#endif /* __KLEOPATRA_UISERVER_CERTIFICATERESOLVER_H__ */
diff --git a/crypto/createchecksumscontroller.h b/crypto/createchecksumscontroller.h
index 4e0eaeb3c..77c2672e6 100644
--- a/crypto/createchecksumscontroller.h
+++ b/crypto/createchecksumscontroller.h
@@ -1,78 +1,78 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/createchecksumscontroller.h
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2010 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#ifndef __KLEOPATRA_CRYPTO_CREATECHECKSUMSCONTROLLER_H__
#define __KLEOPATRA_CRYPTO_CREATECHECKSUMSCONTROLLER_H__
#include <crypto/controller.h>
#include <utils/pimpl_ptr.h>
#include <gpgme++/global.h>
-#include <KMime/kmime_header_parsing.h>
+#include <kmime/kmime_header_parsing.h>
#include <boost/shared_ptr.hpp>
#include <vector>
namespace Kleo {
namespace Crypto {
class CreateChecksumsController : public Controller {
Q_OBJECT
public:
explicit CreateChecksumsController( QObject * parent=0 );
explicit CreateChecksumsController( const boost::shared_ptr<const ExecutionContext> & ctx, QObject * parent=0 );
~CreateChecksumsController();
void setAllowAddition( bool allow );
bool allowAddition() const;
void setFiles( const QStringList & files );
void start();
public Q_SLOTS:
void cancel();
private:
class Private;
kdtools::pimpl_ptr<Private> d;
Q_PRIVATE_SLOT( d, void slotOperationFinished() )
Q_PRIVATE_SLOT( d, void slotProgress(int,int,QString) )
};
}
}
#endif /* __KLEOPATRA_UISERVER_CREATECHECKSUMSCONTROLLER_H__ */
diff --git a/crypto/decryptverifyemailcontroller.cpp b/crypto/decryptverifyemailcontroller.cpp
index a7b8b91ba..11366659a 100644
--- a/crypto/decryptverifyemailcontroller.cpp
+++ b/crypto/decryptverifyemailcontroller.cpp
@@ -1,489 +1,489 @@
/* -*- mode: c++; c-basic-offset:4 -*-
decryptverifyemailcontroller.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2008 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include <config-kleopatra.h>
#include "decryptverifyemailcontroller.h"
#include "emailoperationspreferences.h"
#include <crypto/gui/newresultpage.h>
#include <crypto/decryptverifytask.h>
#include <crypto/taskcollection.h>
#include <utils/classify.h>
#include <utils/formatting.h>
#include <utils/gnupg-helper.h>
#include <utils/input.h>
#include <utils/output.h>
#include <utils/kleo_assert.h>
#include <kleo/cryptobackendfactory.h>
-#include <KMime/kmime_header_parsing.h>
+#include <kmime/kmime_header_parsing.h>
#include <KDebug>
#include <KLocalizedString>
#include <QPoint>
#include <QPointer>
#include <QTimer>
#include <boost/shared_ptr.hpp>
#include <memory>
#include <vector>
using namespace boost;
using namespace GpgME;
using namespace Kleo;
using namespace Kleo::Crypto;
using namespace Kleo::Crypto::Gui;
using namespace KMime::Types;
namespace {
class DecryptVerifyEMailWizard : public QWizard {
Q_OBJECT
public:
explicit DecryptVerifyEMailWizard( QWidget * parent=0, Qt::WindowFlags f=0 )
: QWizard( parent, f ),
m_resultPage( this )
{
KDAB_SET_OBJECT_NAME( m_resultPage );
m_resultPage.setSubTitle( i18n("Status and progress of the crypto operations is shown here.") );
// there's no way we're letting users fast-forward over the decryption/verification results...
m_resultPage.setKeepOpenWhenDoneShown( false );
addPage( &m_resultPage );
}
void addTaskCollection( const shared_ptr<TaskCollection> & coll ) {
m_resultPage.addTaskCollection( coll );
}
public Q_SLOTS:
void accept() {
EMailOperationsPreferences prefs;
prefs.setDecryptVerifyPopupGeometry( geometry() );
prefs.writeConfig();
QWizard::accept();
}
private:
NewResultPage m_resultPage;
};
}
class DecryptVerifyEMailController::Private {
DecryptVerifyEMailController* const q;
public:
explicit Private( DecryptVerifyEMailController* qq );
void slotWizardCanceled();
void schedule();
std::vector<shared_ptr<AbstractDecryptVerifyTask> > buildTasks();
static DecryptVerifyEMailWizard * findOrCreateWizard( unsigned int id );
void ensureWizardCreated();
void ensureWizardVisible();
void reportError( int err, const QString & details ) {
q->setLastError( err, details );
q->emitDoneOrError();
}
void cancelAllTasks();
std::vector<shared_ptr<Input> > m_inputs, m_signedDatas;
std::vector<shared_ptr<Output> > m_outputs;
unsigned int m_sessionId;
QPointer<DecryptVerifyEMailWizard> m_wizard;
std::vector<shared_ptr<const DecryptVerifyResult> > m_results;
std::vector<shared_ptr<AbstractDecryptVerifyTask> > m_runnableTasks, m_completedTasks;
shared_ptr<AbstractDecryptVerifyTask> m_runningTask;
bool m_silent;
bool m_operationCompleted;
DecryptVerifyOperation m_operation;
Protocol m_protocol;
VerificationMode m_verificationMode;
std::vector<KMime::Types::Mailbox> m_informativeSenders;
};
DecryptVerifyEMailController::Private::Private( DecryptVerifyEMailController* qq )
: q( qq ),
m_sessionId( 0 ),
m_silent( false ),
m_operationCompleted( false ),
m_operation( DecryptVerify ),
m_protocol( UnknownProtocol ),
m_verificationMode( Detached )
{
qRegisterMetaType<VerificationResult>();
}
void DecryptVerifyEMailController::Private::slotWizardCanceled()
{
kDebug();
if ( !m_operationCompleted )
reportError( gpg_error( GPG_ERR_CANCELED ), i18n("User canceled") );
}
void DecryptVerifyEMailController::doTaskDone( const Task* task, const shared_ptr<const Task::Result> & result ) {
assert( task );
// We could just delete the tasks here, but we can't use
// Qt::QueuedConnection here (we need sender()) and other slots
// might not yet have executed. Therefore, we push completed tasks
// into a burial container
if ( task == d->m_runningTask.get() ) {
d->m_completedTasks.push_back( d->m_runningTask );
const shared_ptr<const DecryptVerifyResult> & dvr = boost::dynamic_pointer_cast<const DecryptVerifyResult>( result );
assert( dvr );
d->m_results.push_back( dvr );
d->m_runningTask.reset();
}
QTimer::singleShot( 0, this, SLOT(schedule()) );
}
void DecryptVerifyEMailController::Private::schedule()
{
if ( !m_runningTask && !m_runnableTasks.empty() ) {
const shared_ptr<AbstractDecryptVerifyTask> t = m_runnableTasks.back();
m_runnableTasks.pop_back();
t->start();
m_runningTask = t;
}
if ( !m_runningTask ) {
kleo_assert( m_runnableTasks.empty() );
Q_FOREACH ( const shared_ptr<const DecryptVerifyResult> & i, m_results )
emit q->verificationResult( i->verificationResult() );
// if there is a popup, wait for either the client cancel or the user closing the popup.
// Otherwise (silent case), finish immediately
m_operationCompleted = true;
q->emitDoneOrError();
}
}
void DecryptVerifyEMailController::Private::ensureWizardCreated()
{
if ( m_wizard )
return;
DecryptVerifyEMailWizard * w = findOrCreateWizard( m_sessionId );
connect( w, SIGNAL(destroyed()), q, SLOT(slotWizardCanceled()), Qt::QueuedConnection );
m_wizard = w;
}
namespace {
template <typename C>
void collectGarbage( C & c ) {
typename C::iterator it = c.begin();
while ( it != c.end() /*sic!*/ )
if ( it->second )
++it;
else
c.erase( it++ /*sic!*/ );
}
}
// static
DecryptVerifyEMailWizard * DecryptVerifyEMailController::Private::findOrCreateWizard( unsigned int id )
{
static std::map<unsigned int, QPointer<DecryptVerifyEMailWizard> > s_wizards;
collectGarbage( s_wizards );
kDebug() << "id = " << id;
if ( id != 0 ) {
const std::map<unsigned int, QPointer<DecryptVerifyEMailWizard> >::const_iterator it
= s_wizards.find( id );
if ( it != s_wizards.end() ) {
assert( it->second && "This should have been garbage-collected" );
return it->second;
}
}
DecryptVerifyEMailWizard * w = new DecryptVerifyEMailWizard;
w->setWindowTitle( i18n( "Decrypt/Verify E-Mail" ) );
w->setAttribute( Qt::WA_DeleteOnClose );
const QRect preferredGeometry = EMailOperationsPreferences().decryptVerifyPopupGeometry();
if ( preferredGeometry.isValid() )
w->setGeometry( preferredGeometry );
s_wizards[id] = w;
return w;
}
std::vector< shared_ptr<AbstractDecryptVerifyTask> > DecryptVerifyEMailController::Private::buildTasks()
{
const uint numInputs = m_inputs.size();
const uint numMessages = m_signedDatas.size();
const uint numOutputs = m_outputs.size();
const uint numInformativeSenders = m_informativeSenders.size();
// these are duplicated from DecryptVerifyCommandEMailBase::Private::checkForErrors with slightly modified error codes/messages
if ( !numInputs )
throw Kleo::Exception( makeGnuPGError( GPG_ERR_CONFLICT ),
i18n("At least one input needs to be provided") );
if ( numInformativeSenders > 0 && numInformativeSenders != numInputs )
throw Kleo::Exception( makeGnuPGError( GPG_ERR_CONFLICT ), //TODO use better error code if possible
i18n("Informative sender/signed data count mismatch") );
if ( numMessages ) {
if ( numMessages != numInputs )
throw Kleo::Exception( makeGnuPGError( GPG_ERR_CONFLICT ), //TODO use better error code if possible
i18n("Signature/signed data count mismatch") );
else if ( m_operation != Verify || m_verificationMode != Detached )
throw Kleo::Exception( makeGnuPGError( GPG_ERR_CONFLICT ),
i18n("Signed data can only be given for detached signature verification") );
}
if ( numOutputs ) {
if ( numOutputs != numInputs )
throw Kleo::Exception( makeGnuPGError( GPG_ERR_CONFLICT ), //TODO use better error code if possible
i18n("Input/Output count mismatch") );
else if ( numMessages )
throw Kleo::Exception( makeGnuPGError( GPG_ERR_CONFLICT ),
i18n("Cannot use output and signed data simultaneously") );
}
kleo_assert( m_protocol != UnknownProtocol );
const CryptoBackend::Protocol * const backend = CryptoBackendFactory::instance()->protocol( m_protocol );
if ( !backend )
throw Kleo::Exception( makeGnuPGError( GPG_ERR_UNSUPPORTED_PROTOCOL ), i18n("No backend support for %1", Formatting::displayName( m_protocol ) ) );
if ( m_operation != Decrypt && !m_silent )
ensureWizardVisible();
std::vector< shared_ptr<AbstractDecryptVerifyTask> > tasks;
for ( unsigned int i = 0 ; i < numInputs ; ++i ) {
shared_ptr<AbstractDecryptVerifyTask> task;
switch ( m_operation ) {
case Decrypt:
{
shared_ptr<DecryptTask> t( new DecryptTask );
t->setInput( m_inputs.at( i ) );
assert( numOutputs );
t->setOutput( m_outputs.at( i ) );
t->setProtocol( m_protocol );
task = t;
}
break;
case Verify:
{
if ( m_verificationMode == Detached ) {
shared_ptr<VerifyDetachedTask> t( new VerifyDetachedTask );
t->setInput( m_inputs.at( i ) );
t->setSignedData( m_signedDatas.at( i ) );
if ( numInformativeSenders > 0 )
t->setInformativeSender( m_informativeSenders.at( i ) );
t->setProtocol( m_protocol );
task = t;
} else {
shared_ptr<VerifyOpaqueTask> t( new VerifyOpaqueTask );
t->setInput( m_inputs.at( i ) );
if ( numOutputs )
t->setOutput( m_outputs.at( i ) );
if ( numInformativeSenders > 0 )
t->setInformativeSender( m_informativeSenders.at( i ) );
t->setProtocol( m_protocol );
task = t;
}
}
break;
case DecryptVerify:
{
shared_ptr<DecryptVerifyTask> t( new DecryptVerifyTask );
t->setInput( m_inputs.at( i ) );
assert( numOutputs );
t->setOutput( m_outputs.at( i ) );
if ( numInformativeSenders > 0 )
t->setInformativeSender( m_informativeSenders.at( i ) );
t->setProtocol( m_protocol );
task = t;
}
}
assert( task );
tasks.push_back( task );
}
return tasks;
}
void DecryptVerifyEMailController::Private::ensureWizardVisible()
{
ensureWizardCreated();
q->bringToForeground( m_wizard );
}
DecryptVerifyEMailController::DecryptVerifyEMailController( QObject* parent ) : Controller( parent ), d( new Private( this ) )
{
}
DecryptVerifyEMailController::DecryptVerifyEMailController( const shared_ptr<const ExecutionContext> & ctx, QObject* parent ) : Controller( ctx, parent ), d( new Private( this ) )
{
}
DecryptVerifyEMailController::~DecryptVerifyEMailController() { kDebug(); }
void DecryptVerifyEMailController::start()
{
d->m_runnableTasks = d->buildTasks();
const shared_ptr<TaskCollection> coll( new TaskCollection );
std::vector<shared_ptr<Task> > tsks;
Q_FOREACH( const shared_ptr<Task> & i, d->m_runnableTasks ) {
connectTask( i );
tsks.push_back( i );
}
coll->setTasks( tsks );
d->ensureWizardCreated();
d->m_wizard->addTaskCollection( coll );
d->ensureWizardVisible();
QTimer::singleShot( 0, this, SLOT(schedule()) );
}
void DecryptVerifyEMailController::setInput( const shared_ptr<Input> & input )
{
d->m_inputs.resize( 1, input );
}
void DecryptVerifyEMailController::setInputs( const std::vector<shared_ptr<Input> > & inputs )
{
d->m_inputs = inputs;
}
void DecryptVerifyEMailController::setSignedData( const shared_ptr<Input> & data )
{
d->m_signedDatas.resize( 1, data );
}
void DecryptVerifyEMailController::setSignedData( const std::vector<shared_ptr<Input> > & data )
{
d->m_signedDatas = data;
}
void DecryptVerifyEMailController::setOutput( const shared_ptr<Output> & output )
{
d->m_outputs.resize( 1, output );
}
void DecryptVerifyEMailController::setOutputs( const std::vector<shared_ptr<Output> > & outputs )
{
d->m_outputs = outputs;
}
void DecryptVerifyEMailController::setInformativeSenders( const std::vector<KMime::Types::Mailbox> & senders )
{
d->m_informativeSenders = senders;
}
void DecryptVerifyEMailController::setWizardShown( bool shown )
{
d->m_silent = !shown;
if ( d->m_wizard )
d->m_wizard->setVisible( shown );
}
void DecryptVerifyEMailController::setOperation( DecryptVerifyOperation operation )
{
d->m_operation = operation;
}
void DecryptVerifyEMailController::setVerificationMode( VerificationMode vm )
{
d->m_verificationMode = vm;
}
void DecryptVerifyEMailController::setProtocol( Protocol prot )
{
d->m_protocol = prot;
}
void DecryptVerifyEMailController::setSessionId( unsigned int id )
{
kDebug() << "id = " << id;
d->m_sessionId = id;
}
void DecryptVerifyEMailController::cancel()
{
kDebug();
try {
if ( d->m_wizard ) {
disconnect( d->m_wizard );
d->m_wizard->close();
}
d->cancelAllTasks();
} catch ( const std::exception & e ) {
kDebug() << "Caught exception: " << e.what();
}
}
void DecryptVerifyEMailController::Private::cancelAllTasks() {
// we just kill all runnable tasks - this will not result in
// signal emissions.
m_runnableTasks.clear();
// a cancel() will result in a call to
if ( m_runningTask )
m_runningTask->cancel();
}
#include "decryptverifyemailcontroller.moc"
#include "moc_decryptverifyemailcontroller.cpp"
diff --git a/crypto/decryptverifytask.cpp b/crypto/decryptverifytask.cpp
index a657a0d21..a6e4ea12a 100644
--- a/crypto/decryptverifytask.cpp
+++ b/crypto/decryptverifytask.cpp
@@ -1,1352 +1,1352 @@
/* -*- mode: c++; c-basic-offset:4 -*-
decryptverifytask.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2008 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include <config-kleopatra.h>
#include "decryptverifytask.h"
#include <kleo/cryptobackendfactory.h>
#include <kleo/verifyopaquejob.h>
#include <kleo/verifydetachedjob.h>
#include <kleo/decryptjob.h>
#include <kleo/decryptverifyjob.h>
#include <kleo/dn.h>
#include <kleo/exception.h>
#include <kleo/stl_util.h>
#include <models/keycache.h>
#include <models/predicates.h>
#include <utils/detail_p.h>
#include <utils/input.h>
#include <utils/output.h>
#include <utils/classify.h>
#include <utils/formatting.h>
#include <utils/kleo_assert.h>
#include <utils/auditlog.h>
-#include <KMime/kmime_header_parsing.h>
+#include <kmime/kmime_header_parsing.h>
#include <gpgme++/error.h>
#include <gpgme++/key.h>
#include <gpgme++/verificationresult.h>
#include <gpgme++/decryptionresult.h>
#include <gpg-error.h>
#include <KLocalizedString>
#include <KLocale>
#include <KGlobal>
#include <KLocalizedString>
#include <KDebug>
#include <QByteArray>
#include <QDateTime>
#include <QStringList>
#include <QTextDocument> // Qt::escape
#include <boost/bind.hpp>
#include <algorithm>
#include <cassert>
#include <sstream>
using namespace Kleo::Crypto;
using namespace Kleo;
using namespace GpgME;
using namespace boost;
using namespace KMime::Types;
namespace {
static Error make_error( const gpg_err_code_t code ) {
return Error( gpg_error( code ) );
}
static AuditLog auditLogFromSender( QObject* sender ) {
return AuditLog::fromJob( qobject_cast<const Job*>( sender ) );
}
static bool addrspec_equal( const AddrSpec & lhs, const AddrSpec & rhs, Qt::CaseSensitivity cs ) {
return lhs.localPart.compare( rhs.localPart, cs ) == 0 && lhs.domain.compare( rhs.domain, Qt::CaseInsensitive ) == 0;
}
static bool mailbox_equal( const Mailbox & lhs, const Mailbox & rhs, Qt::CaseSensitivity cs ) {
return addrspec_equal( lhs.addrSpec(), rhs.addrSpec(), cs );
}
static std::string stripAngleBrackets( const std::string & str ) {
if ( str.empty() )
return str;
if ( str[0] == '<' && str[str.size()-1] == '>' )
return str.substr( 1, str.size() - 2 );
return str;
}
static std::string email( const UserID & uid ) {
if ( uid.parent().protocol() == OpenPGP )
if ( const char * const email = uid.email() )
return stripAngleBrackets( email );
else
return std::string();
assert( uid.parent().protocol() == CMS );
if ( const char * const id = uid.id() )
if ( *id == '<' )
return stripAngleBrackets( id );
else
return DN( id )[QLatin1String("EMAIL")].trimmed().toUtf8().constData();
else
return std::string();
}
static Mailbox mailbox( const UserID & uid ) {
const std::string e = email( uid );
Mailbox mbox;
if ( !e.empty() )
mbox.setAddress( e.c_str() );
return mbox;
}
static std::vector<Mailbox> extractMailboxes( const Key & key ) {
std::vector<Mailbox> res;
Q_FOREACH( const UserID & id, key.userIDs() ) {
const Mailbox mbox = mailbox( id );
if ( !mbox.addrSpec().isEmpty() )
res.push_back( mbox );
}
return res;
}
static std::vector<Mailbox> extractMailboxes( const std::vector<Key> & signers ) {
std::vector<Mailbox> res;
Q_FOREACH( const Key & i, signers ) {
const std::vector<Mailbox> bxs = extractMailboxes( i );
res.insert( res.end(), bxs.begin(), bxs.end() );
}
return res;
}
static bool keyContainsMailbox( const Key & key, const Mailbox & mbox ) {
const std::vector<Mailbox> mbxs = extractMailboxes( key );
return std::find_if( mbxs.begin(), mbxs.end(), boost::bind( mailbox_equal, mbox, _1, Qt::CaseInsensitive ) ) != mbxs.end();
}
static bool keysContainMailbox( const std::vector<Key> & keys, const Mailbox & mbox ) {
return std::find_if( keys.begin(), keys.end(), boost::bind( keyContainsMailbox, _1, mbox ) ) != keys.end();
}
static bool relevantInDecryptVerifyContext( const VerificationResult & r ) {
// for D/V operations, we ignore verification results which are not errors and contain
// no signatures (which means that the data was just not signed)
return r.error() || r.numSignatures() > 0;
}
static QString signatureSummaryToString( int summary )
{
if ( summary & Signature::None )
return i18n( "Error: Signature not verified" );
else if ( summary & Signature::Valid || summary & Signature::Green )
return i18n( "Good signature" );
else if ( summary & Signature::Red )
return i18n( "Bad signature" );
else if ( summary & Signature::KeyRevoked )
return i18n( "Signing certificate revoked" );
else if ( summary & Signature::KeyExpired )
return i18n( "Signing certificate expired" );
else if ( summary & Signature::KeyMissing )
return i18n( "No public certificate to verify the signature" );
else if ( summary & Signature::SigExpired )
return i18n( "Signature expired" );
else if ( summary & Signature::KeyMissing )
return i18n( "Certificate missing" );
else if ( summary & Signature::CrlMissing )
return i18n( "CRL missing" );
else if ( summary & Signature::CrlTooOld )
return i18n( "CRL too old" );
else if ( summary & Signature::BadPolicy )
return i18n( "Bad policy" );
else if ( summary & Signature::SysError )
return i18n( "System error" ); //### retrieve system error details?
return QString();
}
static QString formatValidSignatureWithTrustLevel( const UserID & id ) {
if ( id.isNull() )
return QString();
switch ( id.validity() ) {
case UserID::Marginal:
return i18n( "The signature is valid but the trust in the certificate's validity is only marginal." );
case UserID::Full:
return i18n( "The signature is valid and the certificate's validity is fully trusted." );
case UserID::Ultimate:
return i18n( "The signature is valid and the certificate's validity is ultimately trusted." );
case UserID::Never:
return i18n( "The signature is valid but the certificate's validity is <em>not trusted</em>." );
case UserID::Unknown:
return i18n( "The signature is valid but the certificate's validity is unknown." );
case UserID::Undefined:
default:
return i18n( "The signature is valid but the certificate's validity is undefined." );
}
}
static QString renderFingerprint( const char * fpr ) {
if ( !fpr )
return QString();
return QString::fromLatin1( "0x%1" ).arg( QString::fromLatin1( fpr ).toUpper() );
}
static QString renderKeyLink( const QString & fpr, const QString & text ) {
return QString::fromLatin1( "<a href=\"key:%1\">%2</a>" ).arg( fpr, text );
}
static QString renderKey( const Key & key ) {
if ( key.isNull() )
return i18n( "Unknown certificate" );
return renderKeyLink( QLatin1String(key.primaryFingerprint()), Formatting::prettyName( key ) );
}
static QString renderKeyEMailOnlyNameAsFallback( const Key & key ) {
if ( key.isNull() )
return i18n( "Unknown certificate" );
const QString email = Formatting::prettyEMail( key );
const QString user = !email.isEmpty() ? email : Formatting::prettyName( key );
return renderKeyLink( QLatin1String(key.primaryFingerprint()), user );
}
static QString formatDate( const QDateTime & dt ) {
return KGlobal::locale()->formatDateTime( dt );
}
static QString formatSigningInformation( const Signature & sig, const Key & key ) {
if ( sig.isNull() )
return QString();
const QDateTime dt = sig.creationTime() != 0 ? QDateTime::fromTime_t( sig.creationTime() ) : QDateTime();
const QString signer = key.isNull() ? QString() : renderKeyEMailOnlyNameAsFallback( key );
const bool haveKey = !key.isNull();
const bool haveSigner = !signer.isEmpty();
const bool haveDate = dt.isValid();
if ( !haveKey ) {
if ( haveDate )
return i18n( "Signed on %1 with unknown certificate %2.", formatDate( dt ), renderFingerprint( sig.fingerprint() ) );
else
return i18n( "Signed with unknown certificate %1.", renderFingerprint( sig.fingerprint() ) );
}
if ( haveSigner ) {
if ( haveDate )
return i18nc( "date, key owner, key ID",
"Signed on %1 by %2 (Key ID: %3).",
formatDate( dt ),
signer,
renderFingerprint( key.shortKeyID() ) );
else
return i18n( "Signed by %1 with certificate %2.", signer, renderKey( key ) );
}
if ( haveDate )
return i18n( "Signed on %1 with certificate %2.", formatDate( dt ), renderKey( key ) );
return i18n( "Signed with certificate %1.", renderKey( key ) );
}
static QString strikeOut( const QString & str, bool strike ) {
return QString( strike ? QLatin1String("<s>%1</s>") : QLatin1String("%1") ).arg( Qt::escape( str ) );
}
static QString formatInputOutputLabel( const QString & input, const QString & output, bool inputDeleted, bool outputDeleted ) {
if ( output.isEmpty() )
return strikeOut( input, inputDeleted );
return i18nc( "Input file --> Output file (rarr is arrow", "%1 &rarr; %2",
strikeOut( input, inputDeleted ),
strikeOut( output, outputDeleted ) );
}
static bool IsErrorOrCanceled( const GpgME::Error & err )
{
return err || err.isCanceled();
}
static bool IsErrorOrCanceled( const Result & res )
{
return IsErrorOrCanceled( res.error() );
}
static bool IsBad( const Signature & sig ) {
return sig.summary() & Signature::Red;
}
static bool IsGoodOrValid( const Signature & sig ) {
return (sig.summary() & Signature::Valid) || (sig.summary() & Signature::Green);
}
static UserID findUserIDByMailbox( const Key & key, const Mailbox & mbox ) {
Q_FOREACH( const UserID & id, key.userIDs() )
if ( mailbox_equal( mailbox( id ), mbox, Qt::CaseInsensitive ) )
return id;
return UserID();
}
}
class DecryptVerifyResult::SenderInfo {
public:
explicit SenderInfo( const Mailbox & infSender, const std::vector<Key> & signers_ ) : informativeSender( infSender ), signers( signers_ ) {}
const Mailbox informativeSender;
const std::vector<Key> signers;
bool hasInformativeSender() const { return !informativeSender.addrSpec().isEmpty(); }
bool conflicts() const { return hasInformativeSender() && hasKeys() && !keysContainMailbox( signers, informativeSender ); }
bool hasKeys() const { return kdtools::any( signers, !boost::bind( &Key::isNull, _1 ) ); }
std::vector<Mailbox> signerMailboxes() const {return extractMailboxes( signers ); }
};
namespace {
static Task::Result::VisualCode codeForVerificationResult( const VerificationResult & res )
{
if ( res.isNull() )
return Task::Result::NeutralSuccess;
const std::vector<Signature> sigs = res.signatures();
if ( sigs.empty() )
return Task::Result::Warning;
if ( std::find_if( sigs.begin(), sigs.end(), IsBad ) != sigs.end() )
return Task::Result::Danger;
if ( std::count_if( sigs.begin(), sigs.end(), IsGoodOrValid ) == sigs.size() )
return Task::Result::AllGood;
return Task::Result::Warning;
}
static QString formatVerificationResultOverview( const VerificationResult & res, const DecryptVerifyResult::SenderInfo & info ) {
if ( res.isNull() )
return QString();
const Error err = res.error();
if ( err.isCanceled() )
return i18n("<b>Verification canceled.</b>");
else if ( err )
return i18n( "<b>Verification failed: %1.</b>", Qt::escape( QString::fromLocal8Bit( err.asString() ) ) );
const std::vector<Signature> sigs = res.signatures();
const std::vector<Key> signers = info.signers;
if ( sigs.empty() )
return i18n( "<b>No signatures found.</b>" );
const uint bad = std::count_if( sigs.begin(), sigs.end(), IsBad );
if ( bad > 0 ) {
return i18np("<b>Invalid signature.</b>", "<b>%1 invalid signatures.</b>", bad );
}
const uint warn = std::count_if( sigs.begin(), sigs.end(), !boost::bind( IsGoodOrValid, _1 ) );
if ( warn > 0 )
return i18np("<b>Not enough information to check signature validity.</b>", "<b>%1 signatures could not be verified.</b>", warn );
//Good signature:
QString text;
if ( sigs.size() == 1 ) {
const Key key = DecryptVerifyResult::keyForSignature( sigs[0], signers );
if ( key.isNull() )
return i18n( "<b>Signature is valid.</b>" );
text = i18n( "<b>Signed by %1</b>", renderKeyEMailOnlyNameAsFallback( key ) );
if ( info.conflicts() )
text += i18n( "<br/><b>Warning:</b> The sender's mail address is not stored in the %1 used for signing.",
renderKeyLink( QLatin1String(key.primaryFingerprint()), i18n( "certificate" ) ) );
}
else {
text = i18np("<b>Valid signature.</b>", "<b>%1 valid signatures.</b>", sigs.size() );
if ( info.conflicts() )
text += i18n( "<br/><b>Warning:</b> The sender's mail address is not stored in the certificates used for signing." );
}
return text;
}
static QString formatDecryptionResultOverview( const DecryptionResult & result, const QString& errorString = QString() )
{
const Error err = result.error();
if ( err.isCanceled() )
return i18n("<b>Decryption canceled.</b>");
else if ( !errorString.isEmpty() )
return i18n( "<b>Decryption failed: %1.</b>", Qt::escape( errorString ) );
else if ( err )
return i18n( "<b>Decryption failed: %1.</b>", Qt::escape( QString::fromLocal8Bit( err.asString() ) ) );
return i18n("<b>Decryption succeeded.</b>" );
}
static QString formatSignature( const Signature & sig, const Key & key, const DecryptVerifyResult::SenderInfo & info ) {
if ( sig.isNull() )
return QString();
const QString text = formatSigningInformation( sig, key ) + QLatin1String("<br/>");
const bool red = sig.summary() & Signature::Red;
if ( sig.summary() & Signature::Valid ) {
const UserID id = findUserIDByMailbox( key, info.informativeSender );
return text + formatValidSignatureWithTrustLevel( !id.isNull() ? id : key.userID( 0 ) );
}
if ( red )
return text + i18n("The signature is bad.");
if ( !sig.summary() )
return text + i18n("The validity of the signature cannot be verified.");
return text + i18n("The signature is invalid: %1", signatureSummaryToString( sig.summary() ) );
}
static QStringList format( const std::vector<Mailbox> & mbxs ) {
QStringList res;
std::transform( mbxs.begin(), mbxs.end(), std::back_inserter( res ), boost::bind( &Mailbox::prettyAddress, _1 ) );
return res;
}
static QString formatVerificationResultDetails( const VerificationResult & res, const DecryptVerifyResult::SenderInfo & info, const QString& errorString )
{
if( (res.error().code() == GPG_ERR_EIO || res.error().code() == GPG_ERR_NO_DATA) && !errorString.isEmpty() )
return i18n( "Input error: %1", errorString );
const std::vector<Signature> sigs = res.signatures();
const std::vector<Key> signers = KeyCache::instance()->findSigners( res );
QString details;
Q_FOREACH ( const Signature & sig, sigs )
details += formatSignature( sig, DecryptVerifyResult::keyForSignature( sig, signers ), info ) + QLatin1Char('\n');
details = details.trimmed();
details.replace( QLatin1Char('\n'), QLatin1String("<br/>") );
if ( info.conflicts() )
details += i18n( "<p>The sender's address %1 is not stored in the certificate. Stored: %2</p>", info.informativeSender.prettyAddress(), format( info.signerMailboxes() ).join( i18nc("separator for a list of e-mail addresses", ", " ) ) );
return details;
}
static QString formatDecryptionResultDetails( const DecryptionResult & res, const std::vector<Key> & recipients, const QString& errorString )
{
if( (res.error().code() == GPG_ERR_EIO || res.error().code() == GPG_ERR_NO_DATA) && !errorString.isEmpty() )
return i18n( "Input error: %1", errorString );
if ( res.isNull() || !res.error() || res.error().isCanceled() )
return QString();
if ( recipients.empty() && res.numRecipients() > 0 )
return QLatin1String( "<i>") + i18np( "One unknown recipient.", "%1 unknown recipients.", res.numRecipients() ) + QLatin1String("</i>");
QString details;
if ( !recipients.empty() ) {
details += i18np( "Recipient:", "Recipients:", res.numRecipients() );
if ( res.numRecipients() == 1 )
return details + renderKey( recipients.front() );
details += QLatin1String("<ul>");
Q_FOREACH( const Key & key, recipients )
details += QLatin1String("<li>") + renderKey( key ) + QLatin1String("</li>");
if ( recipients.size() < res.numRecipients() )
details += QLatin1String("<li><i>") + i18np( "One unknown recipient", "%1 unknown recipients",
res.numRecipients() - recipients.size() ) + QLatin1String("</i></li>");
details += QLatin1String("</ul>");
}
return details;
}
static QString formatDecryptVerifyResultOverview( const DecryptionResult & dr, const VerificationResult & vr, const DecryptVerifyResult::SenderInfo & info )
{
if ( IsErrorOrCanceled( dr ) || !relevantInDecryptVerifyContext( vr ) )
return formatDecryptionResultOverview( dr );
return formatVerificationResultOverview( vr, info );
}
static QString formatDecryptVerifyResultDetails( const DecryptionResult & dr,
const VerificationResult & vr,
const std::vector<Key> & recipients,
const DecryptVerifyResult::SenderInfo & info,
const QString& errorString )
{
const QString drDetails = formatDecryptionResultDetails( dr, recipients, errorString );
if ( IsErrorOrCanceled( dr ) || !relevantInDecryptVerifyContext( vr ) )
return drDetails;
return drDetails + ( drDetails.isEmpty() ? QString() : QLatin1String("<br/>") ) + formatVerificationResultDetails( vr, info, errorString );
}
} // anon namespace
class DecryptVerifyResult::Private {
DecryptVerifyResult* const q;
public:
Private( DecryptVerifyOperation type,
const VerificationResult & vr,
const DecryptionResult & dr,
const QByteArray & stuff,
int errCode,
const QString & errString,
const QString & input,
const QString & output,
const AuditLog & auditLog,
const Mailbox & informativeSender,
DecryptVerifyResult* qq ) :
q( qq ),
m_type( type ),
m_verificationResult( vr ),
m_decryptionResult( dr ),
m_stuff( stuff ),
m_error( errCode ),
m_errorString( errString ),
m_inputLabel( input ),
m_outputLabel( output ),
m_auditLog( auditLog ),
m_informativeSender( informativeSender )
{
}
QString label() const {
return formatInputOutputLabel( m_inputLabel, m_outputLabel, false, q->hasError() );
}
DecryptVerifyResult::SenderInfo makeSenderInfo() const;
bool isDecryptOnly() const { return m_type == Decrypt; }
bool isVerifyOnly() const { return m_type == Verify; }
bool isDecryptVerify() const { return m_type == DecryptVerify; }
DecryptVerifyOperation m_type;
VerificationResult m_verificationResult;
DecryptionResult m_decryptionResult;
QByteArray m_stuff;
int m_error;
QString m_errorString;
QString m_inputLabel;
QString m_outputLabel;
const AuditLog m_auditLog;
const Mailbox m_informativeSender;
};
DecryptVerifyResult::SenderInfo DecryptVerifyResult::Private::makeSenderInfo() const {
return SenderInfo( m_informativeSender, KeyCache::instance()->findSigners( m_verificationResult ) );
}
shared_ptr<DecryptVerifyResult> AbstractDecryptVerifyTask::fromDecryptResult( const DecryptionResult & dr, const QByteArray & plaintext, const AuditLog & auditLog ) {
return shared_ptr<DecryptVerifyResult>( new DecryptVerifyResult(
Decrypt,
VerificationResult(),
dr,
plaintext,
0,
QString(),
inputLabel(),
outputLabel(),
auditLog,
informativeSender() ) );
}
shared_ptr<DecryptVerifyResult> AbstractDecryptVerifyTask::fromDecryptResult( const GpgME::Error & err, const QString& what, const AuditLog & auditLog ) {
return shared_ptr<DecryptVerifyResult>( new DecryptVerifyResult(
Decrypt,
VerificationResult(),
DecryptionResult( err ),
QByteArray(),
err.code(),
what,
inputLabel(),
outputLabel(),
auditLog,
informativeSender() ) );
}
shared_ptr<DecryptVerifyResult> AbstractDecryptVerifyTask::fromDecryptVerifyResult( const DecryptionResult & dr, const VerificationResult & vr, const QByteArray & plaintext, const AuditLog & auditLog ) {
return shared_ptr<DecryptVerifyResult>( new DecryptVerifyResult(
DecryptVerify,
vr,
dr,
plaintext,
0,
QString(),
inputLabel(),
outputLabel(),
auditLog,
informativeSender() ) );
}
shared_ptr<DecryptVerifyResult> AbstractDecryptVerifyTask::fromDecryptVerifyResult( const GpgME::Error & err, const QString & details, const AuditLog & auditLog ) {
return shared_ptr<DecryptVerifyResult>( new DecryptVerifyResult(
DecryptVerify,
VerificationResult(),
DecryptionResult( err ),
QByteArray(),
err.code(),
details,
inputLabel(),
outputLabel(),
auditLog,
informativeSender() ) );
}
shared_ptr<DecryptVerifyResult> AbstractDecryptVerifyTask::fromVerifyOpaqueResult( const VerificationResult & vr, const QByteArray & plaintext, const AuditLog & auditLog ) {
return shared_ptr<DecryptVerifyResult>( new DecryptVerifyResult(
Verify,
vr,
DecryptionResult(),
plaintext,
0,
QString(),
inputLabel(),
outputLabel(),
auditLog,
informativeSender() ) );
}
shared_ptr<DecryptVerifyResult> AbstractDecryptVerifyTask::fromVerifyOpaqueResult( const GpgME::Error & err, const QString & details, const AuditLog & auditLog ) {
return shared_ptr<DecryptVerifyResult>( new DecryptVerifyResult(
Verify,
VerificationResult( err ),
DecryptionResult(),
QByteArray(),
err.code(),
details,
inputLabel(),
outputLabel(),
auditLog,
informativeSender() ) );
}
shared_ptr<DecryptVerifyResult> AbstractDecryptVerifyTask::fromVerifyDetachedResult( const VerificationResult & vr, const AuditLog & auditLog ) {
return shared_ptr<DecryptVerifyResult>( new DecryptVerifyResult(
Verify,
vr,
DecryptionResult(),
QByteArray(),
0,
QString(),
inputLabel(),
outputLabel(),
auditLog,
informativeSender() ) );
}
shared_ptr<DecryptVerifyResult> AbstractDecryptVerifyTask::fromVerifyDetachedResult( const GpgME::Error & err, const QString & details, const AuditLog & auditLog ) {
return shared_ptr<DecryptVerifyResult>( new DecryptVerifyResult(
Verify,
VerificationResult( err ),
DecryptionResult(),
QByteArray(),
err.code(),
details,
inputLabel(),
outputLabel(),
auditLog,
informativeSender() ) );
}
DecryptVerifyResult::DecryptVerifyResult( DecryptVerifyOperation type,
const VerificationResult& vr,
const DecryptionResult& dr,
const QByteArray& stuff,
int errCode,
const QString & errString,
const QString & inputLabel,
const QString & outputLabel,
const AuditLog & auditLog,
const Mailbox & informativeSender )
: Task::Result(), d( new Private( type, vr, dr, stuff, errCode, errString, inputLabel, outputLabel, auditLog, informativeSender, this ) )
{
}
QString DecryptVerifyResult::overview() const
{
QString ov;
if ( d->isDecryptOnly() )
ov = formatDecryptionResultOverview( d->m_decryptionResult );
else if ( d->isVerifyOnly() )
ov = formatVerificationResultOverview( d->m_verificationResult, d->makeSenderInfo() );
else
ov = formatDecryptVerifyResultOverview( d->m_decryptionResult, d->m_verificationResult, d->makeSenderInfo() );
return i18nc( "label: result example: foo.sig: Verification failed. ", "%1: %2", d->label(), ov );
}
QString DecryptVerifyResult::details() const
{
if ( d->isDecryptOnly() )
return formatDecryptionResultDetails( d->m_decryptionResult, KeyCache::instance()->findRecipients( d->m_decryptionResult ), errorString() );
if ( d->isVerifyOnly() )
return formatVerificationResultDetails( d->m_verificationResult, d->makeSenderInfo(), errorString() );
return formatDecryptVerifyResultDetails( d->m_decryptionResult,
d->m_verificationResult, KeyCache::instance()->findRecipients(
d->m_decryptionResult ), d->makeSenderInfo(), errorString() );
}
bool DecryptVerifyResult::hasError() const
{
return d->m_error != 0;
}
int DecryptVerifyResult::errorCode() const
{
return d->m_error;
}
QString DecryptVerifyResult::errorString() const
{
return d->m_errorString;
}
AuditLog DecryptVerifyResult::auditLog() const {
return d->m_auditLog;
}
Task::Result::VisualCode DecryptVerifyResult::code() const {
if ( ( d->m_type == DecryptVerify || d->m_type == Verify ) && relevantInDecryptVerifyContext( verificationResult() ) )
return codeForVerificationResult( verificationResult() );
return hasError() ? NeutralError : NeutralSuccess;
}
GpgME::VerificationResult DecryptVerifyResult::verificationResult() const
{
return d->m_verificationResult;
}
const Key & DecryptVerifyResult::keyForSignature( const Signature & sig, const std::vector<Key> & keys ) {
if ( const char * const fpr = sig.fingerprint() ) {
const std::vector<Key>::const_iterator it
= std::lower_bound( keys.begin(), keys.end(), fpr, _detail::ByFingerprint<std::less>() );
if ( it != keys.end() && _detail::ByFingerprint<std::equal_to>()( *it, fpr ) )
return *it;
}
static const Key null;
return null;
}
class AbstractDecryptVerifyTask::Private {
public:
Mailbox informativeSender;
};
AbstractDecryptVerifyTask::AbstractDecryptVerifyTask( QObject * parent ) : Task( parent ), d( new Private ) {}
AbstractDecryptVerifyTask::~AbstractDecryptVerifyTask() {}
Mailbox AbstractDecryptVerifyTask::informativeSender() const {
return d->informativeSender;
}
void AbstractDecryptVerifyTask::setInformativeSender( const Mailbox & sender ) {
d->informativeSender = sender;
}
class DecryptVerifyTask::Private {
DecryptVerifyTask* const q;
public:
explicit Private( DecryptVerifyTask* qq ) : q( qq ), m_backend( 0 ), m_protocol( UnknownProtocol ) {}
void slotResult( const DecryptionResult&, const VerificationResult&, const QByteArray& );
void registerJob( DecryptVerifyJob * job ) {
q->connect( job, SIGNAL(result(GpgME::DecryptionResult,GpgME::VerificationResult,QByteArray)),
q, SLOT(slotResult(GpgME::DecryptionResult,GpgME::VerificationResult,QByteArray)) );
q->connect( job, SIGNAL(progress(QString,int,int)),
q, SLOT(setProgress(QString,int,int)) );
}
void emitResult( const shared_ptr<DecryptVerifyResult>& result );
shared_ptr<Input> m_input;
shared_ptr<Output> m_output;
const CryptoBackend::Protocol* m_backend;
Protocol m_protocol;
};
void DecryptVerifyTask::Private::emitResult( const shared_ptr<DecryptVerifyResult>& result )
{
q->emitResult( result );
emit q->decryptVerifyResult( result );
}
void DecryptVerifyTask::Private::slotResult( const DecryptionResult& dr, const VerificationResult& vr, const QByteArray& plainText )
{
{
std::stringstream ss;
ss << dr << '\n' << vr;
kDebug() << ss.str().c_str();
}
const AuditLog auditLog = auditLogFromSender( q->sender() );
if ( dr.error().code() || vr.error().code() ) {
m_output->cancel();
} else {
try {
kleo_assert( !dr.isNull() || !vr.isNull() );
m_output->finalize();
} catch ( const GpgME::Exception & e ) {
emitResult( q->fromDecryptResult( e.error(), QString::fromLocal8Bit( e.what() ), auditLog ) );
return;
} catch ( const std::exception & e ) {
emitResult( q->fromDecryptResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught exception: %1", QString::fromLocal8Bit( e.what() ) ), auditLog ) );
return;
} catch ( ... ) {
emitResult( q->fromDecryptResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught unknown exception"), auditLog ) );
return;
}
}
const int drErr = dr.error().code();
const QString errorString = m_output->errorString();
if ( (drErr == GPG_ERR_EIO || drErr == GPG_ERR_NO_DATA) && !errorString.isEmpty() ) {
emitResult( q->fromDecryptResult( dr.error(), errorString, auditLog ) );
return;
}
emitResult( q->fromDecryptVerifyResult( dr, vr, plainText, auditLog ) );
}
DecryptVerifyTask::DecryptVerifyTask( QObject* parent ) : AbstractDecryptVerifyTask( parent ), d( new Private( this ) )
{
}
DecryptVerifyTask::~DecryptVerifyTask()
{
}
void DecryptVerifyTask::setInput( const shared_ptr<Input> & input )
{
d->m_input = input;
kleo_assert( d->m_input && d->m_input->ioDevice() );
}
void DecryptVerifyTask::setOutput( const shared_ptr<Output> & output )
{
d->m_output = output;
kleo_assert( d->m_output && d->m_output->ioDevice() );
}
void DecryptVerifyTask::setProtocol( Protocol prot )
{
kleo_assert( prot != UnknownProtocol );
d->m_protocol = prot;
d->m_backend = CryptoBackendFactory::instance()->protocol( prot );
kleo_assert( d->m_backend );
}
void DecryptVerifyTask::autodetectProtocolFromInput()
{
if ( !d->m_input )
return;
const Protocol p = findProtocol( d->m_input->classification() );
if ( p == UnknownProtocol )
throw Exception( gpg_error( GPG_ERR_NOTHING_FOUND ), i18n("Could not determine whether this is an S/MIME or an OpenPGP signature/ciphertext - maybe it is neither ciphertext nor a signature?"), Exception::MessageOnly );
setProtocol( p );
}
QString DecryptVerifyTask::label() const
{
return i18n( "Decrypting: %1...", d->m_input->label() );
}
unsigned long long DecryptVerifyTask::inputSize() const
{
return d->m_input ? d->m_input->size() : 0;
}
QString DecryptVerifyTask::inputLabel() const
{
return d->m_input ? d->m_input->label() : QString();
}
QString DecryptVerifyTask::outputLabel() const
{
return d->m_output ? d->m_output->label() : QString();
}
Protocol DecryptVerifyTask::protocol() const
{
return d->m_protocol;
}
void DecryptVerifyTask::cancel()
{
}
void DecryptVerifyTask::doStart()
{
kleo_assert( d->m_backend );
try {
DecryptVerifyJob * const job = d->m_backend->decryptVerifyJob();
kleo_assert( job );
d->registerJob( job );
job->start( d->m_input->ioDevice(), d->m_output->ioDevice() );
} catch ( const GpgME::Exception & e ) {
d->emitResult( fromDecryptVerifyResult( e.error(), QString::fromLocal8Bit( e.what() ), AuditLog() ) );
} catch ( const std::exception & e ) {
d->emitResult( fromDecryptVerifyResult( make_error( GPG_ERR_INTERNAL ), i18n( "Caught exception: %1", QString::fromLocal8Bit( e.what() ) ), AuditLog() ) );
} catch ( ... ) {
d->emitResult( fromDecryptVerifyResult( make_error( GPG_ERR_INTERNAL ), i18n( "Caught unknown exception" ), AuditLog() ) );
}
}
class DecryptTask::Private {
DecryptTask* const q;
public:
explicit Private( DecryptTask* qq ) : q( qq ), m_backend( 0 ), m_protocol( UnknownProtocol ) {}
void slotResult( const DecryptionResult&, const QByteArray& );
void registerJob( DecryptJob * job ) {
q->connect( job, SIGNAL(result(GpgME::DecryptionResult,QByteArray)),
q, SLOT(slotResult(GpgME::DecryptionResult,QByteArray)) );
q->connect( job, SIGNAL(progress(QString,int,int)),
q, SLOT(setProgress(QString,int,int)) );
}
void emitResult( const shared_ptr<DecryptVerifyResult>& result );
shared_ptr<Input> m_input;
shared_ptr<Output> m_output;
const CryptoBackend::Protocol* m_backend;
Protocol m_protocol;
};
void DecryptTask::Private::emitResult( const shared_ptr<DecryptVerifyResult>& result )
{
q->emitResult( result );
emit q->decryptVerifyResult( result );
}
void DecryptTask::Private::slotResult( const DecryptionResult& result, const QByteArray& plainText )
{
{
std::stringstream ss;
ss << result;
kDebug() << ss.str().c_str();
}
const AuditLog auditLog = auditLogFromSender( q->sender() );
if ( result.error().code() ) {
m_output->cancel();
} else {
try {
kleo_assert( !result.isNull() );
m_output->finalize();
} catch ( const GpgME::Exception & e ) {
emitResult( q->fromDecryptResult( e.error(), QString::fromLocal8Bit( e.what() ), auditLog ) );
return;
} catch ( const std::exception & e ) {
emitResult( q->fromDecryptResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught exception: %1", QString::fromLocal8Bit( e.what() ) ), auditLog ) );
return;
} catch ( ... ) {
emitResult( q->fromDecryptResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught unknown exception"), auditLog ) );
return;
}
}
const int drErr = result.error().code();
const QString errorString = m_output->errorString();
if ( (drErr == GPG_ERR_EIO || drErr == GPG_ERR_NO_DATA) && !errorString.isEmpty() ) {
emitResult( q->fromDecryptResult( result.error(), errorString, auditLog ) );
return;
}
emitResult( q->fromDecryptResult( result, plainText, auditLog ) );
}
DecryptTask::DecryptTask( QObject* parent ) : AbstractDecryptVerifyTask( parent ), d( new Private( this ) )
{
}
DecryptTask::~DecryptTask()
{
}
void DecryptTask::setInput( const shared_ptr<Input> & input )
{
d->m_input = input;
kleo_assert( d->m_input && d->m_input->ioDevice() );
}
void DecryptTask::setOutput( const shared_ptr<Output> & output )
{
d->m_output = output;
kleo_assert( d->m_output && d->m_output->ioDevice() );
}
void DecryptTask::setProtocol( Protocol prot )
{
kleo_assert( prot != UnknownProtocol );
d->m_protocol = prot;
d->m_backend = CryptoBackendFactory::instance()->protocol( prot );
kleo_assert( d->m_backend );
}
void DecryptTask::autodetectProtocolFromInput()
{
if ( !d->m_input )
return;
const Protocol p = findProtocol( d->m_input->classification() );
if ( p == UnknownProtocol )
throw Exception( gpg_error( GPG_ERR_NOTHING_FOUND ), i18n("Could not determine whether this was S/MIME- or OpenPGP-encrypted - maybe it is not ciphertext at all?"), Exception::MessageOnly );
setProtocol( p );
}
QString DecryptTask::label() const
{
return i18n( "Decrypting: %1...", d->m_input->label() );
}
unsigned long long DecryptTask::inputSize() const
{
return d->m_input ? d->m_input->size() : 0;
}
QString DecryptTask::inputLabel() const
{
return d->m_input ? d->m_input->label() : QString();
}
QString DecryptTask::outputLabel() const
{
return d->m_output ? d->m_output->label() : QString();
}
Protocol DecryptTask::protocol() const
{
kleo_assert( !"not implemented" );
return UnknownProtocol; // ### TODO
}
void DecryptTask::cancel()
{
}
void DecryptTask::doStart()
{
kleo_assert( d->m_backend );
try {
DecryptJob * const job = d->m_backend->decryptJob();
kleo_assert( job );
d->registerJob( job );
job->start( d->m_input->ioDevice(), d->m_output->ioDevice() );
} catch ( const GpgME::Exception & e ) {
d->emitResult( fromDecryptResult( e.error(), QString::fromLocal8Bit( e.what() ), AuditLog() ) );
} catch ( const std::exception & e ) {
d->emitResult( fromDecryptResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught exception: %1", QString::fromLocal8Bit( e.what() ) ), AuditLog() ) );
} catch ( ... ) {
d->emitResult( fromDecryptResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught unknown exception"), AuditLog() ) );
}
}
class VerifyOpaqueTask::Private {
VerifyOpaqueTask* const q;
public:
explicit Private( VerifyOpaqueTask* qq ) : q( qq ), m_backend( 0 ), m_protocol( UnknownProtocol ) {}
void slotResult( const VerificationResult&, const QByteArray& );
void registerJob( VerifyOpaqueJob* job ) {
q->connect( job, SIGNAL(result(GpgME::VerificationResult,QByteArray)),
q, SLOT(slotResult(GpgME::VerificationResult,QByteArray)) );
q->connect( job, SIGNAL(progress(QString,int,int)),
q, SLOT(setProgress(QString,int,int)) );
}
void emitResult( const shared_ptr<DecryptVerifyResult>& result );
shared_ptr<Input> m_input;
shared_ptr<Output> m_output;
const CryptoBackend::Protocol* m_backend;
Protocol m_protocol;
};
void VerifyOpaqueTask::Private::emitResult( const shared_ptr<DecryptVerifyResult>& result )
{
q->emitResult( result );
emit q->decryptVerifyResult( result );
}
void VerifyOpaqueTask::Private::slotResult( const VerificationResult& result, const QByteArray& plainText )
{
{
std::stringstream ss;
ss << result;
kDebug() << ss.str().c_str();
}
const AuditLog auditLog = auditLogFromSender( q->sender() );
if ( result.error().code() ) {
m_output->cancel();
} else {
try {
kleo_assert( !result.isNull() );
m_output->finalize();
} catch ( const GpgME::Exception & e ) {
emitResult( q->fromDecryptResult( e.error(), QString::fromLocal8Bit( e.what() ), auditLog ) );
return;
} catch ( const std::exception & e ) {
emitResult( q->fromDecryptResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught exception: %1", QString::fromLocal8Bit( e.what() ) ), auditLog ) );
return;
} catch ( ... ) {
emitResult( q->fromDecryptResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught unknown exception"), auditLog ) );
return;
}
}
const int drErr = result.error().code();
const QString errorString = m_output->errorString();
if ( (drErr == GPG_ERR_EIO || drErr == GPG_ERR_NO_DATA) && !errorString.isEmpty() ) {
emitResult( q->fromDecryptResult( result.error(), errorString, auditLog ) );
return;
}
emitResult( q->fromVerifyOpaqueResult( result, plainText, auditLog ) );
}
VerifyOpaqueTask::VerifyOpaqueTask( QObject* parent ) : AbstractDecryptVerifyTask( parent ), d( new Private( this ) )
{
}
VerifyOpaqueTask::~VerifyOpaqueTask()
{
}
void VerifyOpaqueTask::setInput( const shared_ptr<Input> & input )
{
d->m_input = input;
kleo_assert( d->m_input && d->m_input->ioDevice() );
}
void VerifyOpaqueTask::setOutput( const shared_ptr<Output> & output )
{
d->m_output = output;
kleo_assert( d->m_output && d->m_output->ioDevice() );
}
void VerifyOpaqueTask::setProtocol( Protocol prot )
{
kleo_assert( prot != UnknownProtocol );
d->m_protocol = prot;
d->m_backend = CryptoBackendFactory::instance()->protocol( prot );
kleo_assert( d->m_backend );
}
void VerifyOpaqueTask::autodetectProtocolFromInput()
{
if ( !d->m_input )
return;
const Protocol p = findProtocol( d->m_input->classification() );
if ( p == UnknownProtocol )
throw Exception( gpg_error( GPG_ERR_NOTHING_FOUND ), i18n("Could not determine whether this is an S/MIME or an OpenPGP signature - maybe it is not a signature at all?"), Exception::MessageOnly );
setProtocol( p );
}
QString VerifyOpaqueTask::label() const
{
return i18n( "Verifying: %1...", d->m_input->label() );
}
unsigned long long VerifyOpaqueTask::inputSize() const
{
return d->m_input ? d->m_input->size() : 0;
}
QString VerifyOpaqueTask::inputLabel() const
{
return d->m_input ? d->m_input->label() : QString();
}
QString VerifyOpaqueTask::outputLabel() const
{
return d->m_output ? d->m_output->label() : QString();
}
Protocol VerifyOpaqueTask::protocol() const
{
return d->m_protocol;
}
void VerifyOpaqueTask::cancel()
{
}
void VerifyOpaqueTask::doStart()
{
kleo_assert( d->m_backend );
try {
VerifyOpaqueJob * const job = d->m_backend->verifyOpaqueJob();
kleo_assert( job );
d->registerJob( job );
job->start( d->m_input->ioDevice(), d->m_output ? d->m_output->ioDevice() : shared_ptr<QIODevice>() );
} catch ( const GpgME::Exception & e ) {
d->emitResult( fromVerifyOpaqueResult( e.error(), QString::fromLocal8Bit( e.what() ), AuditLog() ) );
} catch ( const std::exception & e ) {
d->emitResult( fromVerifyOpaqueResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught exception: %1", QString::fromLocal8Bit( e.what() ) ), AuditLog() ) );
} catch ( ... ) {
d->emitResult( fromVerifyOpaqueResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught unknown exception"), AuditLog() ) );
}
}
class VerifyDetachedTask::Private {
VerifyDetachedTask* const q;
public:
explicit Private( VerifyDetachedTask* qq ) : q( qq ), m_backend( 0 ), m_protocol( UnknownProtocol ) {}
void slotResult( const VerificationResult& );
void registerJob( VerifyDetachedJob* job ) {
q->connect( job, SIGNAL(result(GpgME::VerificationResult)),
q, SLOT(slotResult(GpgME::VerificationResult)) );
q->connect( job, SIGNAL(progress(QString,int,int)),
q, SLOT(setProgress(QString,int,int)) );
}
void emitResult( const shared_ptr<DecryptVerifyResult>& result );
shared_ptr<Input> m_input, m_signedData;
const CryptoBackend::Protocol* m_backend;
Protocol m_protocol;
};
void VerifyDetachedTask::Private::emitResult( const shared_ptr<DecryptVerifyResult>& result )
{
q->emitResult( result );
emit q->decryptVerifyResult( result );
}
void VerifyDetachedTask::Private::slotResult( const VerificationResult& result )
{
{
std::stringstream ss;
ss << result;
kDebug() << ss.str().c_str();
}
const AuditLog auditLog = auditLogFromSender( q->sender() );
try {
kleo_assert( !result.isNull() );
emitResult( q->fromVerifyDetachedResult( result, auditLog ) );
} catch ( const GpgME::Exception & e ) {
emitResult( q->fromVerifyDetachedResult( e.error(), QString::fromLocal8Bit( e.what() ), auditLog ) );
} catch ( const std::exception & e ) {
emitResult( q->fromVerifyDetachedResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught exception: %1", QString::fromLocal8Bit( e.what() ) ), auditLog ) );
} catch ( ... ) {
emitResult( q->fromVerifyDetachedResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught unknown exception"), auditLog ) );
}
}
VerifyDetachedTask::VerifyDetachedTask( QObject* parent ) : AbstractDecryptVerifyTask( parent ), d( new Private( this ) )
{
}
VerifyDetachedTask::~VerifyDetachedTask()
{
}
void VerifyDetachedTask::setInput( const shared_ptr<Input> & input )
{
d->m_input = input;
kleo_assert( d->m_input && d->m_input->ioDevice() );
}
void VerifyDetachedTask::setSignedData( const shared_ptr<Input> & signedData )
{
d->m_signedData = signedData;
kleo_assert( d->m_signedData && d->m_signedData->ioDevice() );
}
void VerifyDetachedTask::setProtocol( Protocol prot )
{
kleo_assert( prot != UnknownProtocol );
d->m_protocol = prot;
d->m_backend = CryptoBackendFactory::instance()->protocol( prot );
kleo_assert( d->m_backend );
}
void VerifyDetachedTask::autodetectProtocolFromInput()
{
if ( !d->m_input )
return;
const Protocol p = findProtocol( d->m_input->classification() );
if ( p == UnknownProtocol )
throw Exception( gpg_error( GPG_ERR_NOTHING_FOUND ), i18n("Could not determine whether this is an S/MIME or an OpenPGP signature - maybe it is not a signature at all?"), Exception::MessageOnly );
setProtocol( p );
}
unsigned long long VerifyDetachedTask::inputSize() const
{
return d->m_signedData ? d->m_signedData->size() : 0;
}
QString VerifyDetachedTask::label() const
{
return i18n( "Verifying signature: %1...", d->m_input->label() );
}
QString VerifyDetachedTask::inputLabel() const
{
return d->m_input ? d->m_input->label() : QString();
}
QString VerifyDetachedTask::outputLabel() const
{
return QString();
}
Protocol VerifyDetachedTask::protocol() const
{
kleo_assert( !"not implemented" );
return UnknownProtocol; // ### TODO
}
void VerifyDetachedTask::cancel()
{
}
void VerifyDetachedTask::doStart()
{
kleo_assert( d->m_backend );
try {
VerifyDetachedJob * const job = d->m_backend->verifyDetachedJob();
kleo_assert( job );
d->registerJob( job );
job->start( d->m_input->ioDevice(), d->m_signedData->ioDevice() );
} catch ( const GpgME::Exception & e ) {
d->emitResult( fromVerifyDetachedResult( e.error(), QString::fromLocal8Bit( e.what() ), AuditLog() ) );
} catch ( const std::exception & e ) {
d->emitResult( fromVerifyDetachedResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught exception: %1", QString::fromLocal8Bit( e.what() ) ), AuditLog() ) );
} catch ( ... ) {
d->emitResult( fromVerifyDetachedResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught unknown exception"), AuditLog() ) );
}
}
#include "moc_decryptverifytask.cpp"
diff --git a/crypto/encryptemailcontroller.cpp b/crypto/encryptemailcontroller.cpp
index 4c5cf84ab..c39c09a4d 100644
--- a/crypto/encryptemailcontroller.cpp
+++ b/crypto/encryptemailcontroller.cpp
@@ -1,314 +1,314 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/encryptemailcontroller.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2007 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include <config-kleopatra.h>
#include "encryptemailcontroller.h"
#include "encryptemailtask.h"
#include "taskcollection.h"
#include <crypto/gui/encryptemailwizard.h>
#include <utils/input.h>
#include <utils/output.h>
#include <utils/kleo_assert.h>
#include <kleo/stl_util.h>
#include <kleo/exception.h>
#include "emailoperationspreferences.h"
#include <gpgme++/key.h>
-#include <KMime/kmime_header_parsing.h>
+#include <kmime/kmime_header_parsing.h>
#include <KLocalizedString>
#include <KDebug>
#include <QPointer>
#include <QTimer>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
using namespace Kleo;
using namespace Kleo::Crypto;
using namespace Kleo::Crypto::Gui;
using namespace boost;
using namespace GpgME;
using namespace KMime::Types;
class EncryptEMailController::Private {
friend class ::Kleo::Crypto::EncryptEMailController;
EncryptEMailController * const q;
public:
explicit Private( Mode mode, EncryptEMailController * qq );
private:
void slotWizardRecipientsResolved();
void slotWizardCanceled();
private:
void ensureWizardCreated() const;
void ensureWizardVisible();
void cancelAllTasks();
void schedule();
shared_ptr<EncryptEMailTask> takeRunnable( GpgME::Protocol proto );
private:
const Mode mode;
std::vector< shared_ptr<EncryptEMailTask> > runnable, completed;
shared_ptr<EncryptEMailTask> cms, openpgp;
mutable QPointer<EncryptEMailWizard> wizard;
};
EncryptEMailController::Private::Private( Mode m, EncryptEMailController * qq )
: q( qq ),
mode( m ),
runnable(),
cms(),
openpgp(),
wizard()
{
}
EncryptEMailController::EncryptEMailController( const shared_ptr<ExecutionContext> & xc, Mode mode, QObject * p )
: Controller( xc, p ), d( new Private( mode, this ) )
{
}
EncryptEMailController::EncryptEMailController( Mode mode, QObject * p )
: Controller( p ), d( new Private( mode, this ) )
{
}
EncryptEMailController::~EncryptEMailController() {
if ( d->wizard && !d->wizard->isVisible() )
delete d->wizard;
//d->wizard->close(); ### ?
}
EncryptEMailController::Mode EncryptEMailController::mode() const {
return d->mode;
}
void EncryptEMailController::setProtocol( Protocol proto ) {
d->ensureWizardCreated();
const Protocol protocol = d->wizard->presetProtocol();
kleo_assert( protocol == UnknownProtocol ||
protocol == proto );
d->wizard->setPresetProtocol( proto );
}
Protocol EncryptEMailController::protocol() const {
d->ensureWizardCreated();
return d->wizard->selectedProtocol();
}
const char * EncryptEMailController::protocolAsString() const {
switch ( protocol() ) {
case OpenPGP: return "OpenPGP";
case CMS: return "CMS";
default:
throw Kleo::Exception( gpg_error( GPG_ERR_INTERNAL ),
i18n("Call to EncryptEMailController::protocolAsString() is ambiguous.") );
}
}
void EncryptEMailController::startResolveRecipients() {
startResolveRecipients( std::vector<Mailbox>(), std::vector<Mailbox>() );
}
void EncryptEMailController::startResolveRecipients( const std::vector<Mailbox> & recipients, const std::vector<Mailbox> & senders ) {
d->ensureWizardCreated();
d->wizard->setRecipients( recipients, senders );
d->ensureWizardVisible();
}
void EncryptEMailController::Private::slotWizardRecipientsResolved() {
emit q->recipientsResolved();
}
void EncryptEMailController::Private::slotWizardCanceled() {
q->setLastError( gpg_error( GPG_ERR_CANCELED ), i18n("User cancel") );
q->emitDoneOrError();
}
void EncryptEMailController::setInputAndOutput( const shared_ptr<Input> & input, const shared_ptr<Output> & output ) {
setInputsAndOutputs( std::vector< shared_ptr<Input> >( 1, input ), std::vector< shared_ptr<Output> >( 1, output ) );
}
void EncryptEMailController::setInputsAndOutputs( const std::vector< shared_ptr<Input> > & inputs, const std::vector< shared_ptr<Output> > & outputs ) {
kleo_assert( !inputs.empty() );
kleo_assert( outputs.size() == inputs.size() );
std::vector< shared_ptr<EncryptEMailTask> > tasks;
tasks.reserve( inputs.size() );
d->ensureWizardCreated();
const std::vector<Key> keys = d->wizard->resolvedCertificates();
kleo_assert( !keys.empty() );
for ( unsigned int i = 0, end = inputs.size() ; i < end ; ++i ) {
const shared_ptr<EncryptEMailTask> task( new EncryptEMailTask );
task->setInput( inputs[i] );
task->setOutput( outputs[i] );
if ( d->mode == ClipboardMode )
task->setAsciiArmor( true );
task->setRecipients( keys );
tasks.push_back( task );
}
d->runnable.swap( tasks );
}
void EncryptEMailController::start() {
shared_ptr<TaskCollection> coll( new TaskCollection );
std::vector<shared_ptr<Task> > tmp;
std::copy( d->runnable.begin(), d->runnable.end(), std::back_inserter( tmp ) );
coll->setTasks( tmp );
d->ensureWizardCreated();
d->wizard->setTaskCollection( coll );
Q_FOREACH( const shared_ptr<Task> & t, tmp )
connectTask( t );
d->schedule();
}
void EncryptEMailController::Private::schedule() {
if ( !cms )
if ( const shared_ptr<EncryptEMailTask> t = takeRunnable( CMS ) ) {
t->start();
cms = t;
}
if ( !openpgp )
if ( const shared_ptr<EncryptEMailTask> t = takeRunnable( OpenPGP ) ) {
t->start();
openpgp = t;
}
if ( cms || openpgp )
return;
kleo_assert( runnable.empty() );
q->emitDoneOrError();
}
shared_ptr<EncryptEMailTask> EncryptEMailController::Private::takeRunnable( GpgME::Protocol proto ) {
const std::vector< shared_ptr<EncryptEMailTask> >::iterator it
= std::find_if( runnable.begin(), runnable.end(),
boost::bind( &Task::protocol, _1 ) == proto );
if ( it == runnable.end() )
return shared_ptr<EncryptEMailTask>();
const shared_ptr<EncryptEMailTask> result = *it;
runnable.erase( it );
return result;
}
void EncryptEMailController::doTaskDone( const Task * task, const shared_ptr<const Task::Result> & result )
{
Q_UNUSED( result );
assert( task );
// We could just delete the tasks here, but we can't use
// Qt::QueuedConnection here (we need sender()) and other slots
// might not yet have executed. Therefore, we push completed tasks
// into a burial container
if ( task == d->cms.get() ) {
d->completed.push_back( d->cms );
d->cms.reset();
} else if ( task == d->openpgp.get() ) {
d->completed.push_back( d->openpgp );
d->openpgp.reset();
}
QTimer::singleShot( 0, this, SLOT(schedule()) );
}
void EncryptEMailController::cancel() {
try {
if ( d->wizard )
d->wizard->close();
d->cancelAllTasks();
} catch ( const std::exception & e ) {
kDebug() << "Caught exception: " << e.what();
}
}
void EncryptEMailController::Private::cancelAllTasks() {
// we just kill all runnable tasks - this will not result in
// signal emissions.
runnable.clear();
// a cancel() will result in a call to
if ( cms )
cms->cancel();
if ( openpgp )
openpgp->cancel();
}
void EncryptEMailController::Private::ensureWizardCreated() const {
if ( wizard )
return;
std::auto_ptr<EncryptEMailWizard> w( new EncryptEMailWizard );
w->setAttribute( Qt::WA_DeleteOnClose );
Kleo::EMailOperationsPreferences prefs;
w->setQuickMode( prefs.quickEncryptEMail() );
connect( w.get(), SIGNAL(recipientsResolved()), q, SLOT(slotWizardRecipientsResolved()), Qt::QueuedConnection );
connect( w.get(), SIGNAL(canceled()), q, SLOT(slotWizardCanceled()), Qt::QueuedConnection );
wizard = w.release();
}
void EncryptEMailController::Private::ensureWizardVisible() {
ensureWizardCreated();
q->bringToForeground( wizard );
}
#include "moc_encryptemailcontroller.cpp"
diff --git a/crypto/gui/resolverecipientspage.cpp b/crypto/gui/resolverecipientspage.cpp
index 79ef8f460..582a80e55 100644
--- a/crypto/gui/resolverecipientspage.cpp
+++ b/crypto/gui/resolverecipientspage.cpp
@@ -1,719 +1,719 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/gui/resolverecipientspage.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2007 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include <config-kleopatra.h>
#include "resolverecipientspage.h"
#include "resolverecipientspage_p.h"
#include <dialogs/certificateselectiondialog.h>
#include <crypto/certificateresolver.h>
#include <models/keycache.h>
#include <utils/formatting.h>
-#include <KMime/kmime_header_parsing.h>
+#include <kmime/kmime_header_parsing.h>
#include <gpgme++/key.h>
#include <KLocalizedString>
#include <QButtonGroup>
#include <QComboBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QListWidget>
#include <QPointer>
#include <QPushButton>
#include <QRadioButton>
#include <QToolButton>
#include <QStringList>
#include <QVBoxLayout>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <cassert>
using namespace GpgME;
using namespace boost;
using namespace Kleo;
using namespace Kleo::Dialogs;
using namespace Kleo::Crypto;
using namespace Kleo::Crypto::Gui;
using namespace KMime::Types;
ResolveRecipientsPage::ListWidget::ListWidget( QWidget* parent, Qt::WindowFlags flags ) : QWidget( parent, flags ), m_protocol( UnknownProtocol )
{
m_listWidget = new QListWidget;
m_listWidget->setSelectionMode( QAbstractItemView::MultiSelection );
QVBoxLayout * const layout = new QVBoxLayout( this );
layout->addWidget( m_listWidget );
connect( m_listWidget, SIGNAL(itemSelectionChanged()), this, SLOT(onSelectionChange()) );
}
ResolveRecipientsPage::ListWidget::~ListWidget()
{
}
void ResolveRecipientsPage::ListWidget::onSelectionChange()
{
Q_FOREACH ( const QString& i, widgets.keys() ) { //krazy:exclude=foreach
assert( items.contains( i ) );
widgets[i]->setSelected( items[i]->isSelected() );
}
emit selectionChanged();
}
void ResolveRecipientsPage::ListWidget::addEntry( const Mailbox& mbox )
{
addEntry( mbox.prettyAddress(), mbox.prettyAddress(), mbox );
}
void ResolveRecipientsPage::ListWidget::addEntry( const QString& id, const QString& name )
{
addEntry( id, name, Mailbox() );
}
void ResolveRecipientsPage::ListWidget::addEntry( const QString& id, const QString& name, const Mailbox& mbox )
{
assert( !widgets.contains( id ) && !items.contains( id ) );
QListWidgetItem* item = new QListWidgetItem;
item->setData( IdRole, id );
ItemWidget* wid = new ItemWidget( id, name, mbox, this );
connect( wid, SIGNAL(changed()), this, SIGNAL(completeChanged()) );
wid->setProtocol( m_protocol );
item->setSizeHint( wid->sizeHint() );
m_listWidget->addItem( item );
m_listWidget->setItemWidget( item, wid );
widgets[id] = wid;
items[id] = item;
}
Mailbox ResolveRecipientsPage::ListWidget::mailbox( const QString& id ) const
{
return widgets.contains( id ) ? widgets[id]->mailbox() : Mailbox();
}
void ResolveRecipientsPage::ListWidget::setCertificates( const QString& id, const std::vector<Key>& pgp, const std::vector<Key>& cms )
{
assert( widgets.contains( id ) );
widgets[id]->setCertificates( pgp, cms );
}
Key ResolveRecipientsPage::ListWidget::selectedCertificate( const QString& id ) const
{
return widgets.contains( id ) ? widgets[id]->selectedCertificate() : Key();
}
GpgME::Key ResolveRecipientsPage::ListWidget::selectedCertificate( const QString& id, GpgME::Protocol prot ) const
{
return widgets.contains( id ) ? widgets[id]->selectedCertificate( prot ) : Key();
}
QStringList ResolveRecipientsPage::ListWidget::identifiers() const
{
return widgets.keys();
}
void ResolveRecipientsPage::ListWidget::setProtocol( GpgME::Protocol prot )
{
if ( m_protocol == prot )
return;
m_protocol = prot;
Q_FOREACH ( ItemWidget* i, widgets )
i->setProtocol( prot );
}
void ResolveRecipientsPage::ListWidget::removeEntry( const QString& id )
{
if ( !widgets.contains( id ) )
return;
delete items[id];
items.remove( id );
delete widgets[id];
widgets.remove( id );
}
void ResolveRecipientsPage::ListWidget::showSelectionDialog( const QString& id )
{
if ( !widgets.contains( id ) )
return;
widgets[id]->showSelectionDialog();
}
QStringList ResolveRecipientsPage::ListWidget::selectedEntries() const
{
QStringList entries;
const QList<QListWidgetItem*> items = m_listWidget->selectedItems();
Q_FOREACH ( const QListWidgetItem* i, items )
{
entries.append( i->data( IdRole ).toString() );
}
return entries;
}
ResolveRecipientsPage::ItemWidget::ItemWidget( const QString& id, const QString& name, const Mailbox& mbox,
QWidget* parent, Qt::WindowFlags flags ) : QWidget( parent, flags ), m_id( id ), m_mailbox( mbox ), m_protocol( UnknownProtocol ), m_selected( false )
{
assert( !m_id.isEmpty() );
setAutoFillBackground( true );
QHBoxLayout* layout = new QHBoxLayout( this );
layout->setMargin( 0 );
layout->addSpacing( 15 );
m_nameLabel = new QLabel;
m_nameLabel->setText( name );
layout->addWidget( m_nameLabel );
layout->addStretch();
m_certLabel = new QLabel;
m_certLabel->setText( i18n( "<i>No certificate selected</i>" ) );
layout->addWidget( m_certLabel );
m_certCombo = new QComboBox;
connect( m_certCombo, SIGNAL(currentIndexChanged(int)),
this, SIGNAL(changed()) );
layout->addWidget( m_certCombo );
m_selectButton = new QToolButton;
m_selectButton->setText( i18n( "..." ) );
connect( m_selectButton, SIGNAL(clicked()),
this, SLOT(showSelectionDialog()) );
layout->addWidget( m_selectButton );
layout->addSpacing( 15 );
setCertificates( std::vector<Key>(), std::vector<Key>() );
}
void ResolveRecipientsPage::ItemWidget::updateVisibility()
{
m_certLabel->setVisible( m_certCombo->count() == 0 );
m_certCombo->setVisible( m_certCombo->count() > 0 );
}
ResolveRecipientsPage::ItemWidget::~ItemWidget()
{
}
QString ResolveRecipientsPage::ItemWidget::id() const
{
return m_id;
}
void ResolveRecipientsPage::ItemWidget::setSelected( bool selected )
{
if ( m_selected == selected )
return;
m_selected = selected;
setBackgroundRole( selected ? QPalette::Highlight : QPalette::Base );
const QPalette::ColorRole foreground = selected ? QPalette::HighlightedText : QPalette::Text;
setForegroundRole( foreground );
m_nameLabel->setForegroundRole( foreground );
m_certLabel->setForegroundRole( foreground );
}
bool ResolveRecipientsPage::ItemWidget::isSelected() const
{
return m_selected;
}
static CertificateSelectionDialog::Option protocol2option( GpgME::Protocol proto ) {
switch ( proto ) {
case OpenPGP: return CertificateSelectionDialog::OpenPGPFormat;
case CMS: return CertificateSelectionDialog::CMSFormat;
default: return CertificateSelectionDialog::AnyFormat;
}
}
static CertificateSelectionDialog * createCertificateSelectionDialog( QWidget* parent, GpgME::Protocol prot ) {
CertificateSelectionDialog * const dlg = new CertificateSelectionDialog( parent );
const CertificateSelectionDialog::Options options =
CertificateSelectionDialog::SingleSelection |
CertificateSelectionDialog::EncryptOnly |
CertificateSelectionDialog::MultiSelection |
protocol2option( prot );
dlg->setOptions( options );
return dlg;
}
void ResolveRecipientsPage::ItemWidget::showSelectionDialog()
{
QPointer<CertificateSelectionDialog> dlg = createCertificateSelectionDialog( this, m_protocol );
if ( dlg->exec() == QDialog::Accepted && dlg /* still with us? */ ) {
const GpgME::Key cert = dlg->selectedCertificate();
if ( !cert.isNull() ) {
addCertificateToComboBox( cert );
selectCertificateInComboBox( cert );
}
}
delete dlg;
}
Mailbox ResolveRecipientsPage::ItemWidget::mailbox() const
{
return m_mailbox;
}
void ResolveRecipientsPage::ItemWidget::selectCertificateInComboBox( const Key& key )
{
m_certCombo->setCurrentIndex( m_certCombo->findData( QLatin1String(key.keyID()) ) );
}
void ResolveRecipientsPage::ItemWidget::addCertificateToComboBox( const GpgME::Key& key )
{
m_certCombo->addItem( Formatting::formatForComboBox( key ), QByteArray( key.keyID() ) );
if ( m_certCombo->count() == 1 )
m_certCombo->setCurrentIndex( 0 );
updateVisibility();
}
void ResolveRecipientsPage::ItemWidget::resetCertificates()
{
std::vector<Key> certs;
Key selected;
switch ( m_protocol )
{
case OpenPGP:
certs = m_pgp;
break;
case CMS:
certs = m_cms;
break;
case UnknownProtocol:
certs = m_cms;
certs.insert( certs.end(), m_pgp.begin(), m_pgp.end() );
}
m_certCombo->clear();
Q_FOREACH ( const Key& i, certs )
addCertificateToComboBox( i );
if ( !m_selectedCertificates[m_protocol].isNull() )
selectCertificateInComboBox( m_selectedCertificates[m_protocol] );
else if ( m_certCombo->count() > 0 )
m_certCombo->setCurrentIndex( 0 );
updateVisibility();
emit changed();
}
void ResolveRecipientsPage::ItemWidget::setProtocol( Protocol prot )
{
if ( m_protocol == prot )
return;
m_selectedCertificates[m_protocol] = selectedCertificate();
if ( m_protocol != UnknownProtocol )
( m_protocol == OpenPGP ? m_pgp : m_cms ) = certificates();
m_protocol = prot;
resetCertificates();
}
void ResolveRecipientsPage::ItemWidget::setCertificates( const std::vector<Key>& pgp, const std::vector<Key>& cms )
{
m_pgp = pgp;
m_cms = cms;
resetCertificates();
}
Key ResolveRecipientsPage::ItemWidget::selectedCertificate() const
{
#ifdef QT_STL
return KeyCache::instance()->findByKeyIDOrFingerprint( m_certCombo->itemData( m_certCombo->currentIndex(), ListWidget::IdRole ).toString().toStdString() );
#else
const QString tmpStr = m_certCombo->itemData( m_certCombo->currentIndex(), ListWidget::IdRole ).toString();
const QByteArray asc = tmpStr.toLatin1();
std::string tmpstdstring = std::string(asc.constData(), asc.length());
return KeyCache::instance()->findByKeyIDOrFingerprint( tmpstdstring );
#endif
}
GpgME::Key ResolveRecipientsPage::ItemWidget::selectedCertificate( GpgME::Protocol prot ) const
{
return prot == m_protocol ? selectedCertificate() : m_selectedCertificates.value( prot );
}
std::vector<Key> ResolveRecipientsPage::ItemWidget::certificates() const
{
std::vector<Key> certs;
for ( int i = 0; i < m_certCombo->count(); ++i ) {
#ifdef QT_STL
certs.push_back( KeyCache::instance()->findByKeyIDOrFingerprint( m_certCombo->itemData( i, ListWidget::IdRole ).toString().toStdString() ) );
#else
const QString tmpStr = m_certCombo->itemData( i, ListWidget::IdRole ).toString();
const QByteArray asc = tmpStr.toLatin1();
std::string tmpstdstring = std::string(asc.constData(), asc.length());
certs.push_back( KeyCache::instance()->findByKeyIDOrFingerprint( tmpstdstring ) );
#endif
}
return certs;
}
class ResolveRecipientsPage::Private {
friend class ::Kleo::Crypto::Gui::ResolveRecipientsPage;
ResolveRecipientsPage * const q;
public:
explicit Private( ResolveRecipientsPage * qq );
~Private();
void setSelectedProtocol( Protocol protocol );
void selectionChanged();
void removeSelectedEntries();
void addRecipient();
void addRecipient( const Mailbox& mbox );
void addRecipient( const QString& id, const QString& name );
void updateProtocolRBVisibility();
void protocolSelected( int prot );
void writeSelectedCertificatesToPreferences();
void completeChangedInternal();
private:
ListWidget* m_listWidget;
QPushButton* m_addButton;
QPushButton* m_removeButton;
QRadioButton* m_pgpRB;
QRadioButton* m_cmsRB;
QLabel* m_additionalRecipientsLabel;
Protocol m_presetProtocol;
Protocol m_selectedProtocol;
bool m_multipleProtocolsAllowed;
boost::shared_ptr<RecipientPreferences> m_recipientPreferences;
};
ResolveRecipientsPage::Private::Private( ResolveRecipientsPage * qq )
: q( qq ), m_presetProtocol( UnknownProtocol ), m_selectedProtocol( m_presetProtocol ), m_multipleProtocolsAllowed( false ), m_recipientPreferences()
{
connect( q, SIGNAL(completeChanged()), q, SLOT(completeChangedInternal()) );
q->setTitle( i18n( "<b>Recipients</b>" ) );
QVBoxLayout* const layout = new QVBoxLayout( q );
m_listWidget = new ListWidget;
connect( m_listWidget, SIGNAL(selectionChanged()), q, SLOT(selectionChanged()) );
connect( m_listWidget, SIGNAL(completeChanged()), q, SIGNAL(completeChanged()) );
layout->addWidget( m_listWidget );
m_additionalRecipientsLabel = new QLabel;
m_additionalRecipientsLabel->setWordWrap( true );
layout->addWidget( m_additionalRecipientsLabel );
m_additionalRecipientsLabel->setVisible( false );
QWidget* buttonWidget = new QWidget;
QHBoxLayout* buttonLayout = new QHBoxLayout( buttonWidget );
buttonLayout->setMargin( 0 );
m_addButton = new QPushButton;
connect( m_addButton, SIGNAL(clicked()), q, SLOT(addRecipient()) );
m_addButton->setText( i18n( "Add Recipient..." ) );
buttonLayout->addWidget( m_addButton );
m_removeButton = new QPushButton;
m_removeButton->setEnabled( false );
m_removeButton->setText( i18n( "Remove Selected" ) );
connect( m_removeButton, SIGNAL(clicked()),
q, SLOT(removeSelectedEntries()) );
buttonLayout->addWidget( m_removeButton );
buttonLayout->addStretch();
layout->addWidget( buttonWidget );
QWidget* protocolWidget = new QWidget;
QHBoxLayout* protocolLayout = new QHBoxLayout( protocolWidget );
QButtonGroup* protocolGroup = new QButtonGroup( q );
connect( protocolGroup, SIGNAL(buttonClicked(int)), q, SLOT(protocolSelected(int)) );
m_pgpRB = new QRadioButton;
m_pgpRB->setText( i18n( "OpenPGP" ) );
protocolGroup->addButton( m_pgpRB, OpenPGP );
protocolLayout->addWidget( m_pgpRB );
m_cmsRB = new QRadioButton;
m_cmsRB->setText( i18n( "S/MIME" ) );
protocolGroup->addButton( m_cmsRB, CMS );
protocolLayout->addWidget( m_cmsRB );
protocolLayout->addStretch();
layout->addWidget( protocolWidget );
}
ResolveRecipientsPage::Private::~Private() {}
void ResolveRecipientsPage::Private::completeChangedInternal()
{
const bool isComplete = q->isComplete();
const std::vector<Key> keys = q->resolvedCertificates();
const bool haveSecret = std::find_if( keys.begin(), keys.end(), boost::bind( &Key::hasSecret, _1 ) ) != keys.end();
if ( isComplete && !haveSecret )
q->setExplanation( i18n( "<b>Warning:</b> None of the selected certificates seem to be your own. You will not be able to decrypt the encrypted data again." ) );
else
q->setExplanation( QString() );
}
void ResolveRecipientsPage::Private::updateProtocolRBVisibility()
{
const bool visible = !m_multipleProtocolsAllowed && m_presetProtocol == UnknownProtocol;
m_cmsRB->setVisible( visible );
m_pgpRB->setVisible( visible );
if ( visible )
{
if ( m_selectedProtocol == CMS )
m_cmsRB->click();
else
m_pgpRB->click();
}
}
bool ResolveRecipientsPage::isComplete() const
{
const QStringList ids = d->m_listWidget->identifiers();
if ( ids.isEmpty() )
return false;
Q_FOREACH ( const QString& i, ids )
{
if ( d->m_listWidget->selectedCertificate( i ).isNull() )
return false;
}
return true;
}
ResolveRecipientsPage::ResolveRecipientsPage( QWidget * parent )
: WizardPage( parent ), d( new Private( this ) )
{
}
ResolveRecipientsPage::~ResolveRecipientsPage() {}
Protocol ResolveRecipientsPage::selectedProtocol() const
{
return d->m_selectedProtocol;
}
void ResolveRecipientsPage::Private::setSelectedProtocol( Protocol protocol )
{
if ( m_selectedProtocol == protocol )
return;
m_selectedProtocol = protocol;
m_listWidget->setProtocol( m_selectedProtocol );
emit q->selectedProtocolChanged();
}
void ResolveRecipientsPage::Private::protocolSelected( int p )
{
const Protocol protocol = static_cast<Protocol>( p );
assert( protocol != UnknownProtocol );
setSelectedProtocol( protocol );
}
void ResolveRecipientsPage::setPresetProtocol( Protocol prot )
{
if ( d->m_presetProtocol == prot )
return;
d->m_presetProtocol = prot;
d->setSelectedProtocol( prot );
if ( prot != UnknownProtocol )
d->m_multipleProtocolsAllowed = false;
d->updateProtocolRBVisibility();
}
Protocol ResolveRecipientsPage::presetProtocol() const
{
return d->m_presetProtocol;
}
bool ResolveRecipientsPage::multipleProtocolsAllowed() const
{
return d->m_multipleProtocolsAllowed;
}
void ResolveRecipientsPage::setMultipleProtocolsAllowed( bool allowed )
{
if ( d->m_multipleProtocolsAllowed == allowed )
return;
d->m_multipleProtocolsAllowed = allowed;
if ( d->m_multipleProtocolsAllowed )
{
setPresetProtocol( UnknownProtocol );
d->setSelectedProtocol( UnknownProtocol );
}
d->updateProtocolRBVisibility();
}
void ResolveRecipientsPage::Private::addRecipient( const QString& id, const QString& name )
{
m_listWidget->addEntry( id, name );
}
void ResolveRecipientsPage::Private::addRecipient( const Mailbox& mbox )
{
m_listWidget->addEntry( mbox );
}
void ResolveRecipientsPage::Private::addRecipient()
{
QPointer<CertificateSelectionDialog> dlg = createCertificateSelectionDialog( q, q->selectedProtocol() );
if ( dlg->exec() != QDialog::Accepted || !dlg /*q already deleted*/ )
return;
const std::vector<Key> keys = dlg->selectedCertificates();
int i = 0;
Q_FOREACH( const Key & key, keys ) {
const QStringList existing = m_listWidget->identifiers();
QString rec = i18n( "Recipient" );
while ( existing.contains( rec ) )
rec = i18nc( "%1 == number", "Recipient (%1)", ++i );
addRecipient( rec, rec );
const std::vector<Key> pgp = key.protocol() == OpenPGP ? std::vector<Key>( 1, key ) : std::vector<Key>();
const std::vector<Key> cms = key.protocol() == CMS ? std::vector<Key>( 1, key ) : std::vector<Key>();
m_listWidget->setCertificates( rec, pgp, cms );
}
emit q->completeChanged();
}
namespace {
std::vector<Key> makeSuggestions( const boost::shared_ptr<RecipientPreferences>& prefs, const Mailbox& mb, GpgME::Protocol prot )
{
std::vector<Key> suggestions;
const Key remembered = prefs ? prefs->preferredCertificate( mb, prot ) : Key();
if ( !remembered.isNull() )
suggestions.push_back( remembered );
else
suggestions = CertificateResolver::resolveRecipient( mb, prot );
return suggestions;
}
}
static QString listKeysForInfo( const std::vector<Key> & keys ) {
QStringList list;
std::transform( keys.begin(), keys.end(), list.begin(), &Formatting::formatKeyLink );
return list.join( QLatin1String("<br/>") );
}
void ResolveRecipientsPage::setAdditionalRecipientsInfo( const std::vector<Key> & recipients ) {
d->m_additionalRecipientsLabel->setVisible( !recipients.empty() );
if ( recipients.empty() )
return;
d->m_additionalRecipientsLabel->setText(
i18n( "<qt><p>Recipients predefined via GnuPG settings:</p>%1</qt>",
listKeysForInfo( recipients ) ) );
}
void ResolveRecipientsPage::setRecipients( const std::vector<Mailbox>& recipients, const std::vector<Mailbox> & encryptToSelfRecipients )
{
uint cmsCount = 0;
uint pgpCount = 0;
uint senders = 0;
Q_FOREACH( const Mailbox & mb, encryptToSelfRecipients ) {
const QString id = QLatin1String("sender-") + QString::number( ++senders );
d->m_listWidget->addEntry( id, i18n("Sender"), mb );
const std::vector<Key> pgp = makeSuggestions( d->m_recipientPreferences, mb, OpenPGP );
const std::vector<Key> cms = makeSuggestions( d->m_recipientPreferences, mb, CMS );
pgpCount += !pgp.empty();
cmsCount += !cms.empty();
d->m_listWidget->setCertificates( id, pgp, cms );
}
Q_FOREACH( const Mailbox& i, recipients )
{
//TODO:
const QString address = i.prettyAddress();
d->addRecipient( i );
const std::vector<Key> pgp = makeSuggestions( d->m_recipientPreferences, i, OpenPGP );
const std::vector<Key> cms = makeSuggestions( d->m_recipientPreferences, i, CMS );
pgpCount += pgp.empty() ? 0 : 1;
cmsCount += cms.empty() ? 0 : 1;
d->m_listWidget->setCertificates( address, pgp, cms );
}
if ( d->m_presetProtocol == UnknownProtocol && !d->m_multipleProtocolsAllowed )
( cmsCount > pgpCount ? d->m_cmsRB : d->m_pgpRB )->click();
}
std::vector<Key> ResolveRecipientsPage::resolvedCertificates() const
{
std::vector<Key> certs;
Q_FOREACH( const QString& i, d->m_listWidget->identifiers() )
{
const GpgME::Key cert = d->m_listWidget->selectedCertificate( i );
if ( !cert.isNull() )
certs.push_back( cert );
}
return certs;
}
void ResolveRecipientsPage::Private::selectionChanged()
{
m_removeButton->setEnabled( !m_listWidget->selectedEntries().isEmpty() );
}
void ResolveRecipientsPage::Private::removeSelectedEntries()
{
Q_FOREACH ( const QString& i, m_listWidget->selectedEntries() )
m_listWidget->removeEntry( i );
emit q->completeChanged();
}
void ResolveRecipientsPage::setRecipientsUserMutable( bool isMutable )
{
d->m_addButton->setVisible( isMutable );
d->m_removeButton->setVisible( isMutable );
}
bool ResolveRecipientsPage::recipientsUserMutable() const
{
return d->m_addButton->isVisible();
}
boost::shared_ptr<RecipientPreferences> ResolveRecipientsPage::recipientPreferences() const
{
return d->m_recipientPreferences;
}
void ResolveRecipientsPage::setRecipientPreferences( const boost::shared_ptr<RecipientPreferences>& prefs )
{
d->m_recipientPreferences = prefs;
}
void ResolveRecipientsPage::Private::writeSelectedCertificatesToPreferences()
{
if ( !m_recipientPreferences )
return;
Q_FOREACH ( const QString& i, m_listWidget->identifiers() )
{
const Mailbox mbox = m_listWidget->mailbox( i );
if ( !mbox.hasAddress() )
continue;
const Key pgp = m_listWidget->selectedCertificate( i, OpenPGP );
if ( !pgp.isNull() )
m_recipientPreferences->setPreferredCertificate( mbox, OpenPGP, pgp );
const Key cms = m_listWidget->selectedCertificate( i, CMS );
if ( !cms.isNull() )
m_recipientPreferences->setPreferredCertificate( mbox, CMS, cms );
}
}
void ResolveRecipientsPage::onNext() {
d->writeSelectedCertificatesToPreferences();
}
#include "moc_resolverecipientspage_p.cpp"
#include "moc_resolverecipientspage.cpp"
diff --git a/crypto/gui/resolverecipientspage_p.h b/crypto/gui/resolverecipientspage_p.h
index 60582ea45..6fa38dff4 100644
--- a/crypto/gui/resolverecipientspage_p.h
+++ b/crypto/gui/resolverecipientspage_p.h
@@ -1,131 +1,131 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/gui/resolverecipientspage_p.h
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2007 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#ifndef __KLEOPATRA_CRYPTO_GUI_RESOLVERECIPIENTSPAGE_P_H__
#define __KLEOPATRA_CRYPTO_GUI_RESOLVERECIPIENTSPAGE_P_H__
#include <crypto/gui/resolverecipientspage.h>
-#include <KMime/kmime_header_parsing.h>
+#include <kmime/kmime_header_parsing.h>
#include <QHash>
class QComboBox;
class QLabel;
class QListWidget;
class QListWidgetItem;
class QPushButton;
class QStringList;
class QToolButton;
class Kleo::Crypto::Gui::ResolveRecipientsPage::ListWidget : public QWidget {
Q_OBJECT
public:
explicit ListWidget( QWidget* parent = 0, Qt::WindowFlags flags = 0 );
~ListWidget();
void addEntry( const QString& id, const QString& name );
void addEntry( const KMime::Types::Mailbox& mbox );
void addEntry( const QString& id, const QString& name, const KMime::Types::Mailbox& mbox );
void removeEntry( const QString& id );
QStringList selectedEntries() const;
void setCertificates( const QString& id, const std::vector<GpgME::Key>& pgpCerts, const std::vector<GpgME::Key>& cmsCerts );
GpgME::Key selectedCertificate( const QString& id ) const;
GpgME::Key selectedCertificate( const QString& id, GpgME::Protocol prot ) const;
KMime::Types::Mailbox mailbox( const QString& id ) const;
QStringList identifiers() const;
void setProtocol( GpgME::Protocol prot );
void showSelectionDialog( const QString& id );
enum Role {
IdRole = Qt::UserRole
};
Q_SIGNALS:
void selectionChanged();
void completeChanged();
private Q_SLOTS:
void onSelectionChange();
private:
QListWidget* m_listWidget;
QHash<QString,ItemWidget*> widgets;
QHash<QString,QListWidgetItem*> items;
GpgME::Protocol m_protocol;
};
class Kleo::Crypto::Gui::ResolveRecipientsPage::ItemWidget : public QWidget {
Q_OBJECT
public:
explicit ItemWidget( const QString& id, const QString& name, const KMime::Types::Mailbox& mbox, QWidget* parent = 0, Qt::WindowFlags flags = 0 );
~ItemWidget();
QString id() const;
KMime::Types::Mailbox mailbox() const;
void setCertificates( const std::vector<GpgME::Key>& pgp,
const std::vector<GpgME::Key>& cms );
GpgME::Key selectedCertificate() const;
GpgME::Key selectedCertificate( GpgME::Protocol prot ) const;
std::vector<GpgME::Key> certificates() const;
void setProtocol( GpgME::Protocol protocol );
void setSelected( bool selected );
bool isSelected() const;
public Q_SLOTS:
void showSelectionDialog();
Q_SIGNALS:
void changed();
private:
void addCertificateToComboBox( const GpgME::Key& key );
void resetCertificates();
void selectCertificateInComboBox( const GpgME::Key& key );
void updateVisibility();
private:
QString m_id;
KMime::Types::Mailbox m_mailbox;
QLabel* m_nameLabel;
QLabel* m_certLabel;
QComboBox* m_certCombo;
QToolButton* m_selectButton;
GpgME::Protocol m_protocol;
QHash<GpgME::Protocol, GpgME::Key> m_selectedCertificates;
std::vector<GpgME::Key> m_pgp, m_cms;
bool m_selected;
};
#endif // __KLEOPATRA_CRYPTO_GUI_RESOLVERECIPIENTSPAGE_P_H__
diff --git a/crypto/gui/signencryptemailconflictdialog.cpp b/crypto/gui/signencryptemailconflictdialog.cpp
index 2c55905a9..a3d9b3187 100644
--- a/crypto/gui/signencryptemailconflictdialog.cpp
+++ b/crypto/gui/signencryptemailconflictdialog.cpp
@@ -1,814 +1,814 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/gui/signencryptemailconflictdialog.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2009 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include <config-kleopatra.h>
#include "signencryptemailconflictdialog.h"
#include <crypto/sender.h>
#include <crypto/recipient.h>
#include <dialogs/certificateselectiondialog.h>
#include <models/predicates.h>
#include <utils/gui-helper.h>
#include <utils/formatting.h>
#include <utils/kleo_assert.h>
#include <utils/kdsignalblocker.h>
#include <kleo/stl_util.h>
#include <gpgme++/key.h>
-#include <KMime/kmime_header_parsing.h>
+#include <kmime/kmime_header_parsing.h>
#include <KLocalizedString>
#include <QLabel>
#include <QComboBox>
#include <QLayout>
#include <QStackedWidget>
#include <QToolButton>
#include <QGroupBox>
#include <QDialogButtonBox>
#include <QCheckBox>
#include <QRadioButton>
#include <QPushButton>
#include <QStylePainter>
#include <QStyle>
#include <QPointer>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <iterator>
using namespace Kleo;
using namespace Kleo::Crypto;
using namespace Kleo::Crypto::Gui;
using namespace Kleo::Dialogs;
using namespace GpgME;
using namespace boost;
Q_DECLARE_METATYPE( GpgME::Key )
Q_DECLARE_METATYPE( GpgME::UserID )
namespace {
// A QComboBox with an initial text (as known from web browsers)
//
// only works with read-only QComboBoxen, doesn't affect sizeHint
// as it should...
//
class ComboBox : public QComboBox {
Q_OBJECT
Q_PROPERTY( QString initialText READ initialText WRITE setInitialText )
Q_PROPERTY( QIcon initialIcon READ initialIcon WRITE setInitialIcon )
public:
explicit ComboBox( QWidget * parent=0 )
: QComboBox( parent ),
m_initialText(),
m_initialIcon()
{
}
explicit ComboBox( const QString & initialText, QWidget * parent=0 )
: QComboBox( parent ),
m_initialText( initialText ),
m_initialIcon()
{
}
explicit ComboBox( const QIcon & initialIcon, const QString & initialText, QWidget * parent=0 )
: QComboBox( parent ),
m_initialText( initialText ),
m_initialIcon( initialIcon )
{
}
QString initialText() const { return m_initialText; }
QIcon initialIcon() const { return m_initialIcon; }
public Q_SLOTS:
void setInitialText( const QString & txt ) {
if ( txt == m_initialText )
return;
m_initialText = txt;
if ( currentIndex() == -1 )
update();
}
void setInitialIcon( const QIcon & icon ) {
if ( icon.cacheKey() == m_initialIcon.cacheKey() )
return;
m_initialIcon = icon;
if ( currentIndex() == -1 )
update();
}
protected:
void paintEvent( QPaintEvent * ) {
QStylePainter p( this );
p.setPen( palette().color( QPalette::Text ) );
QStyleOptionComboBox opt;
initStyleOption( &opt );
p.drawComplexControl( QStyle::CC_ComboBox, opt );
if ( currentIndex() == -1 ) {
opt.currentText = m_initialText;
opt.currentIcon = m_initialIcon;
}
p.drawControl( QStyle::CE_ComboBoxLabel, opt );
}
private:
QString m_initialText;
QIcon m_initialIcon;
};
static QString make_initial_text( const std::vector<Key> & keys ) {
if ( keys.empty() )
return i18n("(no matching certificates found)");
else
return i18n("Please select a certificate");
}
class KeysComboBox : public ComboBox {
Q_OBJECT
public:
explicit KeysComboBox( QWidget * parent=0 )
: ComboBox( parent ) {}
explicit KeysComboBox( const QString & initialText, QWidget * parent=0 )
: ComboBox( initialText, parent ) {}
explicit KeysComboBox( const std::vector<Key> & keys, QWidget * parent=0 )
: ComboBox( make_initial_text( keys ), parent ) { setKeys( keys ); }
void setKeys( const std::vector<Key> & keys ) {
clear();
Q_FOREACH( const Key & key, keys )
addItem( Formatting::formatForComboBox( key ), qVariantFromValue( key ) );
}
std::vector<Key> keys() const {
std::vector<Key> result;
result.reserve( count() );
for ( int i = 0, end = count() ; i != end ; ++i )
result.push_back( qvariant_cast<Key>( itemData(i) ) );
return result;;
}
int findOrAdd( const Key & key ) {
for ( int i = 0, end = count() ; i != end ; ++i )
if ( _detail::ByFingerprint<std::equal_to>()( key, qvariant_cast<Key>( itemData(i) ) ) )
return i;
insertItem( 0, Formatting::formatForComboBox( key ), qVariantFromValue( key ) );
return 0;
}
void addAndSelectCertificate( const Key & key ) {
setCurrentIndex( findOrAdd( key ) );
}
Key currentKey() const {
return qvariant_cast<Key>( itemData( currentIndex() ) );
}
};
class Line {
public:
static const unsigned int NumColumns = 4;
Line( const QString & toFrom, const QString & mailbox, const std::vector<Key> & pgp, bool pgpAmbig, const std::vector<Key> & cms, bool cmsAmbig, QWidget * q, QGridLayout & glay )
: pgpAmbiguous( pgpAmbig ),
cmsAmbiguous( cmsAmbig ),
toFromLB( new QLabel( toFrom, q ) ),
mailboxLB( new QLabel( mailbox, q ) ),
sbox( new QStackedWidget( q ) ),
pgpCB( new KeysComboBox( pgp, sbox ) ),
cmsCB( new KeysComboBox( cms, sbox ) ),
noProtocolCB( new KeysComboBox( i18n("(please choose between OpenPGP and S/MIME first)"), sbox ) ),
toolTB( new QToolButton( q ) )
{
KDAB_SET_OBJECT_NAME( toFromLB );
KDAB_SET_OBJECT_NAME( mailboxLB );
KDAB_SET_OBJECT_NAME( noProtocolCB );
KDAB_SET_OBJECT_NAME( pgpCB );
KDAB_SET_OBJECT_NAME( cmsCB );
KDAB_SET_OBJECT_NAME( sbox );
KDAB_SET_OBJECT_NAME( toolTB );
QFont bold;
bold.setBold( true );
toFromLB->setFont( bold );
mailboxLB->setTextFormat( Qt::PlainText );
toolTB->setText( i18n("...") );
pgpCB->setEnabled( !pgp.empty() );
cmsCB->setEnabled( !cms.empty() );
noProtocolCB->setEnabled( false );
pgpCB->setKeys( pgp );
if ( pgpAmbiguous )
pgpCB->setCurrentIndex( -1 );
cmsCB->setKeys( cms );
if ( cmsAmbiguous )
cmsCB->setCurrentIndex( -1 );
sbox->addWidget( pgpCB );
sbox->addWidget( cmsCB );
sbox->addWidget( noProtocolCB );
sbox->setCurrentWidget( noProtocolCB );
const int row = glay.rowCount();
unsigned int col = 0;
glay.addWidget( toFromLB, row, col++ );
glay.addWidget( mailboxLB, row, col++ );
glay.addWidget( sbox, row, col++ );
glay.addWidget( toolTB, row, col++ );
assert( col == NumColumns );
q->connect( pgpCB, SIGNAL(currentIndexChanged(int)), SLOT(slotCompleteChanged()) );
q->connect( cmsCB, SIGNAL(currentIndexChanged(int)), SLOT(slotCompleteChanged()) );
q->connect( toolTB, SIGNAL(clicked()), SLOT(slotCertificateSelectionDialogRequested()) );
}
KeysComboBox * comboBox( Protocol proto ) const {
if ( proto == OpenPGP )
return pgpCB;
if ( proto == CMS )
return cmsCB;
return 0;
}
QString mailboxText() const {
return mailboxLB->text();
}
void addAndSelectCertificate( const Key & key ) const {
if ( KeysComboBox * const cb = comboBox( key.protocol() ) ) {
cb->addAndSelectCertificate( key );
cb->setEnabled( true );
}
}
void showHide( Protocol proto, bool & first, bool showAll, bool op ) const {
if ( op && ( showAll || wasInitiallyAmbiguous( proto ) ) ) {
toFromLB->setVisible( first );
first = false;
QFont font = mailboxLB->font();
font.setBold( wasInitiallyAmbiguous( proto ) );
mailboxLB->setFont( font );
sbox->setCurrentIndex( proto );
mailboxLB->show();
sbox->show();
toolTB->show();
} else {
toFromLB->hide();
mailboxLB->hide();
sbox->hide();
toolTB->hide();
}
}
bool wasInitiallyAmbiguous( Protocol proto ) const {
return proto == OpenPGP && pgpAmbiguous
|| proto == CMS && cmsAmbiguous ;
}
bool isStillAmbiguous( Protocol proto ) const {
kleo_assert( proto == OpenPGP || proto == CMS );
const KeysComboBox * const cb = comboBox( proto );
return cb->currentIndex() == -1 ;
}
Key key( Protocol proto ) const {
kleo_assert( proto == OpenPGP || proto == CMS );
const KeysComboBox * const cb = comboBox( proto );
return cb->currentKey();
}
const QToolButton * toolButton() const { return toolTB; }
void kill() {
delete toFromLB;
delete mailboxLB;
delete sbox;
delete toolTB;
}
private:
bool pgpAmbiguous : 1;
bool cmsAmbiguous : 1;
QLabel * toFromLB;
QLabel * mailboxLB;
QStackedWidget * sbox;
KeysComboBox * pgpCB;
KeysComboBox * cmsCB;
KeysComboBox * noProtocolCB;
QToolButton * toolTB;
};
}
static CertificateSelectionDialog *
create_certificate_selection_dialog( QWidget * parent, Protocol proto ) {
CertificateSelectionDialog * const dlg = new CertificateSelectionDialog( parent );
dlg->setOptions( proto == OpenPGP ? CertificateSelectionDialog::OpenPGPFormat :
proto == CMS ? CertificateSelectionDialog::CMSFormat : CertificateSelectionDialog::AnyFormat );
return dlg;
}
static CertificateSelectionDialog *
create_encryption_certificate_selection_dialog( QWidget * parent, Protocol proto, const QString & mailbox ) {
CertificateSelectionDialog * const dlg = create_certificate_selection_dialog( parent, proto );
dlg->setCustomLabelText( i18n("Please select an encryption certificate for recipient \"%1\"", mailbox ) );
dlg->setOptions( CertificateSelectionDialog::SingleSelection |
CertificateSelectionDialog::EncryptOnly |
dlg->options() );
return dlg;
}
static CertificateSelectionDialog *
create_signing_certificate_selection_dialog( QWidget * parent, Protocol proto, const QString & mailbox ) {
CertificateSelectionDialog * const dlg = create_certificate_selection_dialog( parent, proto );
dlg->setCustomLabelText( i18n("Please select a signing certificate for sender \"%1\"", mailbox ) );
dlg->setOptions( CertificateSelectionDialog::SingleSelection |
CertificateSelectionDialog::SignOnly |
CertificateSelectionDialog::SecretKeys |
dlg->options() );
return dlg;
}
static QString make_top_label_conflict_text( bool sign, bool enc ) {
return
sign && enc ? i18n("Kleopatra cannot unambiguously determine matching certificates "
"for all recipients/senders of the message.\n"
"Please select the correct certificates for each recipient:") :
sign ? i18n("Kleopatra cannot unambiguously determine matching certificates "
"for the sender of the message.\n"
"Please select the correct certificates for the sender:") :
enc ? i18n("Kleopatra cannot unambiguously determine matching certificates "
"for all recipients of the message.\n"
"Please select the correct certificates for each recipient:" ) :
/* else */ (kleo_assert_fail( sign || enc ),QString()) ;
}
static QString make_top_label_quickmode_text( bool sign, bool enc ) {
return
enc ? i18n("Please verify that correct certificates have been selected for each recipient:") :
sign ? i18n("Please verify that the correct certificate has been selected for the sender:") :
/*else*/ (kleo_assert_fail( sign || enc ),QString()) ;
}
class SignEncryptEMailConflictDialog::Private {
friend class ::Kleo::Crypto::Gui::SignEncryptEMailConflictDialog;
SignEncryptEMailConflictDialog * const q;
public:
explicit Private( SignEncryptEMailConflictDialog * qq )
: q( qq ),
senders(),
recipients(),
sign( true ),
encrypt( true ),
presetProtocol( UnknownProtocol ),
ui( q )
{
}
private:
void updateTopLabelText() {
ui.conflictTopLB.setText( make_top_label_conflict_text( sign, encrypt ) );
ui.quickModeTopLB.setText( make_top_label_quickmode_text( sign, encrypt ) );
}
void showHideWidgets() {
const Protocol proto = q->selectedProtocol();
const bool quickMode = q->isQuickMode();
const bool needProtocolSelection = presetProtocol == UnknownProtocol ;
const bool needShowAllRecipientsCB =
quickMode ? false :
needProtocolSelection ? needShowAllRecipients( OpenPGP ) || needShowAllRecipients( CMS ) :
/* else */ needShowAllRecipients( proto )
;
ui.showAllRecipientsCB.setVisible( needShowAllRecipientsCB );
ui.pgpRB.setVisible( needProtocolSelection );
ui.cmsRB.setVisible( needProtocolSelection );
const bool showAll = !needShowAllRecipientsCB || ui.showAllRecipientsCB.isChecked();
bool first;
first = true;
Q_FOREACH( const Line & line, ui.signers )
line.showHide( proto, first, showAll, sign );
ui.selectSigningCertificatesGB.setVisible( sign && ( showAll || !first ) );
first = true;
Q_FOREACH( const Line & line, ui.recipients )
line.showHide( proto, first, showAll, encrypt );
ui.selectEncryptionCertificatesGB.setVisible( encrypt && ( showAll || !first ) );
}
bool needShowAllRecipients( Protocol proto ) const {
if ( sign )
if ( const unsigned int num = kdtools::count_if( ui.signers, boost::bind( &Line::wasInitiallyAmbiguous, _1, proto ) ) )
if ( num != ui.signers.size() )
return true;
if ( encrypt )
if ( const unsigned int num = kdtools::count_if( ui.recipients, boost::bind( &Line::wasInitiallyAmbiguous, _1, proto ) ) )
if ( num != ui.recipients.size() )
return true;
return false;
}
void createSendersAndRecipients() {
ui.clearSendersAndRecipients();
ui.addSelectSigningCertificatesGB();
Q_FOREACH( const Sender & s, senders )
addSigner( s );
ui.addSelectEncryptionCertificatesGB();
Q_FOREACH( const Sender & s, senders )
addRecipient( s );
Q_FOREACH( const Recipient & r, recipients )
addRecipient( r );
}
void addSigner( const Sender & s ) {
ui.addSigner( s.mailbox().prettyAddress(),
s.signingCertificateCandidates( OpenPGP ),
s.isSigningAmbiguous( OpenPGP ),
s.signingCertificateCandidates( CMS ),
s.isSigningAmbiguous( CMS ),
q );
}
void addRecipient( const Sender & s ) {
ui.addRecipient( s.mailbox().prettyAddress(),
s.encryptToSelfCertificateCandidates( OpenPGP ),
s.isEncryptionAmbiguous( OpenPGP ),
s.encryptToSelfCertificateCandidates( CMS ),
s.isEncryptionAmbiguous( CMS ),
q );
}
void addRecipient( const Recipient & r ) {
ui.addRecipient( r.mailbox().prettyAddress(),
r.encryptionCertificateCandidates( OpenPGP ),
r.isEncryptionAmbiguous( OpenPGP ),
r.encryptionCertificateCandidates( CMS ),
r.isEncryptionAmbiguous( CMS ),
q );
}
bool isComplete( Protocol proto ) const;
private:
void enableDisableOkButton() {
ui.setOkButtonEnabled( q->isComplete() );
}
void slotCompleteChanged() {
enableDisableOkButton();
}
void slotShowAllRecipientsToggled( bool ) {
showHideWidgets();
}
void slotProtocolChanged() {
showHideWidgets();
enableDisableOkButton();
}
void slotCertificateSelectionDialogRequested() {
const QObject * const s = q->sender();
const Protocol proto = q->selectedProtocol();
QPointer<CertificateSelectionDialog> dlg;
Q_FOREACH( const Line & l, ui.signers )
if ( s == l.toolButton() ) {
dlg = create_signing_certificate_selection_dialog( q, proto, l.mailboxText() );
if ( dlg->exec() )
l.addAndSelectCertificate( dlg->selectedCertificate() );
// ### switch to key.protocol(), in case proto == UnknownProtocol
break;
}
Q_FOREACH( const Line & l, ui.recipients )
if ( s == l.toolButton() ) {
dlg = create_encryption_certificate_selection_dialog( q, proto, l.mailboxText() );
if ( dlg->exec() )
l.addAndSelectCertificate( dlg->selectedCertificate() );
// ### switch to key.protocol(), in case proto == UnknownProtocol
break;
}
delete dlg;
}
private:
std::vector<Sender> senders;
std::vector<Recipient> recipients;
bool sign : 1;
bool encrypt : 1;
Protocol presetProtocol;
private:
struct Ui {
QLabel conflictTopLB, quickModeTopLB;
QCheckBox showAllRecipientsCB;
QRadioButton pgpRB, cmsRB;
QGroupBox selectSigningCertificatesGB;
QGroupBox selectEncryptionCertificatesGB;
QCheckBox quickModeCB;
QDialogButtonBox buttonBox;
QVBoxLayout vlay;
QHBoxLayout hlay;
QGridLayout glay;
std::vector<Line> signers, recipients;
void setOkButtonEnabled( bool enable ) {
return buttonBox.button( QDialogButtonBox::Ok )->setEnabled( enable );
}
explicit Ui( SignEncryptEMailConflictDialog * q )
: conflictTopLB( make_top_label_conflict_text( true, true ), q ),
quickModeTopLB( make_top_label_quickmode_text( true, true ), q ),
showAllRecipientsCB( i18n("Show all recipients"), q ),
pgpRB( i18n("OpenPGP"), q ),
cmsRB( i18n("S/MIME"), q ),
selectSigningCertificatesGB( i18n("Select Signing Certificate"), q ),
selectEncryptionCertificatesGB( i18n("Select Encryption Certificate"), q ),
quickModeCB( i18n("Only show this dialog in case of conflicts (experimental)"), q ),
buttonBox( QDialogButtonBox::Ok|QDialogButtonBox::Cancel, Qt::Horizontal, q ),
vlay( q ),
hlay(),
glay(),
signers(),
recipients()
{
KDAB_SET_OBJECT_NAME( conflictTopLB );
KDAB_SET_OBJECT_NAME( quickModeTopLB );
KDAB_SET_OBJECT_NAME( showAllRecipientsCB );
KDAB_SET_OBJECT_NAME( pgpRB );
KDAB_SET_OBJECT_NAME( cmsRB );
KDAB_SET_OBJECT_NAME( selectSigningCertificatesGB );
KDAB_SET_OBJECT_NAME( selectEncryptionCertificatesGB );
KDAB_SET_OBJECT_NAME( quickModeCB );
KDAB_SET_OBJECT_NAME( buttonBox );
KDAB_SET_OBJECT_NAME( hlay );
KDAB_SET_OBJECT_NAME( glay );
KDAB_SET_OBJECT_NAME( vlay );
q->setWindowTitle( i18n("Select Certificates For Message") );
conflictTopLB.hide();
selectSigningCertificatesGB.setFlat( true );
selectEncryptionCertificatesGB.setFlat( true );
selectSigningCertificatesGB.setAlignment( Qt::AlignCenter );
selectEncryptionCertificatesGB.setAlignment( Qt::AlignCenter );
glay.setColumnStretch( 2, 1 );
glay.setColumnStretch( 3, 1 );
vlay.setSizeConstraint( QLayout::SetMinimumSize );
vlay.addWidget( &conflictTopLB );
vlay.addWidget( &quickModeTopLB );
hlay.addWidget( &showAllRecipientsCB );
hlay.addStretch( 1 );
hlay.addWidget( &pgpRB );
hlay.addWidget( &cmsRB );
vlay.addLayout( &hlay );
addSelectSigningCertificatesGB();
addSelectEncryptionCertificatesGB();
vlay.addLayout( &glay );
vlay.addStretch( 1 );
vlay.addWidget( &quickModeCB, 0, Qt::AlignCenter );
vlay.addWidget( &buttonBox );
connect( &buttonBox, SIGNAL(accepted()), q, SLOT(accept()) );
connect( &buttonBox, SIGNAL(rejected()), q, SLOT(reject()) );
connect( &showAllRecipientsCB, SIGNAL(toggled(bool)),
q, SLOT(slotShowAllRecipientsToggled(bool)) );
connect( &pgpRB, SIGNAL(toggled(bool)),
q, SLOT(slotProtocolChanged()) );
connect( &cmsRB, SIGNAL(toggled(bool)),
q, SLOT(slotProtocolChanged()) );
}
void clearSendersAndRecipients() {
std::vector<Line> sig, enc;
sig.swap( signers );
enc.swap( recipients );
kdtools::for_each( sig, mem_fn( &Line::kill ) );
kdtools::for_each( enc, mem_fn( &Line::kill ) );
glay.removeWidget( &selectSigningCertificatesGB );
glay.removeWidget( &selectEncryptionCertificatesGB );
}
void addSelectSigningCertificatesGB() {
glay.addWidget( &selectSigningCertificatesGB, glay.rowCount(), 0, 1, Line::NumColumns );
}
void addSelectEncryptionCertificatesGB() {
glay.addWidget( &selectEncryptionCertificatesGB, glay.rowCount(), 0, 1, Line::NumColumns );
}
void addSigner( const QString & mailbox,
const std::vector<Key> & pgp, bool pgpAmbiguous,
const std::vector<Key> & cms, bool cmsAmbiguous, QWidget * q )
{
Line line( i18n("From:"), mailbox, pgp, pgpAmbiguous, cms, cmsAmbiguous, q, glay );
signers.push_back( line );
}
void addRecipient( const QString & mailbox,
const std::vector<Key> & pgp, bool pgpAmbiguous,
const std::vector<Key> & cms, bool cmsAmbiguous, QWidget * q )
{
Line line( i18n("To:"), mailbox, pgp, pgpAmbiguous, cms, cmsAmbiguous, q, glay );
recipients.push_back( line );
}
} ui;
};
SignEncryptEMailConflictDialog::SignEncryptEMailConflictDialog( QWidget * parent, Qt::WindowFlags f )
: QDialog( parent, f ), d( new Private( this ) )
{
}
SignEncryptEMailConflictDialog::~SignEncryptEMailConflictDialog() {}
void SignEncryptEMailConflictDialog::setPresetProtocol( Protocol p ) {
if ( p == d->presetProtocol )
return;
const KDSignalBlocker pgpBlocker( d->ui.pgpRB );
const KDSignalBlocker cmsBlocker( d->ui.cmsRB );
really_check( d->ui.pgpRB, p == OpenPGP );
really_check( d->ui.cmsRB, p == CMS );
d->presetProtocol = p;
d->showHideWidgets();
d->enableDisableOkButton();
}
Protocol SignEncryptEMailConflictDialog::selectedProtocol() const {
if ( d->presetProtocol != UnknownProtocol )
return d->presetProtocol;
if ( d->ui.pgpRB.isChecked() )
return OpenPGP;
if ( d->ui.cmsRB.isChecked() )
return CMS;
return UnknownProtocol;
}
void SignEncryptEMailConflictDialog::setSubject( const QString & subject ) {
setWindowTitle( i18n("Select Certificates For Message \"%1\"", subject ) );
}
void SignEncryptEMailConflictDialog::setSign( bool sign ) {
if ( sign == d->sign )
return;
d->sign = sign;
d->updateTopLabelText();
d->showHideWidgets();
d->enableDisableOkButton();
}
void SignEncryptEMailConflictDialog::setEncrypt( bool encrypt ) {
if ( encrypt == d->encrypt )
return;
d->encrypt = encrypt;
d->updateTopLabelText();
d->showHideWidgets();
d->enableDisableOkButton();
}
void SignEncryptEMailConflictDialog::setSenders( const std::vector<Sender> & senders ) {
if ( senders == d->senders )
return;
d->senders = senders;
d->createSendersAndRecipients();
d->showHideWidgets();
d->enableDisableOkButton();
}
void SignEncryptEMailConflictDialog::setRecipients( const std::vector<Recipient> & recipients ) {
if ( d->recipients == recipients )
return;
d->recipients = recipients;
d->createSendersAndRecipients();
d->showHideWidgets();
d->enableDisableOkButton();
}
void SignEncryptEMailConflictDialog::pickProtocol() {
if ( selectedProtocol() != UnknownProtocol )
return; // already picked
const bool pgp = d->isComplete( OpenPGP );
const bool cms = d->isComplete( CMS );
if ( pgp && !cms )
d->ui.pgpRB.setChecked( true );
else if ( cms && !pgp )
d->ui.cmsRB.setChecked( true );
}
bool SignEncryptEMailConflictDialog::isComplete() const {
const Protocol proto = selectedProtocol();
return proto != UnknownProtocol && d->isComplete( proto ) ;
}
bool SignEncryptEMailConflictDialog::Private::isComplete( Protocol proto ) const {
return ( !sign || kdtools::none_of( ui.signers, boost::bind( &Line::isStillAmbiguous, _1, proto ) ) )
&& ( !encrypt || kdtools::none_of( ui.recipients, boost::bind( &Line::isStillAmbiguous, _1, proto ) ) )
;
}
static std::vector<Key> get_keys( const std::vector<Line> & lines, Protocol proto ) {
if ( proto == UnknownProtocol )
return std::vector<Key>();
assert( proto == OpenPGP || proto == CMS );
std::vector<Key> keys;
keys.reserve( lines.size() );
kdtools::transform( lines, std::back_inserter( keys ),
boost::bind( &Line::key, _1, proto ) );
kleo_assert( kdtools::none_of( keys, mem_fn( &Key::isNull ) ) );
return keys;
}
std::vector<Key> SignEncryptEMailConflictDialog::resolvedSigningKeys() const {
return d->sign ? get_keys( d->ui.signers, selectedProtocol() ) : std::vector<Key>() ;
}
std::vector<Key> SignEncryptEMailConflictDialog::resolvedEncryptionKeys() const {
return d->encrypt ? get_keys( d->ui.recipients, selectedProtocol() ) : std::vector<Key>() ;
}
void SignEncryptEMailConflictDialog::setQuickMode( bool on ) {
d->ui.quickModeCB.setChecked( on );
}
bool SignEncryptEMailConflictDialog::isQuickMode() const {
return d->ui.quickModeCB.isChecked();
}
void SignEncryptEMailConflictDialog::setConflict( bool conflict ) {
d->ui.conflictTopLB.setVisible( conflict );
d->ui.quickModeTopLB.setVisible( !conflict );
}
#include "moc_signencryptemailconflictdialog.cpp"
#include "signencryptemailconflictdialog.moc"
diff --git a/crypto/gui/signencryptwizard.h b/crypto/gui/signencryptwizard.h
index 9f0e0a571..d5475b363 100644
--- a/crypto/gui/signencryptwizard.h
+++ b/crypto/gui/signencryptwizard.h
@@ -1,163 +1,163 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/gui/signencryptwizard.h
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2007 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#ifndef __KLEOPATRA_CRYPTO_GUI_SIGNENCRYPTWIZARD_H__
#define __KLEOPATRA_CRYPTO_GUI_SIGNENCRYPTWIZARD_H__
#include <crypto/gui/wizard.h>
#include <crypto/gui/signerresolvepage.h>
#include <utils/pimpl_ptr.h>
#include <gpgme++/global.h>
-#include <KMime/kmime_header_parsing.h>
+#include <kmime/kmime_header_parsing.h>
#include <boost/shared_ptr.hpp>
#include <vector>
namespace GpgME {
class Key;
}
class QFileInfo;
template <typename T> class QList;
typedef QList<QFileInfo> QFileInfoList;
namespace Kleo {
namespace Crypto {
class Task;
class TaskCollection;
namespace Gui {
class ObjectsPage;
class ResolveRecipientsPage;
class ResultPage;
class SignerResolvePage;
class SignEncryptWizard : public Wizard {
Q_OBJECT
public:
explicit SignEncryptWizard( QWidget * parent=0, Qt::WindowFlags f=0 );
virtual ~SignEncryptWizard();
enum Page {
ResolveSignerPage=0,
ObjectsPage,
ResolveRecipientsPage,
ResultPage
};
void setCommitPage( Page );
GpgME::Protocol presetProtocol() const;
void setPresetProtocol( GpgME::Protocol proto );
GpgME::Protocol selectedProtocol() const;
/// SignOrEncryptFiles mode subinterface
//@{
QFileInfoList resolvedFiles() const;
void setFiles( const QStringList & files );
bool signingSelected() const;
void setSigningSelected( bool selected );
bool encryptionSelected() const;
void setEncryptionSelected( bool selected );
bool isSigningUserMutable() const;
void setSigningUserMutable( bool isMutable );
bool isEncryptionUserMutable() const;
void setEncryptionUserMutable( bool isMutable );
bool isMultipleProtocolsAllowed() const;
void setMultipleProtocolsAllowed( bool allowed );
//@}
void setRecipients( const std::vector<KMime::Types::Mailbox> & recipients, const std::vector<KMime::Types::Mailbox> & encryptoToSelfRecipients );
/** if true, the user is allowed to remove/add recipients via the UI.
* Defaults to @p false.
*/
bool recipientsUserMutable() const;
void setRecipientsUserMutable( bool isMutable );
void setSignersAndCandidates( const std::vector<KMime::Types::Mailbox> & signers, const std::vector< std::vector<GpgME::Key> > & keys );
void setTaskCollection( const boost::shared_ptr<TaskCollection> & tasks );
std::vector<GpgME::Key> resolvedCertificates() const;
std::vector<GpgME::Key> resolvedSigners() const;
bool isAsciiArmorEnabled() const;
void setAsciiArmorEnabled( bool enabled );
bool removeUnencryptedFile() const;
void setRemoveUnencryptedFile( bool remove );
bool keepResultPageOpenWhenDone() const;
void setKeepResultPageOpenWhenDone( bool keep );
/*reimp*/ void onNext( int currentId );
Q_SIGNALS:
void signersResolved();
void objectsResolved();
void recipientsResolved();
void linkActivated( const QString & link );
protected:
Gui::SignerResolvePage* signerResolvePage();
const Gui::SignerResolvePage* signerResolvePage() const;
Gui::ObjectsPage* objectsPage();
Gui::ResultPage* resultPage();
Gui::ResolveRecipientsPage* resolveRecipientsPage();
void setSignerResolvePageValidator( const boost::shared_ptr<SignerResolvePage::Validator>& validator );
private:
class Private;
kdtools::pimpl_ptr<Private> d;
};
}
}
}
#endif /* __KLEOPATRA_CRYPTO_GUI_SIGNENCRYPTWIZARD_H__ */
diff --git a/crypto/gui/signerresolvepage.cpp b/crypto/gui/signerresolvepage.cpp
index 6159ff4cb..5e3202531 100644
--- a/crypto/gui/signerresolvepage.cpp
+++ b/crypto/gui/signerresolvepage.cpp
@@ -1,670 +1,670 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/gui/signerresolvepage.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2007 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#if !defined(QT_STL)
#define QT_STL
#endif
#include <config-kleopatra.h>
#include "signerresolvepage.h"
#include "signerresolvepage_p.h"
#include "signingcertificateselectiondialog.h"
#include <crypto/certificateresolver.h>
#include <models/keycache.h>
#include <utils/formatting.h>
#include <utils/kleo_assert.h>
-#include <KMime/kmime_header_parsing.h>
+#include <kmime/kmime_header_parsing.h>
#include <gpgme++/key.h>
#include <KDialog>
#include <KLocalizedString>
#include <QButtonGroup>
#include <QCheckBox>
#include <QGridLayout>
#include <QGroupBox>
#include <QLabel>
#include <QPointer>
#include <QPushButton>
#include <QRadioButton>
#include <QVBoxLayout>
#include <QVector>
#include <cassert>
using namespace GpgME;
using namespace Kleo;
using namespace Kleo::Crypto;
using namespace Kleo::Crypto::Gui;
using namespace boost;
namespace {
static SignerResolvePage::Operation operationFromFlags( bool sign, bool encrypt ) {
if ( !encrypt && sign )
return SignerResolvePage::SignOnly;
if ( !sign && encrypt )
return SignerResolvePage::EncryptOnly;
return SignerResolvePage::SignAndEncrypt;
}
static QString formatLabel( Protocol p, const Key & key ) {
return i18nc( "%1=protocol (S/Mime, OpenPGP), %2=certificate", "Sign using %1: %2", Formatting::displayName( p ),
!key.isNull() ? Formatting::formatForComboBox( key ) : i18n( "No certificate selected" ) );
}
static std::vector<Protocol> supportedProtocols() {
std::vector<Protocol> protocols;
protocols.push_back( OpenPGP );
protocols.push_back( CMS );
return protocols;
}
}
AbstractSigningProtocolSelectionWidget::AbstractSigningProtocolSelectionWidget( QWidget* p, Qt::WindowFlags f ) : QWidget( p, f ) {
}
ReadOnlyProtocolSelectionWidget::ReadOnlyProtocolSelectionWidget( QWidget* p, Qt::WindowFlags f ) : AbstractSigningProtocolSelectionWidget( p, f ) {
QVBoxLayout * const layout = new QVBoxLayout( this );
layout->setMargin( 0 );
Q_FOREACH ( const Protocol i, supportedProtocols() ) { //krazy:exclude=foreach
QLabel * const l = new QLabel;
l->setText( formatLabel( i, Key() ) );
layout->addWidget( l );
m_labels[i] = l;
}
}
void ReadOnlyProtocolSelectionWidget::setProtocolChecked( Protocol protocol, bool checked ) {
QLabel * const l = label( protocol );
assert( l );
l->setVisible( checked );
}
bool ReadOnlyProtocolSelectionWidget::isProtocolChecked( Protocol protocol ) const {
QLabel * const l = label( protocol );
assert( l );
return l->isVisible();
}
std::vector<Protocol> ReadOnlyProtocolSelectionWidget::checkedProtocols() const {
std::vector<Protocol> res;
Q_FOREACH( const Protocol i, supportedProtocols() ) //krazy:exclude=foreach
if( isProtocolChecked( i ) )
res.push_back( i );
return res;
}
SigningProtocolSelectionWidget::SigningProtocolSelectionWidget( QWidget* parent, Qt::WindowFlags f )
: AbstractSigningProtocolSelectionWidget( parent, f ) {
m_buttonGroup = new QButtonGroup( this );
connect( m_buttonGroup, SIGNAL(buttonClicked(int)), this, SIGNAL(userSelectionChanged()) );
QVBoxLayout * const layout = new QVBoxLayout( this );
layout->setMargin( 0 );
Q_FOREACH ( const Protocol i, supportedProtocols() ) { //krazy:exclude=foreach
QCheckBox * const b = new QCheckBox;
b->setText( formatLabel( i, Key() ) );
m_buttons[i] = b;
layout->addWidget( b );
m_buttonGroup->addButton( b );
}
setExclusive( true );
}
void SigningProtocolSelectionWidget::setProtocolChecked( Protocol p, bool checked ) {
assert( p != UnknownProtocol );
QCheckBox * const b = button( p );
assert( b );
b->setChecked( checked );
}
bool SigningProtocolSelectionWidget::isProtocolChecked( Protocol p ) const {
assert( p != UnknownProtocol );
const QAbstractButton * const b = button( p );
assert( b );
return b->isChecked();
}
std::vector<Protocol> SigningProtocolSelectionWidget::checkedProtocols() const {
std::vector<Protocol> res;
for ( std::map<Protocol,QCheckBox*>::const_iterator it = m_buttons.begin(), end = m_buttons.end();
it != end;
++it )
if ( it->second->isChecked() )
res.push_back( it->first );
return res;
}
void SigningProtocolSelectionWidget::setExclusive( bool exclusive ) {
if ( exclusive == isExclusive() )
return;
m_buttonGroup->setExclusive( exclusive );
emit userSelectionChanged();
}
QCheckBox * SigningProtocolSelectionWidget::button( Protocol p ) const
{
const std::map<Protocol,QCheckBox*>::const_iterator it = m_buttons.find( p );
return it == m_buttons.end() ? 0 : it->second;
}
QLabel * ReadOnlyProtocolSelectionWidget::label( Protocol p ) const
{
const std::map<Protocol,QLabel*>::const_iterator it = m_labels.find( p );
return it == m_labels.end() ? 0 : it->second;
}
bool SigningProtocolSelectionWidget::isExclusive() const {
return m_buttonGroup->exclusive();
}
void SigningProtocolSelectionWidget::setCertificate( Protocol prot, const Key & key ) {
QAbstractButton * const b = button( prot );
assert( b );
b->setText( formatLabel( prot, key ) );
}
void ReadOnlyProtocolSelectionWidget::setCertificate( Protocol prot, const Key & key ) {
QLabel * const l = label( prot );
l->setText( formatLabel( prot, key ) );
}
namespace {
class ValidatorImpl : public SignerResolvePage::Validator {
public:
QString explanation() const { return QString(); }
bool isComplete() const { return true; }
QString customWindowTitle() const { return QString(); }
};
}
class SignerResolvePage::Private {
friend class ::Kleo::Crypto::Gui::SignerResolvePage;
SignerResolvePage * const q;
public:
explicit Private( SignerResolvePage * qq );
~Private();
void setOperation( Operation operation );
void operationButtonClicked( int operation );
void selectCertificates();
void setCertificates( const QMap<GpgME::Protocol, GpgME::Key>& certs );
void updateModeSelectionWidgets();
void updateUi();
bool protocolSelected( Protocol p ) const;
bool protocolSelectionActuallyUserMutable() const;
private:
QButtonGroup* signEncryptGroup;
QRadioButton* signAndEncryptRB;
QRadioButton* encryptOnlyRB;
QRadioButton* signOnlyRB;
QGroupBox* signingCertificateBox;
QLabel * signerLabelLabel;
QLabel * signerLabel;
QGroupBox * encryptBox;
QCheckBox * textArmorCO;
QCheckBox * removeUnencryptedCO;
QPushButton * selectCertificatesButton;
SigningProtocolSelectionWidget* signingProtocolSelectionWidget;
ReadOnlyProtocolSelectionWidget* readOnlyProtocolSelectionWidget;
std::vector<Protocol> presetProtocols;
bool signingMutable;
bool encryptionMutable;
bool signingSelected;
bool encryptionSelected;
bool multipleProtocolsAllowed;
bool protocolSelectionUserMutable;
QMap<GpgME::Protocol,GpgME::Key> certificates;
shared_ptr<SignerResolvePage::Validator> validator;
shared_ptr<SigningPreferences> signingPreferences;
};
bool SignerResolvePage::Private::protocolSelectionActuallyUserMutable() const {
return ( q->protocolSelectionUserMutable() || presetProtocols.empty() ) && q->operation() == SignOnly;
}
SignerResolvePage::Private::Private( SignerResolvePage * qq )
: q( qq )
, presetProtocols()
, signingMutable( true )
, encryptionMutable( true )
, signingSelected( false )
, encryptionSelected( false )
, multipleProtocolsAllowed( false )
, protocolSelectionUserMutable( true )
, validator( new ValidatorImpl )
{
QVBoxLayout* layout = new QVBoxLayout( q );
layout->setSpacing( KDialog::spacingHint() );
signEncryptGroup = new QButtonGroup( q );
q->connect( signEncryptGroup, SIGNAL(buttonClicked(int)), q, SLOT(operationButtonClicked(int)) );
signAndEncryptRB = new QRadioButton;
signAndEncryptRB->setText( i18n( "Sign and encrypt (OpenPGP only)" ) );
signAndEncryptRB->setChecked( true );
signEncryptGroup->addButton( signAndEncryptRB, SignAndEncrypt );
layout->addWidget( signAndEncryptRB );
encryptOnlyRB = new QRadioButton;
encryptOnlyRB->setText( i18n( "Encrypt only" ) );
signEncryptGroup->addButton( encryptOnlyRB, EncryptOnly );
layout->addWidget( encryptOnlyRB );
signOnlyRB = new QRadioButton;
signOnlyRB->setText( i18n( "Sign only" ) );
signEncryptGroup->addButton( signOnlyRB, SignOnly );
layout->addWidget( signOnlyRB );
encryptBox = new QGroupBox;
encryptBox->setTitle( i18n( "Encryption Options" ) );
QBoxLayout * const encryptLayout = new QVBoxLayout( encryptBox );
textArmorCO = new QCheckBox;
textArmorCO->setText( i18n( "Text output (ASCII armor)" ) );
encryptLayout->addWidget( textArmorCO );
removeUnencryptedCO = new QCheckBox;
removeUnencryptedCO->setText( i18n( "Remove unencrypted original file when done" ) );
removeUnencryptedCO->setChecked( false );
encryptLayout->addWidget( removeUnencryptedCO );
layout->addWidget( encryptBox );
signingCertificateBox = new QGroupBox;
signingCertificateBox->setTitle( i18n( "Signing Options" ) );
QGridLayout* signerLayout = new QGridLayout( signingCertificateBox );
signerLayout->setColumnStretch( 1, 1 );
signerLabelLabel = new QLabel;
signerLabelLabel->setText( i18n( "Signer:" ) );
signerLayout->addWidget( signerLabelLabel, 1, 0 );
signerLabel = new QLabel;
signerLayout->addWidget( signerLabel, 1, 1 );
signerLabelLabel->setVisible( false );
signerLabel->setVisible( false );
signingProtocolSelectionWidget = new SigningProtocolSelectionWidget;
connect( signingProtocolSelectionWidget, SIGNAL(userSelectionChanged()), q, SLOT(updateUi()) );
signerLayout->addWidget( signingProtocolSelectionWidget, 2, 0, 1, -1 );
readOnlyProtocolSelectionWidget = new ReadOnlyProtocolSelectionWidget;
signerLayout->addWidget( readOnlyProtocolSelectionWidget, 3, 0, 1, -1 );
selectCertificatesButton = new QPushButton;
selectCertificatesButton->setText( i18n( "Change Signing Certificates..." ) );
selectCertificatesButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
signerLayout->addWidget( selectCertificatesButton, 4, 0, 1, -1, Qt::AlignLeft );
q->connect( selectCertificatesButton, SIGNAL(clicked()),
q, SLOT(selectCertificates()) );
layout->addWidget( signingCertificateBox );
layout->addStretch();
}
void SignerResolvePage::setValidator( const boost::shared_ptr<SignerResolvePage::Validator>& validator )
{
assert( validator );
d->validator = validator;
d->updateUi();
}
shared_ptr<SignerResolvePage::Validator> SignerResolvePage::validator() const
{
return d->validator;
}
SignerResolvePage::Private::~Private() {}
bool SignerResolvePage::Private::protocolSelected( Protocol p ) const {
assert( p != UnknownProtocol );
return signingProtocolSelectionWidget->isProtocolChecked( p );
}
void SignerResolvePage::Private::setCertificates( const QMap<GpgME::Protocol, GpgME::Key>& certs )
{
certificates = certs;
Q_FOREACH ( const Protocol i, certs.keys() ) { //krazy:exclude=foreach
const Key key = certs.value( i );
readOnlyProtocolSelectionWidget->setCertificate( i, key );
signingProtocolSelectionWidget->setCertificate( i, key );
}
updateUi();
}
void SignerResolvePage::Private::updateUi() {
const bool ismutable = protocolSelectionActuallyUserMutable();
readOnlyProtocolSelectionWidget->setVisible( !ismutable );
signingProtocolSelectionWidget->setVisible( ismutable );
q->setExplanation( validator->explanation() );
emit q->completeChanged();
const QString customTitle = validator->customWindowTitle();
if ( !customTitle.isEmpty() )
emit q->windowTitleChanged( customTitle );
selectCertificatesButton->setEnabled(signingProtocolSelectionWidget->checkedProtocols().size()>0);
}
void SignerResolvePage::setProtocolSelectionUserMutable( bool ismutable ) {
if ( d->protocolSelectionUserMutable == ismutable )
return;
d->protocolSelectionUserMutable = ismutable;
d->updateModeSelectionWidgets();
}
bool SignerResolvePage::protocolSelectionUserMutable() const {
return d->protocolSelectionUserMutable;
}
void SignerResolvePage::setMultipleProtocolsAllowed( bool allowed )
{
if ( d->multipleProtocolsAllowed == allowed )
return;
d->multipleProtocolsAllowed = allowed;
d->updateModeSelectionWidgets();
}
bool SignerResolvePage::multipleProtocolsAllowed() const
{
return d->multipleProtocolsAllowed;
}
void SignerResolvePage::Private::updateModeSelectionWidgets()
{
const bool bothMutable = signingMutable && encryptionMutable;
const bool noSigningPossible = !signingSelected && !signingMutable;
const bool noEncryptionPossible = !encryptionSelected && !encryptionMutable;
signAndEncryptRB->setChecked( signingSelected && encryptionSelected );
signOnlyRB->setChecked( signingSelected && !encryptionSelected );
encryptOnlyRB->setChecked( encryptionSelected && !signingSelected );
const bool canSignAndEncrypt = !noSigningPossible && !noEncryptionPossible; bothMutable && presetProtocols != std::vector<Protocol>( 1, CMS );
const bool canSignOnly = !encryptionSelected || encryptionMutable;
const bool canEncryptOnly = !signingSelected || signingMutable;
signAndEncryptRB->setEnabled( canSignAndEncrypt );
signOnlyRB->setEnabled( canSignOnly );
encryptOnlyRB->setEnabled( canEncryptOnly );
const bool buttonsVisible = signingMutable || encryptionMutable;
signOnlyRB->setVisible( buttonsVisible );
encryptOnlyRB->setVisible( buttonsVisible );
signAndEncryptRB->setVisible( buttonsVisible );
signingProtocolSelectionWidget->setExclusive( !multipleProtocolsAllowed );
signingCertificateBox->setVisible( !noSigningPossible );
encryptBox->setVisible( !noEncryptionPossible );
updateUi();
}
void SignerResolvePage::Private::selectCertificates()
{
QPointer<SigningCertificateSelectionDialog> dlg = new SigningCertificateSelectionDialog( q );
dlg->setAllowedProtocols( QVector<Protocol>::fromStdVector( signingProtocolSelectionWidget->checkedProtocols() ) );
if ( dlg->exec() == QDialog::Accepted && dlg )
{
const QMap<Protocol, Key> certs = dlg->selectedCertificates();
setCertificates( certs );
if ( signingPreferences && dlg->rememberAsDefault() ) {
signingPreferences->setPreferredCertificate( OpenPGP, certs.value( OpenPGP ) );
signingPreferences->setPreferredCertificate( CMS, certs.value( CMS ) );
}
}
delete dlg;
updateUi();
}
void SignerResolvePage::Private::operationButtonClicked( int mode_ )
{
const Operation op = static_cast<SignerResolvePage::Operation>( mode_ );
signingCertificateBox->setEnabled( op != EncryptOnly );
encryptBox->setEnabled( op != SignOnly );
if ( op == SignAndEncrypt ) {
signingProtocolSelectionWidget->setProtocolChecked( CMS, false );
readOnlyProtocolSelectionWidget->setProtocolChecked( CMS, false );
signingProtocolSelectionWidget->setProtocolChecked( OpenPGP, true );
readOnlyProtocolSelectionWidget->setProtocolChecked( OpenPGP, true );
}
updateUi();
}
void SignerResolvePage::Private::setOperation( Operation op ) {
switch ( op ) {
case SignOnly:
signOnlyRB->click();
break;
case EncryptOnly:
encryptOnlyRB->click();
break;
case SignAndEncrypt:
signAndEncryptRB->click();
break;
}
}
SignerResolvePage::Operation SignerResolvePage::operation() const
{
return operationFromFlags( signingSelected(), encryptionSelected() );
}
SignerResolvePage::SignerResolvePage( QWidget * parent, Qt::WindowFlags f )
: WizardPage( parent, f ), d( new Private( this ) )
{
setTitle( i18n( "<b>Choose Operation to be Performed</b>" ) );
// setSubTitle( i18n( "TODO" ) );
setPresetProtocol( UnknownProtocol );
d->setCertificates( QMap<GpgME::Protocol, GpgME::Key>() );
d->updateModeSelectionWidgets();
d->operationButtonClicked( EncryptOnly );
}
SignerResolvePage::~SignerResolvePage() {}
void SignerResolvePage::setSignersAndCandidates( const std::vector<KMime::Types::Mailbox> & signers,
const std::vector< std::vector<GpgME::Key> > & keys )
{
kleo_assert( signers.empty() || signers.size() == keys.size() );
switch ( signers.size() )
{
case 0:
d->signerLabelLabel->setVisible( false );
d->signerLabel->setVisible( false ); // TODO: use default identity?
break;
case 1:
d->signerLabelLabel->setVisible( true );
d->signerLabel->setVisible( true ); // TODO: use default identity?
d->signerLabel->setText( signers.front().prettyAddress() );
break;
default: // > 1
kleo_assert( !"Resolving multiple signers not implemented" );
}
d->updateUi();
}
void SignerResolvePage::setPresetProtocol( Protocol protocol )
{
std::vector<Protocol> protocols;
if ( protocol != CMS )
protocols.push_back( OpenPGP );
if ( protocol != OpenPGP )
protocols.push_back( CMS );
setPresetProtocols( protocols );
d->updateUi();
}
void SignerResolvePage::setPresetProtocols( const std::vector<Protocol>& protocols )
{
d->presetProtocols = protocols;
Q_FOREACH ( const Protocol i, supportedProtocols() ) { //krazy:exclude=foreach
const bool checked = std::find( protocols.begin(), protocols.end(), i ) != protocols.end();
d->signingProtocolSelectionWidget->setProtocolChecked( i, checked );
d->readOnlyProtocolSelectionWidget->setProtocolChecked( i, checked );
}
d->updateModeSelectionWidgets();
}
std::vector<Protocol> SignerResolvePage::selectedProtocols() const {
return d->signingProtocolSelectionWidget->checkedProtocols();
}
std::vector<Key> SignerResolvePage::signingCertificates( Protocol protocol ) const
{
std::vector<Key> result;
if ( protocol != CMS && d->signingProtocolSelectionWidget->isProtocolChecked( OpenPGP ) && !d->certificates[OpenPGP].isNull() )
result.push_back( d->certificates[OpenPGP] );
if ( protocol != OpenPGP && d->signingProtocolSelectionWidget->isProtocolChecked( CMS ) && !d->certificates[CMS].isNull() )
result.push_back( d->certificates[CMS] );
return result;
}
std::vector<Key> SignerResolvePage::resolvedSigners() const
{
std::vector<Key> result = signingCertificates( CMS );
const std::vector<Key> pgp = signingCertificates( OpenPGP );
result.insert( result.end(), pgp.begin(), pgp.end() );
return result;
}
bool SignerResolvePage::isComplete() const
{
assert( d->validator );
return d->validator->isComplete();
}
bool SignerResolvePage::encryptionSelected() const
{
return !d->signOnlyRB->isChecked();
}
void SignerResolvePage::setEncryptionSelected( bool selected )
{
d->encryptionSelected = selected;
d->updateModeSelectionWidgets();
d->setOperation( operationFromFlags( d->signingSelected, d->encryptionSelected ) );
}
bool SignerResolvePage::signingSelected() const
{
return !d->encryptOnlyRB->isChecked();
}
void SignerResolvePage::setSigningSelected( bool selected )
{
d->signingSelected = selected;
d->updateModeSelectionWidgets();
d->setOperation( operationFromFlags( d->signingSelected, d->encryptionSelected ) );
}
bool SignerResolvePage::isEncryptionUserMutable() const
{
return d->encryptionMutable;
}
bool SignerResolvePage::isSigningUserMutable() const
{
return d->signingMutable;
}
void SignerResolvePage::setEncryptionUserMutable( bool ismutable )
{
d->encryptionMutable = ismutable;
d->updateModeSelectionWidgets();
}
void SignerResolvePage::setSigningUserMutable( bool ismutable )
{
d->signingMutable = ismutable;
d->updateModeSelectionWidgets();
}
std::vector<Protocol> SignerResolvePage::selectedProtocolsWithoutSigningCertificate() const {
std::vector<Protocol> res;
Q_FOREACH ( const Protocol i, selectedProtocols() ) //krazy:exclude=foreach
if ( signingCertificates( i ).empty() )
res.push_back( i );
return res;
}
bool SignerResolvePage::isAsciiArmorEnabled() const
{
return d->textArmorCO->isChecked();
}
void SignerResolvePage::setAsciiArmorEnabled( bool enabled )
{
d->textArmorCO->setChecked( enabled );
}
bool SignerResolvePage::removeUnencryptedFile() const
{
return d->removeUnencryptedCO->isChecked();
}
void SignerResolvePage::setRemoveUnencryptedFile( bool remove )
{
d->removeUnencryptedCO->setChecked( remove );
}
void SignerResolvePage::setSigningPreferences( const boost::shared_ptr<SigningPreferences>& prefs )
{
d->signingPreferences = prefs;
QMap<Protocol,Key> map;
map[OpenPGP] = prefs ? prefs->preferredCertificate( OpenPGP ) : Key();
map[CMS] = prefs ? prefs->preferredCertificate( CMS ) : Key();
d->setCertificates( map );
}
shared_ptr<SigningPreferences> SignerResolvePage::signingPreferences() const
{
return d->signingPreferences;
}
void SignerResolvePage::onNext()
{
}
#include "moc_signerresolvepage.cpp"
#include "moc_signerresolvepage_p.cpp"
diff --git a/crypto/gui/signerresolvepage.h b/crypto/gui/signerresolvepage.h
index ed6581849..a09b9976d 100644
--- a/crypto/gui/signerresolvepage.h
+++ b/crypto/gui/signerresolvepage.h
@@ -1,148 +1,148 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/gui/signerresolvepage.h
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2007 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#ifndef __KLEOPATRA_CRYPTO_GUI_SIGNERRESOLVEPAGE_H__
#define __KLEOPATRA_CRYPTO_GUI_SIGNERRESOLVEPAGE_H__
#include <crypto/gui/wizardpage.h>
#include <utils/pimpl_ptr.h>
#include <gpgme++/global.h>
-#include <KMime/kmime_header_parsing.h>
+#include <kmime/kmime_header_parsing.h>
#include <boost/shared_ptr.hpp>
#include <vector>
namespace GpgME {
class Key;
}
namespace Kleo {
namespace Crypto {
class SigningPreferences;
namespace Gui {
class SignerResolvePage : public WizardPage {
Q_OBJECT
public:
explicit SignerResolvePage( QWidget * parent=0, Qt::WindowFlags f=0 );
~SignerResolvePage();
void setSignersAndCandidates( const std::vector<KMime::Types::Mailbox> & signers,
const std::vector< std::vector<GpgME::Key> > & keys );
std::vector<GpgME::Key> resolvedSigners() const;
std::vector<GpgME::Key> signingCertificates( GpgME::Protocol protocol = GpgME::UnknownProtocol ) const;
/*reimpl*/ bool isComplete() const;
bool encryptionSelected() const;
void setEncryptionSelected( bool selected );
bool signingSelected() const;
void setSigningSelected( bool selected );
bool isEncryptionUserMutable() const;
void setEncryptionUserMutable( bool ismutable );
bool isSigningUserMutable() const;
void setSigningUserMutable( bool ismutable );
bool isAsciiArmorEnabled() const;
void setAsciiArmorEnabled( bool enabled );
bool removeUnencryptedFile() const;
void setRemoveUnencryptedFile( bool remove );
void setPresetProtocol( GpgME::Protocol protocol );
void setPresetProtocols( const std::vector<GpgME::Protocol>& protocols );
std::vector<GpgME::Protocol> selectedProtocols() const;
std::vector<GpgME::Protocol> selectedProtocolsWithoutSigningCertificate() const;
void setMultipleProtocolsAllowed( bool allowed );
bool multipleProtocolsAllowed() const;
void setProtocolSelectionUserMutable( bool ismutable );
bool protocolSelectionUserMutable() const;
enum Operation {
SignAndEncrypt=0,
SignOnly,
EncryptOnly
};
Operation operation() const;
class Validator
{
public:
virtual ~Validator() {}
virtual bool isComplete() const = 0;
virtual QString explanation() const = 0;
/**
* returns a custom window title, or a null string if no custom
* title is required.
* (use this if the title needs dynamic adaption
* depending on the user's selection)
*/
virtual QString customWindowTitle() const = 0;
};
void setValidator( const boost::shared_ptr<Validator>& );
boost::shared_ptr<Validator> validator() const;
void setSigningPreferences( const boost::shared_ptr<SigningPreferences>& prefs );
boost::shared_ptr<SigningPreferences> signingPreferences() const;
private:
/*reimpl*/ void onNext();
private:
class Private;
kdtools::pimpl_ptr<Private> d;
Q_PRIVATE_SLOT( d, void operationButtonClicked( int ) )
Q_PRIVATE_SLOT( d, void selectCertificates() )
Q_PRIVATE_SLOT( d, void updateUi() )
};
}
}
}
#endif // __KLEOPATRA_CRYPTO_GUI_SIGNERRESOLVEPAGE_H__
diff --git a/crypto/newsignencryptemailcontroller.cpp b/crypto/newsignencryptemailcontroller.cpp
index c98a3811f..9e91f7d28 100644
--- a/crypto/newsignencryptemailcontroller.cpp
+++ b/crypto/newsignencryptemailcontroller.cpp
@@ -1,569 +1,569 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/newsignencryptemailcontroller.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2009,2010 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include <config-kleopatra.h>
#include "newsignencryptemailcontroller.h"
#include "encryptemailtask.h"
#include "signemailtask.h"
#include "taskcollection.h"
#include "sender.h"
#include "recipient.h"
#include "emailoperationspreferences.h"
#include <crypto/gui/signencryptemailconflictdialog.h>
#include <utils/input.h>
#include <utils/output.h>
#include <utils/kleo_assert.h>
#include <kleo/stl_util.h>
#include <kleo/exception.h>
#include <gpgme++/key.h>
-#include <KMime/kmime_header_parsing.h>
+#include <kmime/kmime_header_parsing.h>
#include <KLocalizedString>
#include <KDebug>
#include <KMessageBox>
#include <QPointer>
#include <QTimer>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
using namespace Kleo;
using namespace Kleo::Crypto;
using namespace Kleo::Crypto::Gui;
using namespace boost;
using namespace GpgME;
using namespace KMime::Types;
//
// BEGIN Conflict Detection
//
/*
This code implements the following conflict detection algortihm:
1. There is no conflict if and only if we have a Perfect Match.
2. A Perfect Match is defined as:
a. either a Perfect OpenPGP-Match and not even a Partial S/MIME Match
b. or a Perfect S/MIME-Match and not even a Partial OpenPGP-Match
c. or a Perfect OpenPGP-Match and preselected protocol=OpenPGP
d. or a Perfect S/MIME-Match and preselected protocol=S/MIME
3. For Protocol \in {OpenPGP,S/MIME}, a Perfect Protocol-Match is defined as:
a. If signing, \foreach Sender, there is exactly one
Matching Protocol-Certificate with
i. can-sign=true
ii. has-secret=true
b. and, if encrypting, \foreach Recipient, there is exactly one
Matching Protocol-Certificate with
i. can-encrypt=true
ii. (validity is not considered, cf. msg 24059)
4. For Protocol \in {OpenPGP,S/MIME}, a Partial Protocol-Match is defined as:
a. If signing, \foreach Sender, there is at least one
Matching Protocol-Certificate with
i. can-sign=true
ii. has-secret=true
b. and, if encrypting, \foreach Recipient, there is at least
one Matching Protocol-Certificate with
i. can-encrypt=true
ii. (validity is not considered, cf. msg 24059)
5. For Protocol \in {OpenPGP,S/MIME}, a Matching Protocol-Certificate is
defined as matching by email-address. A revoked, disabled, or expired
certificate is not considered a match.
6. Sender is defined as those mailboxes that have been set with the SENDER
command.
7. Recipient is defined as those mailboxes that have been set with either the
SENDER or the RECIPIENT commands.
*/
namespace {
struct count_signing_certificates {
typedef size_t result_type;
const Protocol proto;
explicit count_signing_certificates( Protocol proto ) : proto( proto ) {}
size_t operator()( const Sender & sender ) const {
const size_t result = sender.signingCertificateCandidates( proto ).size();
qDebug( "count_signing_certificates( %9s %20s ) == %2lu",
proto == OpenPGP ? "OpenPGP," : proto == CMS ? "CMS," : "<unknown>,",
qPrintable( sender.mailbox().prettyAddress() ), result );
return result;
}
};
struct count_encrypt_certificates {
typedef size_t result_type;
const Protocol proto;
explicit count_encrypt_certificates( Protocol proto ) : proto( proto ) {}
size_t operator()( const Sender & sender ) const {
const size_t result = sender.encryptToSelfCertificateCandidates( proto ).size();
qDebug( "count_encrypt_certificates( %9s %20s ) == %2lu",
proto == OpenPGP ? "OpenPGP," : proto == CMS ? "CMS," : "<unknown>,",
qPrintable( sender.mailbox().prettyAddress() ), result );
return result;
}
size_t operator()( const Recipient & recipient ) const {
const size_t result = recipient.encryptionCertificateCandidates( proto ).size();
qDebug( "count_encrypt_certificates( %9s %20s ) == %2lu",
proto == OpenPGP ? "OpenPGP," : proto == CMS ? "CMS," : "<unknown>,",
qPrintable( recipient.mailbox().prettyAddress() ), result );
return result;
}
};
}
static bool has_perfect_match( bool sign, bool encrypt, Protocol proto, const std::vector<Sender> & senders, const std::vector<Recipient> & recipients ) {
if ( sign )
if ( !kdtools::all( senders, boost::bind( count_signing_certificates( proto ), _1 ) == 1 ) )
return false;
if ( encrypt )
if ( !kdtools::all( senders, boost::bind( count_encrypt_certificates( proto ), _1 ) == 1 ) ||
!kdtools::all( recipients, boost::bind( count_encrypt_certificates( proto ), _1 ) == 1 ) )
return false;
return true;
}
static bool has_partial_match( bool sign, bool encrypt, Protocol proto, const std::vector<Sender> & senders, const std::vector<Recipient> & recipients ) {
if ( sign )
if ( !kdtools::all( senders, boost::bind( count_signing_certificates( proto ), _1 ) >= 1 ) )
return false;
if ( encrypt )
if ( !kdtools::all( senders, boost::bind( count_encrypt_certificates( proto ), _1 ) >= 1 ) ||
!kdtools::all( recipients, boost::bind( count_encrypt_certificates( proto ), _1 ) >= 1 ) )
return false;
return true;
}
static bool has_perfect_overall_match( bool sign, bool encrypt, const std::vector<Sender> & senders, const std::vector<Recipient> & recipients, Protocol presetProtocol ) {
return presetProtocol == OpenPGP && has_perfect_match( sign, encrypt, OpenPGP, senders, recipients )
|| presetProtocol == CMS && has_perfect_match( sign, encrypt, CMS, senders, recipients )
|| has_perfect_match( sign, encrypt, OpenPGP, senders, recipients ) && !has_partial_match( sign, encrypt, CMS, senders, recipients )
|| has_perfect_match( sign, encrypt, CMS, senders, recipients ) && !has_partial_match( sign, encrypt, OpenPGP, senders, recipients ) ;
}
static bool has_conflict( bool sign, bool encrypt, const std::vector<Sender> & senders, const std::vector<Recipient> & recipients, Protocol presetProtocol ) {
return !has_perfect_overall_match( sign, encrypt, senders, recipients, presetProtocol );
}
//
// END Conflict Detection
//
static std::vector<Sender> mailbox2sender( const std::vector<Mailbox> & mbs ) {
std::vector<Sender> senders;
senders.reserve( mbs.size() );
Q_FOREACH( const Mailbox & mb, mbs )
senders.push_back( Sender( mb ) );
return senders;
}
static std::vector<Recipient> mailbox2recipient( const std::vector<Mailbox> & mbs ) {
std::vector<Recipient> recipients;
recipients.reserve( mbs.size() );
Q_FOREACH( const Mailbox & mb, mbs )
recipients.push_back( Recipient( mb ) );
return recipients;
}
class NewSignEncryptEMailController::Private {
friend class ::Kleo::Crypto::NewSignEncryptEMailController;
NewSignEncryptEMailController * const q;
public:
explicit Private( NewSignEncryptEMailController * qq );
~Private();
private:
void slotDialogAccepted();
void slotDialogRejected();
private:
void ensureDialogVisible();
void cancelAllTasks();
void startSigning();
void startEncryption();
void schedule();
shared_ptr<Task> takeRunnable( GpgME::Protocol proto );
private:
bool sign : 1;
bool encrypt : 1;
bool resolvingInProgress : 1;
bool certificatesResolved : 1;
bool detached : 1;
Protocol presetProtocol;
std::vector<Key> signers, recipients;
std::vector< shared_ptr<Task> > runnable, completed;
shared_ptr<Task> cms, openpgp;
QPointer<SignEncryptEMailConflictDialog> dialog;
};
NewSignEncryptEMailController::Private::Private( NewSignEncryptEMailController * qq )
: q( qq ),
sign( false ),
encrypt( false ),
resolvingInProgress( false ),
certificatesResolved( false ),
detached( false ),
presetProtocol( UnknownProtocol ),
signers(),
recipients(),
runnable(),
cms(),
openpgp(),
dialog( new SignEncryptEMailConflictDialog )
{
connect( dialog, SIGNAL(accepted()), q, SLOT(slotDialogAccepted()) );
connect( dialog, SIGNAL(rejected()), q, SLOT(slotDialogRejected()) );
}
NewSignEncryptEMailController::Private::~Private() {
delete dialog;
}
NewSignEncryptEMailController::NewSignEncryptEMailController( const shared_ptr<ExecutionContext> & xc, QObject * p )
: Controller( xc, p ), d( new Private( this ) )
{
}
NewSignEncryptEMailController::NewSignEncryptEMailController( QObject * p )
: Controller( p ), d( new Private( this ) )
{
}
NewSignEncryptEMailController::~NewSignEncryptEMailController() { kDebug(); }
void NewSignEncryptEMailController::setSubject( const QString & subject ) {
d->dialog->setSubject( subject );
}
void NewSignEncryptEMailController::setProtocol( Protocol proto ) {
d->presetProtocol = proto;
d->dialog->setPresetProtocol( proto );
}
Protocol NewSignEncryptEMailController::protocol() const {
return d->dialog->selectedProtocol();
}
const char * NewSignEncryptEMailController::protocolAsString() const {
switch ( protocol() ) {
case OpenPGP: return "OpenPGP";
case CMS: return "CMS";
default:
throw Kleo::Exception( gpg_error( GPG_ERR_INTERNAL ),
i18n("Call to NewSignEncryptEMailController::protocolAsString() is ambiguous.") );
}
}
void NewSignEncryptEMailController::setSigning( bool sign ) {
d->sign = sign;
d->dialog->setSign( sign );
}
bool NewSignEncryptEMailController::isSigning() const {
return d->sign;
}
void NewSignEncryptEMailController::setEncrypting( bool encrypt ) {
d->encrypt = encrypt;
d->dialog->setEncrypt( encrypt );
}
bool NewSignEncryptEMailController::isEncrypting() const {
return d->encrypt;
}
void NewSignEncryptEMailController::setDetachedSignature( bool detached ) {
d->detached = detached;
}
bool NewSignEncryptEMailController::isResolvingInProgress() const {
return d->resolvingInProgress;
}
bool NewSignEncryptEMailController::areCertificatesResolved() const {
return d->certificatesResolved;
}
static bool is_dialog_quick_mode( bool sign, bool encrypt ) {
const EMailOperationsPreferences prefs;
return ( !sign || prefs.quickSignEMail() )
&& ( !encrypt || prefs.quickEncryptEMail() )
;
}
static void save_dialog_quick_mode( bool on ) {
EMailOperationsPreferences prefs;
prefs.setQuickSignEMail( on );
prefs.setQuickEncryptEMail( on );
prefs.writeConfig();
}
void NewSignEncryptEMailController::startResolveCertificates( const std::vector<Mailbox> & r, const std::vector<Mailbox> & s ) {
d->certificatesResolved = false;
d->resolvingInProgress = true;
const std::vector<Sender> senders = mailbox2sender( s );
const std::vector<Recipient> recipients = mailbox2recipient( r );
const bool quickMode = is_dialog_quick_mode( d->sign, d->encrypt );
const bool conflict = quickMode && has_conflict( d->sign, d->encrypt, senders, recipients, d->presetProtocol );
d->dialog->setQuickMode( quickMode );
d->dialog->setSenders( senders );
d->dialog->setRecipients( recipients );
d->dialog->pickProtocol();
d->dialog->setConflict( conflict );
if ( quickMode && !conflict )
QMetaObject::invokeMethod( this, "slotDialogAccepted", Qt::QueuedConnection );
else
d->ensureDialogVisible();
}
void NewSignEncryptEMailController::Private::slotDialogAccepted() {
if ( dialog->isQuickMode() != is_dialog_quick_mode( sign, encrypt ) )
save_dialog_quick_mode( dialog->isQuickMode() );
resolvingInProgress = false;
certificatesResolved = true;
signers = dialog->resolvedSigningKeys();
recipients = dialog->resolvedEncryptionKeys();
QMetaObject::invokeMethod( q, "certificatesResolved", Qt::QueuedConnection );
}
void NewSignEncryptEMailController::Private::slotDialogRejected() {
resolvingInProgress = false;
certificatesResolved = false;
QMetaObject::invokeMethod( q, "error", Qt::QueuedConnection,
Q_ARG( int, gpg_error( GPG_ERR_CANCELED ) ),
Q_ARG( QString, i18n("User cancel") ) );
}
void NewSignEncryptEMailController::startEncryption( const std::vector< shared_ptr<Input> > & inputs, const std::vector< shared_ptr<Output> > & outputs ) {
kleo_assert( d->encrypt );
kleo_assert( !d->resolvingInProgress );
kleo_assert( !inputs.empty() );
kleo_assert( outputs.size() == inputs.size() );
std::vector< shared_ptr<Task> > tasks;
tasks.reserve( inputs.size() );
kleo_assert( !d->recipients.empty() );
for ( unsigned int i = 0, end = inputs.size() ; i < end ; ++i ) {
const shared_ptr<EncryptEMailTask> task( new EncryptEMailTask );
task->setInput( inputs[i] );
task->setOutput( outputs[i] );
task->setRecipients( d->recipients );
tasks.push_back( task );
}
// append to runnable stack
d->runnable.insert( d->runnable.end(), tasks.begin(), tasks.end() );
d->startEncryption();
}
void NewSignEncryptEMailController::Private::startEncryption() {
shared_ptr<TaskCollection> coll( new TaskCollection );
const std::vector<shared_ptr<Task> > tmp
= kdtools::copy< std::vector<shared_ptr<Task> > >( runnable );
coll->setTasks( tmp );
#if 0
#warning use a new result dialog
// ### use a new result dialog
dialog->setTaskCollection( coll );
#endif
Q_FOREACH( const shared_ptr<Task> & t, tmp )
q->connectTask( t );
schedule();
}
void NewSignEncryptEMailController::startSigning( const std::vector< shared_ptr<Input> > & inputs, const std::vector< shared_ptr<Output> > & outputs ) {
kleo_assert( d->sign );
kleo_assert( !d->resolvingInProgress );
kleo_assert( !inputs.empty() );
kleo_assert( !outputs.empty() );
std::vector< shared_ptr<Task> > tasks;
tasks.reserve( inputs.size() );
kleo_assert( !d->signers.empty() );
kleo_assert( kdtools::none_of( d->signers, mem_fn( &Key::isNull ) ) );
for ( unsigned int i = 0, end = inputs.size() ; i < end ; ++i ) {
const shared_ptr<SignEMailTask> task( new SignEMailTask );
task->setInput( inputs[i] );
task->setOutput( outputs[i] );
task->setSigners( d->signers );
task->setDetachedSignature( d->detached );
tasks.push_back( task );
}
// append to runnable stack
d->runnable.insert( d->runnable.end(), tasks.begin(), tasks.end() );
d->startSigning();
}
void NewSignEncryptEMailController::Private::startSigning() {
shared_ptr<TaskCollection> coll( new TaskCollection );
const std::vector<shared_ptr<Task> > tmp
= kdtools::copy< std::vector<shared_ptr<Task> > >( runnable );
coll->setTasks( tmp );
#if 0
#warning use a new result dialog
// ### use a new result dialog
dialog->setTaskCollection( coll );
#endif
Q_FOREACH( const shared_ptr<Task> & t, tmp )
q->connectTask( t );
schedule();
}
void NewSignEncryptEMailController::Private::schedule() {
if ( !cms )
if ( const shared_ptr<Task> t = takeRunnable( CMS ) ) {
t->start();
cms = t;
}
if ( !openpgp )
if ( const shared_ptr<Task> t = takeRunnable( OpenPGP ) ) {
t->start();
openpgp = t;
}
if ( cms || openpgp )
return;
kleo_assert( runnable.empty() );
q->emitDoneOrError();
}
shared_ptr<Task> NewSignEncryptEMailController::Private::takeRunnable( GpgME::Protocol proto ) {
const std::vector< shared_ptr<Task> >::iterator it
= std::find_if( runnable.begin(), runnable.end(),
boost::bind( &Task::protocol, _1 ) == proto );
if ( it == runnable.end() )
return shared_ptr<Task>();
const shared_ptr<Task> result = *it;
runnable.erase( it );
return result;
}
void NewSignEncryptEMailController::doTaskDone( const Task * task, const shared_ptr<const Task::Result> & result ) {
assert( task );
if ( result && result->hasError() ) {
QPointer<QObject> that = this;
if ( result->details().isEmpty() )
KMessageBox:: sorry( 0,
result->overview(),
i18nc("@title:window","Error") );
else
KMessageBox::detailedSorry( 0,
result->overview(),
result->details(),
i18nc("@title:window","Error") );
if ( !that )
return;
}
// We could just delete the tasks here, but we can't use
// Qt::QueuedConnection here (we need sender()) and other slots
// might not yet have executed. Therefore, we push completed tasks
// into a burial container
if ( task == d->cms.get() ) {
d->completed.push_back( d->cms );
d->cms.reset();
} else if ( task == d->openpgp.get() ) {
d->completed.push_back( d->openpgp );
d->openpgp.reset();
}
QTimer::singleShot( 0, this, SLOT(schedule()) );
}
void NewSignEncryptEMailController::cancel() {
try {
d->dialog->close();
d->cancelAllTasks();
} catch ( const std::exception & e ) {
kDebug() << "Caught exception: " << e.what();
}
}
void NewSignEncryptEMailController::Private::cancelAllTasks() {
// we just kill all runnable tasks - this will not result in
// signal emissions.
runnable.clear();
// a cancel() will result in a call to
if ( cms )
cms->cancel();
if ( openpgp )
openpgp->cancel();
}
void NewSignEncryptEMailController::Private::ensureDialogVisible() {
q->bringToForeground( dialog );
}
#include "moc_newsignencryptemailcontroller.cpp"
diff --git a/crypto/recipient.cpp b/crypto/recipient.cpp
index 5d7e8a051..60c2903e9 100644
--- a/crypto/recipient.cpp
+++ b/crypto/recipient.cpp
@@ -1,174 +1,174 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/recipient.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2009 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include <config-kleopatra.h>
#include "recipient.h"
#include <models/predicates.h>
#include <models/keycache.h>
#include <utils/kleo_assert.h>
#include <utils/cached.h>
-#include <KMime/kmime_header_parsing.h>
+#include <kmime/kmime_header_parsing.h>
#include <gpgme++/key.h>
using namespace Kleo;
using namespace Kleo::Crypto;
using namespace KMime::Types;
using namespace GpgME;
using namespace boost;
namespace KMime {
namespace Types {
static bool operator==( const AddrSpec & lhs, const AddrSpec & rhs ) {
return lhs.localPart == rhs.localPart
&& lhs.domain == rhs.domain ;
}
static bool operator==( const Mailbox & lhs, const Mailbox & rhs ) {
return lhs.name() == rhs.name()
&& lhs.addrSpec() == rhs.addrSpec() ;
}
static bool determine_ambiguous( const Mailbox & mb, const std::vector<Key> & keys ) {
Q_UNUSED( mb );
// ### really do check when we don't only show matching keys
return keys.size() != 1 ;
}
} // namespace Types
} // namespace KMime
class Recipient::Private {
friend class ::Kleo::Crypto::Recipient;
public:
explicit Private( const Mailbox & mb )
: mailbox( mb )
{
// ### also fill up to a certain number of keys with those
// ### that don't match, for the case where there's a low
// ### total number of keys
const std::vector<Key> encrypt = KeyCache::instance()->findEncryptionKeysByMailbox( mb );
kdtools::separate_if( encrypt,
std::back_inserter( pgpEncryptionKeys ), std::back_inserter( cmsEncryptionKeys ),
boost::bind( &Key::protocol, _1 ) == OpenPGP );
}
private:
const Mailbox mailbox;
std::vector<Key> pgpEncryptionKeys, cmsEncryptionKeys;
Key cmsEncryptionKey;
UserID pgpEncryptionUid;
cached<bool> encryptionAmbiguous[2];
};
Recipient::Recipient( const Mailbox & mb )
: d( new Private( mb ) )
{
}
void Recipient::detach() {
if ( d && !d.unique() )
d.reset( new Private( *d ) );
}
bool Recipient::deepEquals( const Recipient & other ) const {
static const _detail::ByFingerprint<std::equal_to> compare = {};
return mailbox() == other.mailbox()
&& compare( d->cmsEncryptionKey, other.d->cmsEncryptionKey )
&& compare( d->pgpEncryptionUid.parent(), other.d->pgpEncryptionUid.parent() )
&& strcmp( d->pgpEncryptionUid.id(), other.d->pgpEncryptionUid.id() )
&& kdtools::equal( d->pgpEncryptionKeys, other.d->pgpEncryptionKeys, compare )
&& kdtools::equal( d->cmsEncryptionKeys, other.d->cmsEncryptionKeys, compare )
;
}
bool Recipient::isEncryptionAmbiguous( GpgME::Protocol proto ) const {
if ( d->encryptionAmbiguous[proto].dirty() )
d->encryptionAmbiguous[proto] = determine_ambiguous( d->mailbox, encryptionCertificateCandidates( proto ) );
return d->encryptionAmbiguous[proto];
}
const Mailbox & Recipient::mailbox() const {
return d->mailbox;
}
const std::vector<Key> & Recipient::encryptionCertificateCandidates( GpgME::Protocol proto ) const {
if ( proto == OpenPGP )
return d->pgpEncryptionKeys;
if ( proto == CMS )
return d->cmsEncryptionKeys;
kleo_assert_fail( proto == OpenPGP || proto == CMS );
#if 0
return
proto == OpenPGP ? d->pgpEncryptionKeys :
proto == CMS ? d->cmsEncryptionKeys :
// even though gcc warns about this line, it's completely ok, promise:
kleo_assert_fail( proto == OpenPGP || proto == CMS ) ;
#endif
}
void Recipient::setResolvedEncryptionKey( const Key & key ) {
if ( key.isNull() )
return;
const Protocol proto = key.protocol();
kleo_assert( proto == OpenPGP || proto == CMS );
detach();
if ( proto == OpenPGP )
d->pgpEncryptionUid = key.userID( 0 );
else
d->cmsEncryptionKey = key;
d->encryptionAmbiguous[proto] = false;
}
Key Recipient::resolvedEncryptionKey( GpgME::Protocol proto ) const {
kleo_assert( proto == OpenPGP || proto == CMS );
if ( proto == OpenPGP )
return d->pgpEncryptionUid.parent();
else
return d->cmsEncryptionKey;
}
void Recipient::setResolvedOpenPGPEncryptionUserID( const UserID & uid ) {
if ( uid.isNull() )
return;
detach();
d->pgpEncryptionUid = uid;
}
UserID Recipient::resolvedOpenPGPEncryptionUserID() const {
return d->pgpEncryptionUid;
}
diff --git a/crypto/sender.cpp b/crypto/sender.cpp
index 9c3a173e5..3ffd92e8b 100644
--- a/crypto/sender.cpp
+++ b/crypto/sender.cpp
@@ -1,217 +1,217 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/sender.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2009 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include <config-kleopatra.h>
#include "sender.h"
#include <models/predicates.h>
#include <models/keycache.h>
#include <utils/kleo_assert.h>
#include <utils/cached.h>
-#include <KMime/kmime_header_parsing.h>
+#include <kmime/kmime_header_parsing.h>
#include <gpgme++/key.h>
using namespace Kleo;
using namespace Kleo::Crypto;
using namespace KMime::Types;
using namespace GpgME;
using namespace boost;
namespace KMime {
namespace Types {
static bool operator==( const AddrSpec & lhs, const AddrSpec & rhs ) {
return lhs.localPart == rhs.localPart
&& lhs.domain == rhs.domain ;
}
static bool operator==( const Mailbox & lhs, const Mailbox & rhs ) {
return lhs.name() == rhs.name()
&& lhs.addrSpec() == rhs.addrSpec() ;
}
static bool determine_ambiguous( const Mailbox & mb, const std::vector<Key> & keys ) {
Q_UNUSED( mb );
// ### really do check when we don't only show matching keys
return keys.size() != 1 ;
}
} // namespace Types
} // namespace KMime
class Sender::Private {
friend class ::Kleo::Crypto::Sender;
public:
explicit Private( const Mailbox & mb )
: mailbox( mb )
{
// ### also fill up to a certain number of keys with those
// ### that don't match, for the case where there's a low
// ### total number of keys
const std::vector<Key> signers = KeyCache::instance()->findSigningKeysByMailbox( mb );
const std::vector<Key> encrypt = KeyCache::instance()->findEncryptionKeysByMailbox( mb );
kdtools::separate_if( signers,
std::back_inserter( pgpSigners ), std::back_inserter( cmsSigners ),
boost::bind( &Key::protocol, _1 ) == OpenPGP );
kdtools::separate_if( encrypt,
std::back_inserter( pgpEncryptToSelfKeys ), std::back_inserter( cmsEncryptToSelfKeys ),
boost::bind( &Key::protocol, _1 ) == OpenPGP );
}
private:
const Mailbox mailbox;
std::vector<Key> pgpSigners, cmsSigners, pgpEncryptToSelfKeys, cmsEncryptToSelfKeys;
cached<bool> signingAmbiguous[2], encryptionAmbiguous[2];
Key signingKey[2], cmsEncryptionKey;
UserID pgpEncryptionUid;
};
Sender::Sender( const Mailbox & mb )
: d( new Private( mb ) )
{
}
void Sender::detach() {
if ( d && !d.unique() )
d.reset( new Private( *d ) );
}
bool Sender::deepEquals( const Sender & other ) const {
static const _detail::ByFingerprint<std::equal_to> compare = {};
return mailbox() == other.mailbox()
&& compare( d->signingKey[CMS], other.d->signingKey[CMS] )
&& compare( d->signingKey[OpenPGP], other.d->signingKey[OpenPGP] )
&& compare( d->cmsEncryptionKey, other.d->cmsEncryptionKey )
&& compare( d->pgpEncryptionUid.parent(), other.d->pgpEncryptionUid.parent() )
&& strcmp( d->pgpEncryptionUid.id(), other.d->pgpEncryptionUid.id() ) == 0
&& kdtools::equal( d->pgpSigners, other.d->pgpSigners, compare )
&& kdtools::equal( d->cmsSigners, other.d->cmsSigners, compare )
&& kdtools::equal( d->pgpEncryptToSelfKeys, other.d->pgpEncryptToSelfKeys, compare )
&& kdtools::equal( d->cmsEncryptToSelfKeys, other.d->cmsEncryptToSelfKeys, compare )
;
}
bool Sender::isSigningAmbiguous( GpgME::Protocol proto ) const {
if ( d->signingAmbiguous[proto].dirty() )
d->signingAmbiguous[proto] = determine_ambiguous( d->mailbox, signingCertificateCandidates( proto ) );
return d->signingAmbiguous[proto];
}
bool Sender::isEncryptionAmbiguous( GpgME::Protocol proto ) const {
if ( d->encryptionAmbiguous[proto].dirty() )
d->encryptionAmbiguous[proto] = determine_ambiguous( d->mailbox, encryptToSelfCertificateCandidates( proto ) );
return d->encryptionAmbiguous[proto];
}
const Mailbox & Sender::mailbox() const {
return d->mailbox;
}
const std::vector<Key> & Sender::signingCertificateCandidates( GpgME::Protocol proto ) const {
if ( proto == OpenPGP )
return d->pgpSigners;
if ( proto == CMS )
return d->cmsSigners;
kleo_assert_fail( proto == OpenPGP || proto == CMS );
#if 0
return
proto == OpenPGP ? d->pgpSigners :
proto == CMS ? d->cmsSigners :
// even though gcc warns about this line, it's completely ok, promise:
kleo_assert_fail( proto == OpenPGP || proto == CMS ) ;
#endif
}
const std::vector<Key> & Sender::encryptToSelfCertificateCandidates( GpgME::Protocol proto ) const {
if ( proto == OpenPGP )
return d->pgpEncryptToSelfKeys;
if ( proto == CMS )
return d->cmsEncryptToSelfKeys;
kleo_assert_fail( proto == OpenPGP || proto == CMS );
#if 0
return
proto == OpenPGP ? d->pgpEncryptToSelfKeys :
proto == CMS ? d->cmsEncryptToSelfKeys :
// even though gcc warns about this line, it's completely ok, promise:
kleo_assert_fail( proto == OpenPGP || proto == CMS ) ;
#endif
}
void Sender::setResolvedSigningKey( const Key & key ) {
if ( key.isNull() )
return;
const Protocol proto = key.protocol();
kleo_assert( proto == OpenPGP || proto == CMS );
detach();
d->signingKey[proto] = key;
d->signingAmbiguous[proto] = false;
}
Key Sender::resolvedSigningKey( GpgME::Protocol proto ) const {
kleo_assert( proto == OpenPGP || proto == CMS );
return d->signingKey[proto];
}
void Sender::setResolvedEncryptionKey( const Key & key ) {
if ( key.isNull() )
return;
const Protocol proto = key.protocol();
kleo_assert( proto == OpenPGP || proto == CMS );
detach();
if ( proto == OpenPGP )
d->pgpEncryptionUid = key.userID( 0 );
else
d->cmsEncryptionKey = key;
d->encryptionAmbiguous[proto] = false;
}
Key Sender::resolvedEncryptionKey( GpgME::Protocol proto ) const {
kleo_assert( proto == OpenPGP || proto == CMS );
if ( proto == OpenPGP )
return d->pgpEncryptionUid.parent();
else
return d->cmsEncryptionKey;
}
void Sender::setResolvedOpenPGPEncryptionUserID( const UserID & uid ) {
if ( uid.isNull() )
return;
detach();
d->pgpEncryptionUid = uid;
}
UserID Sender::resolvedOpenPGPEncryptionUserID() const {
return d->pgpEncryptionUid;
}
diff --git a/crypto/signemailcontroller.cpp b/crypto/signemailcontroller.cpp
index 487be8080..2c4937f5b 100644
--- a/crypto/signemailcontroller.cpp
+++ b/crypto/signemailcontroller.cpp
@@ -1,347 +1,347 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/signemailcontroller.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2007 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include <config-kleopatra.h>
#include "signemailcontroller.h"
#include "signemailtask.h"
#include "certificateresolver.h"
#include "taskcollection.h"
#include <crypto/gui/signemailwizard.h>
#include <utils/input.h>
#include <utils/output.h>
#include <utils/kleo_assert.h>
#include "emailoperationspreferences.h"
#include <kleo/stl_util.h>
-#include <KMime/kmime_header_parsing.h>
+#include <kmime/kmime_header_parsing.h>
#include <KLocalizedString>
#include <QPointer>
#include <QTimer>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <KDebug>
using namespace Kleo;
using namespace Kleo::Crypto;
using namespace Kleo::Crypto::Gui;
using namespace boost;
using namespace GpgME;
using namespace KMime::Types;
class SignEMailController::Private {
friend class ::Kleo::Crypto::SignEMailController;
SignEMailController * const q;
public:
explicit Private( Mode m, SignEMailController * qq );
~Private();
private:
void slotWizardSignersResolved();
void slotWizardCanceled(); // ### extract to base
private:
void ensureWizardCreated(); // ### extract to base
void ensureWizardVisible(); // ### extract to base
void cancelAllJobs(); // ### extract to base
void schedule(); // ### extract to base
shared_ptr<SignEMailTask> takeRunnable( GpgME::Protocol proto ); // ### extract to base
private:
const Mode mode;
std::vector< shared_ptr<SignEMailTask> > runnable, completed; // ### extract to base
shared_ptr<SignEMailTask> cms, openpgp; // ### extract to base
QPointer<SignEMailWizard> wizard; // ### extract to base
Protocol protocol; // ### extract to base
bool detached : 1;
};
SignEMailController::Private::Private( Mode m, SignEMailController * qq )
: q( qq ),
mode( m ),
runnable(),
cms(),
openpgp(),
wizard(),
protocol( UnknownProtocol ),
detached( false )
{
}
SignEMailController::Private::~Private() {}
SignEMailController::SignEMailController( Mode mode, QObject * p )
: Controller( p ), d( new Private( mode, this ) )
{
}
SignEMailController::SignEMailController( const boost::shared_ptr<ExecutionContext> & xc, Mode mode, QObject * p )
: Controller( xc, p ), d( new Private( mode, this ) )
{
}
SignEMailController::~SignEMailController() {
/// ### extract to base
if ( d->wizard && !d->wizard->isVisible() )
delete d->wizard;
//d->wizard->close(); ### ?
}
SignEMailController::Mode SignEMailController::mode() const {
return d->mode;
}
// ### extract to base
void SignEMailController::setProtocol( Protocol proto ) {
kleo_assert( d->protocol == UnknownProtocol ||
d->protocol == proto );
d->protocol = proto;
d->ensureWizardCreated();
d->wizard->setPresetProtocol( proto );
}
Protocol SignEMailController::protocol() const {
return d->protocol;
}
void SignEMailController::startResolveSigners() {
startResolveSigners( std::vector<Mailbox>() );
}
void SignEMailController::startResolveSigners( const std::vector<Mailbox> & signers ) {
const std::vector< std::vector<Key> > keys = CertificateResolver::resolveSigners( signers, d->protocol );
if ( !signers.empty() ) {
kleo_assert( keys.size() == static_cast<size_t>( signers.size() ) );
}
d->ensureWizardCreated();
d->wizard->setSignersAndCandidates( signers, keys );
d->ensureWizardVisible();
}
void SignEMailController::setDetachedSignature( bool detached ) {
kleo_assert( !d->openpgp );
kleo_assert( !d->cms );
kleo_assert( d->completed.empty() );
kleo_assert( d->runnable.empty() );
d->detached = detached;
}
void SignEMailController::Private::slotWizardSignersResolved() {
emit q->signersResolved();
}
// ### extract to base
void SignEMailController::Private::slotWizardCanceled() {
q->setLastError( gpg_error( GPG_ERR_CANCELED ), i18n("User cancel") );
q->emitDoneOrError();
}
void SignEMailController::setInputAndOutput( const shared_ptr<Input> & input, const shared_ptr<Output> & output ) {
setInputsAndOutputs( std::vector< shared_ptr<Input> >( 1, input ), std::vector< shared_ptr<Output> >( 1, output ) );
}
// ### extract to base
void SignEMailController::setInputsAndOutputs( const std::vector< shared_ptr<Input> > & inputs, const std::vector< shared_ptr<Output> > & outputs ) {
kleo_assert( !inputs.empty() );
kleo_assert( !outputs.empty() );
std::vector< shared_ptr<SignEMailTask> > tasks;
tasks.reserve( inputs.size() );
d->ensureWizardCreated();
const std::vector<Key> keys = d->wizard->resolvedSigners();
kleo_assert( !keys.empty() );
for ( unsigned int i = 0, end = inputs.size() ; i < end ; ++i ) {
const shared_ptr<SignEMailTask> task( new SignEMailTask );
task->setInput( inputs[i] );
task->setOutput( outputs[i] );
task->setSigners( keys );
task->setDetachedSignature( d->detached );
if ( d->mode == ClipboardMode ) {
if ( d->protocol == OpenPGP )
task->setClearsign( true );
else
task->setAsciiArmor( true );
}
tasks.push_back( task );
}
d->runnable.swap( tasks );
}
// ### extract to base
void SignEMailController::start() {
shared_ptr<TaskCollection> coll( new TaskCollection );
std::vector<shared_ptr<Task> > tmp;
std::copy( d->runnable.begin(), d->runnable.end(), std::back_inserter( tmp ) );
coll->setTasks( tmp );
d->ensureWizardCreated();
d->wizard->setTaskCollection( coll );
Q_FOREACH( const shared_ptr<Task> & t, tmp )
connectTask( t );
d->schedule();
}
// ### extract to base
void SignEMailController::Private::schedule() {
if ( !cms )
if ( const shared_ptr<SignEMailTask> t = takeRunnable( CMS ) ) {
t->start();
cms = t;
}
if ( !openpgp )
if ( const shared_ptr<SignEMailTask> t = takeRunnable( OpenPGP ) ) {
t->start();
openpgp = t;
}
if ( !cms && !openpgp ) {
kleo_assert( runnable.empty() );
QPointer<QObject> Q = q;
Q_FOREACH( const shared_ptr<SignEMailTask> t, completed ) {
emit q->reportMicAlg( t->micAlg() );
if ( !Q )
return;
}
q->emitDoneOrError();
}
}
// ### extract to base
shared_ptr<SignEMailTask> SignEMailController::Private::takeRunnable( GpgME::Protocol proto ) {
const std::vector< shared_ptr<SignEMailTask> >::iterator it
= std::find_if( runnable.begin(), runnable.end(),
boost::bind( &Task::protocol, _1 ) == proto );
if ( it == runnable.end() )
return shared_ptr<SignEMailTask>();
const shared_ptr<SignEMailTask> result = *it;
runnable.erase( it );
return result;
}
// ### extract to base
void SignEMailController::doTaskDone( const Task * task, const shared_ptr<const Task::Result> & result )
{
Q_UNUSED( result );
assert( task );
// We could just delete the tasks here, but we can't use
// Qt::QueuedConnection here (we need sender()) and other slots
// might not yet have executed. Therefore, we push completed tasks
// into a burial container
if ( task == d->cms.get() ) {
d->completed.push_back( d->cms );
d->cms.reset();
} else if ( task == d->openpgp.get() ) {
d->completed.push_back( d->openpgp );
d->openpgp.reset();
}
QTimer::singleShot( 0, this, SLOT(schedule()) );
}
// ### extract to base
void SignEMailController::cancel() {
try {
if ( d->wizard )
d->wizard->close();
d->cancelAllJobs();
} catch ( const std::exception & e ) {
kDebug() << "Caught exception: " << e.what();
}
}
// ### extract to base
void SignEMailController::Private::cancelAllJobs() {
// we just kill all runnable tasks - this will not result in
// signal emissions.
runnable.clear();
// a cancel() will result in a call to
if ( cms )
cms->cancel();
if ( openpgp )
openpgp->cancel();
}
// ### extract to base
void SignEMailController::Private::ensureWizardCreated() {
if ( wizard )
return;
std::auto_ptr<SignEMailWizard> w( new SignEMailWizard );
w->setAttribute( Qt::WA_DeleteOnClose );
connect( w.get(), SIGNAL(signersResolved()), q, SLOT(slotWizardSignersResolved()), Qt::QueuedConnection );
connect( w.get(), SIGNAL(canceled()), q, SLOT(slotWizardCanceled()), Qt::QueuedConnection );
w->setPresetProtocol( protocol );
EMailOperationsPreferences prefs;
w->setQuickMode( prefs.quickSignEMail() );
wizard = w.release();
}
// ### extract to base
void SignEMailController::Private::ensureWizardVisible() {
ensureWizardCreated();
q->bringToForeground( wizard );
}
#include "moc_signemailcontroller.cpp"
diff --git a/crypto/signencryptfilescontroller.cpp b/crypto/signencryptfilescontroller.cpp
index 9d8295a2f..302d39b81 100644
--- a/crypto/signencryptfilescontroller.cpp
+++ b/crypto/signencryptfilescontroller.cpp
@@ -1,583 +1,583 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/signencryptfilescontroller.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2007 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include <config-kleopatra.h>
#include "signencryptfilescontroller.h"
#include "signencryptfilestask.h"
#include "certificateresolver.h"
#include <crypto/gui/newsignencryptfileswizard.h>
#include <crypto/taskcollection.h>
#include <utils/input.h>
#include <utils/output.h>
#include <utils/classify.h>
#include <utils/kleo_assert.h>
#include <utils/archivedefinition.h>
#include <kleo/stl_util.h>
#include <kleo/exception.h>
-#include <KMime/kmime_header_parsing.h>
+#include <kmime/kmime_header_parsing.h>
#include <KLocalizedString>
#include <kdebug.h>
#include <QPointer>
#include <QTimer>
#include <QFileInfo>
#include <boost/bind.hpp>
using namespace Kleo;
using namespace Kleo::Crypto;
using namespace Kleo::Crypto::Gui;
using namespace boost;
using namespace GpgME;
using namespace KMime::Types;
namespace {
struct is_dir : std::unary_function<QString,bool> {
bool operator()( const QString & file ) const {
return QFileInfo( file ).isDir();
}
};
}
static bool contains_dir( const QStringList & files ) {
return kdtools::any( files, is_dir() );
}
class SignEncryptFilesController::Private {
friend class ::Kleo::Crypto::SignEncryptFilesController;
SignEncryptFilesController * const q;
public:
explicit Private( SignEncryptFilesController * qq );
~Private();
private:
void slotWizardOperationPrepared();
void slotWizardCanceled();
private:
void ensureWizardCreated();
void ensureWizardVisible();
void updateWizardMode();
void cancelAllTasks();
void reportError( int err, const QString & details ) {
q->setLastError( err, details );
q->emitDoneOrError();
}
void schedule();
shared_ptr<SignEncryptFilesTask> takeRunnable( GpgME::Protocol proto );
static void assertValidOperation( unsigned int );
static QString titleForOperation( unsigned int op );
private:
std::vector< shared_ptr<SignEncryptFilesTask> > runnable, completed;
shared_ptr<SignEncryptFilesTask> cms, openpgp;
QPointer<NewSignEncryptFilesWizard> wizard;
QStringList files;
unsigned int operation;
Protocol protocol;
};
SignEncryptFilesController::Private::Private( SignEncryptFilesController * qq )
: q( qq ),
runnable(),
cms(),
openpgp(),
wizard(),
files(),
operation( SignAllowed|EncryptAllowed|ArchiveAllowed ),
protocol( UnknownProtocol )
{
}
SignEncryptFilesController::Private::~Private() { kDebug(); }
QString SignEncryptFilesController::Private::titleForOperation( unsigned int op ) {
const bool signDisallowed = (op & SignMask) == SignDisallowed;
const bool encryptDisallowed = (op & EncryptMask) == EncryptDisallowed;
const bool archiveForced = (op & ArchiveMask) == ArchiveForced;
kleo_assert( !signDisallowed || !encryptDisallowed );
if ( !signDisallowed && encryptDisallowed ) {
if ( archiveForced )
return i18n( "Archive and Sign Files" );
else
return i18n( "Sign Files" );
}
if ( signDisallowed && !encryptDisallowed ) {
if ( archiveForced )
return i18n( "Archive and Encrypt Files" );
else
return i18n( "Encrypt Files" );
}
if ( archiveForced )
return i18n( "Archive and Sign/Encrypt Files" );
else
return i18n( "Sign/Encrypt Files" );
}
SignEncryptFilesController::SignEncryptFilesController( QObject * p )
: Controller( p ), d( new Private( this ) )
{
}
SignEncryptFilesController::SignEncryptFilesController( const shared_ptr<const ExecutionContext> & ctx, QObject * p )
: Controller( ctx, p ), d( new Private( this ) )
{
}
SignEncryptFilesController::~SignEncryptFilesController() {
kDebug();
if ( d->wizard && !d->wizard->isVisible() )
delete d->wizard;
//d->wizard->close(); ### ?
}
void SignEncryptFilesController::setProtocol( Protocol proto ) {
kleo_assert( d->protocol == UnknownProtocol ||
d->protocol == proto );
d->protocol = proto;
d->ensureWizardCreated();
d->wizard->setPresetProtocol( proto );
}
Protocol SignEncryptFilesController::protocol() const {
return d->protocol;
}
// static
void SignEncryptFilesController::Private::assertValidOperation( unsigned int op ) {
kleo_assert( ( op & SignMask ) == SignDisallowed ||
( op & SignMask ) == SignAllowed ||
( op & SignMask ) == SignForced );
kleo_assert( ( op & EncryptMask ) == EncryptDisallowed ||
( op & EncryptMask ) == EncryptAllowed ||
( op & EncryptMask ) == EncryptForced );
kleo_assert( ( op & ArchiveMask ) == ArchiveDisallowed ||
( op & ArchiveMask ) == ArchiveAllowed ||
( op & ArchiveMask ) == ArchiveForced );
kleo_assert( ( op & ~(SignMask|EncryptMask|ArchiveMask) ) == 0 );
}
void SignEncryptFilesController::setOperationMode( unsigned int mode ) {
Private::assertValidOperation( mode );
if ( contains_dir( d->files ) )
mode = mode & ~ArchiveMask | ArchiveForced;
d->operation = mode;
d->updateWizardMode();
}
void SignEncryptFilesController::Private::updateWizardMode() {
if ( !wizard )
return;
wizard->setWindowTitle( titleForOperation( operation ) );
const unsigned int signOp = (operation & SignMask);
const unsigned int encrOp = (operation & EncryptMask);
const unsigned int archOp = (operation & ArchiveMask);
switch ( signOp ) {
case SignForced:
case SignDisallowed:
wizard->setSigningPreset( signOp == SignForced );
wizard->setSigningUserMutable( false );
break;
default:
assert( !"Should not happen" );
case SignAllowed:
wizard->setSigningPreset( encrOp == EncryptDisallowed );
wizard->setSigningUserMutable( true );
break;
}
switch ( encrOp ) {
case EncryptForced:
case EncryptDisallowed:
wizard->setEncryptionPreset( encrOp == EncryptForced );
wizard->setEncryptionUserMutable( false );
break;
default:
assert( !"Should not happen" );
case EncryptAllowed:
wizard->setEncryptionPreset( true );
wizard->setEncryptionUserMutable( true );
break;
}
switch ( archOp ) {
case ArchiveForced:
case ArchiveDisallowed:
wizard->setCreateArchivePreset( archOp == ArchiveForced );
wizard->setCreateArchiveUserMutable( false );
break;
default:
assert( !"Shouldn't happen" );
case ArchiveAllowed:
wizard->setCreateArchivePreset( false );
wizard->setEncryptionUserMutable( true );
break;
};
}
unsigned int SignEncryptFilesController::operationMode() const {
return d->operation;
}
void SignEncryptFilesController::setFiles( const QStringList & files ) {
kleo_assert( !files.empty() );
d->files = files;
if ( contains_dir( files ) )
setOperationMode( ( operationMode() & ~ArchiveMask ) | ArchiveForced );
d->ensureWizardCreated();
d->wizard->setFiles( files );
}
void SignEncryptFilesController::Private::slotWizardCanceled() {
kDebug();
reportError( gpg_error( GPG_ERR_CANCELED ), i18n("User cancel") );
}
void SignEncryptFilesController::start() {
d->ensureWizardVisible();
}
static const char * extension( bool pgp, bool sign, bool encrypt, bool ascii, bool detached ) {
unsigned int cls = pgp ? Class::OpenPGP : Class::CMS ;
if ( encrypt )
cls |= Class::CipherText;
else if ( sign )
cls |= detached ? Class::DetachedSignature : Class::OpaqueSignature ;
cls |= ascii ? Class::Ascii : Class::Binary ;
if ( const char * const ext = outputFileExtension( cls ) )
return ext;
else
return "out";
}
static shared_ptr<SignEncryptFilesTask>
createSignEncryptTaskForFileInfo( const QFileInfo & fi, bool pgp, bool sign, bool encrypt, bool ascii, bool removeUnencrypted, const std::vector<Key> & recipients, const std::vector<Key> & signers ) {
const shared_ptr<SignEncryptFilesTask> task( new SignEncryptFilesTask );
task->setSign( sign );
task->setEncrypt( encrypt );
task->setAsciiArmor( ascii );
task->setRemoveInputFileOnSuccess( removeUnencrypted );
if ( sign ) {
task->setSigners( signers );
task->setDetachedSignature( true );
}
if ( encrypt )
task->setRecipients( recipients );
const QString input = fi.absoluteFilePath();
task->setInputFileName( input );
task->setInput( Input::createFromFile( input ) );
const char * const ext = extension( pgp, sign, encrypt, ascii, true );
kleo_assert( ext );
const QString output = input + QLatin1Char('.') + QLatin1String(ext);
task->setOutputFileName( output );
return task;
}
static shared_ptr<SignEncryptFilesTask>
createArchiveSignEncryptTaskForFiles( const QStringList & files, const QString & outputFileBaseName, const shared_ptr<ArchiveDefinition> & ad, bool pgp, bool sign, bool encrypt, bool ascii, bool removeUnencrypted, const std::vector<Key> & recipients, const std::vector<Key> & signers ) {
const shared_ptr<SignEncryptFilesTask> task( new SignEncryptFilesTask );
task->setSign( sign );
task->setEncrypt( encrypt );
task->setAsciiArmor( ascii );
task->setRemoveInputFileOnSuccess( removeUnencrypted );
if ( sign ) {
task->setSigners( signers );
task->setDetachedSignature( false );
}
if ( encrypt )
task->setRecipients( recipients );
kleo_assert( ad );
const Protocol proto = pgp ? OpenPGP : CMS ;
task->setInputFileNames( files );
task->setInput( ad->createInputFromPackCommand( proto, files ) );
const char * const ext = extension( pgp, sign, encrypt, ascii, false );
kleo_assert( ext );
kleo_assert( !ad->extensions( proto ).empty() );
task->setOutputFileName( outputFileBaseName + QLatin1Char('.') + QLatin1String(ext) );
return task;
}
static std::vector< shared_ptr<SignEncryptFilesTask> >
createSignEncryptTasksForFileInfo( const QFileInfo & fi, bool sign, bool encrypt, bool ascii, bool removeUnencrypted, const std::vector<Key> & pgpRecipients, const std::vector<Key> & pgpSigners, const std::vector<Key> & cmsRecipients, const std::vector<Key> & cmsSigners ) {
std::vector< shared_ptr<SignEncryptFilesTask> > result;
const bool shallPgpSign = sign && !pgpSigners.empty();
const bool shallPgpEncrypt = encrypt && !pgpRecipients.empty();
const bool pgp = ( shallPgpEncrypt && ( !sign || shallPgpSign ) ) || ( !encrypt && shallPgpSign );
const bool shallCmsSign = sign && !cmsSigners.empty();
const bool shallCmsEncrypt = encrypt && !cmsRecipients.empty();
const bool cms = ( shallCmsEncrypt && ( !sign || shallCmsSign ) ) || ( !encrypt && shallCmsSign );
result.reserve( pgp + cms );
if ( pgp )
result.push_back( createSignEncryptTaskForFileInfo( fi, true, sign, encrypt, ascii, removeUnencrypted, pgpRecipients, pgpSigners ) );
if ( cms )
result.push_back( createSignEncryptTaskForFileInfo( fi, false, sign, encrypt, ascii, removeUnencrypted, cmsRecipients, cmsSigners ) );
return result;
}
static std::vector< shared_ptr<SignEncryptFilesTask> >
createArchiveSignEncryptTasksForFiles( const QStringList & files, const QString & pgpOutputFileBaseName, const QString & cmsOutputFileBaseName, const shared_ptr<ArchiveDefinition> & ad, bool sign, bool encrypt, bool ascii, bool removeUnencrypted, const std::vector<Key> & pgpRecipients, const std::vector<Key> & pgpSigners, const std::vector<Key> & cmsRecipients, const std::vector<Key> & cmsSigners ) {
std::vector< shared_ptr<SignEncryptFilesTask> > result;
const bool shallPgpSign = sign && !pgpSigners.empty();
const bool shallPgpEncrypt = encrypt && !pgpRecipients.empty();
const bool pgp = ( shallPgpEncrypt && ( !sign || shallPgpSign )) || ( !encrypt && shallPgpSign );
const bool shallCmsSign = sign && !cmsSigners.empty();
const bool shallCmsEncrypt = encrypt && !cmsRecipients.empty();
const bool cms = ( shallCmsEncrypt && ( !sign || shallCmsSign )) || ( !encrypt && shallCmsSign );
result.reserve( pgp + cms );
if ( pgp )
result.push_back( createArchiveSignEncryptTaskForFiles( files, pgpOutputFileBaseName, ad, true, sign, encrypt, ascii, removeUnencrypted, pgpRecipients, pgpSigners ) );
if ( cms )
result.push_back( createArchiveSignEncryptTaskForFiles( files, cmsOutputFileBaseName, ad, false, sign, encrypt, ascii, removeUnencrypted, cmsRecipients, cmsSigners ) );
return result;
}
void SignEncryptFilesController::Private::slotWizardOperationPrepared() {
try {
kleo_assert( wizard );
kleo_assert( !files.empty() );
const bool archive = wizard->isCreateArchiveSelected();
const bool sign = wizard->isSigningSelected();
const bool encrypt = wizard->isEncryptionSelected();
const bool ascii = wizard->isAsciiArmorEnabled();
const bool removeUnencrypted = wizard->isRemoveUnencryptedFilesEnabled();
std::vector<Key> pgpRecipients, cmsRecipients, pgpSigners, cmsSigners;
if ( encrypt ) {
const std::vector<Key> recipients = wizard->resolvedRecipients();
kdtools::copy_if( recipients.begin(), recipients.end(),
std::back_inserter( pgpRecipients ),
boost::bind( &Key::protocol, _1 ) == GpgME::OpenPGP );
kdtools::copy_if( recipients.begin(), recipients.end(),
std::back_inserter( cmsRecipients ),
boost::bind( &Key::protocol, _1 ) == GpgME::CMS );
kleo_assert( pgpRecipients.size() + cmsRecipients.size() == recipients.size() );
}
if ( sign ) {
const std::vector<Key> signers = wizard->resolvedSigners();
kdtools::copy_if( signers.begin(), signers.end(),
std::back_inserter( pgpSigners ),
boost::bind( &Key::protocol, _1 ) == GpgME::OpenPGP );
kdtools::copy_if( signers.begin(), signers.end(),
std::back_inserter( cmsSigners ),
boost::bind( &Key::protocol, _1 ) == GpgME::CMS );
kleo_assert( pgpSigners.size() + cmsSigners.size() == signers.size() );
}
std::vector< shared_ptr<SignEncryptFilesTask> > tasks;
if ( !archive )
tasks.reserve( files.size() );
if ( archive )
tasks = createArchiveSignEncryptTasksForFiles( files,
wizard->archiveFileName( OpenPGP ),
wizard->archiveFileName( CMS ),
wizard->selectedArchiveDefinition(),
sign, encrypt, ascii, removeUnencrypted,
pgpRecipients, pgpSigners, cmsRecipients, cmsSigners );
else
Q_FOREACH( const QString & file, files ) {
const std::vector< shared_ptr<SignEncryptFilesTask> > created =
createSignEncryptTasksForFileInfo( QFileInfo( file ), sign, encrypt, ascii, removeUnencrypted, pgpRecipients, pgpSigners, cmsRecipients, cmsSigners );
tasks.insert( tasks.end(), created.begin(), created.end() );
}
const shared_ptr<OverwritePolicy> overwritePolicy( new OverwritePolicy( wizard ) );
Q_FOREACH( const shared_ptr<SignEncryptFilesTask> & i, tasks )
i->setOverwritePolicy( overwritePolicy );
kleo_assert( runnable.empty() );
runnable.swap( tasks );
Q_FOREACH( const shared_ptr<Task> task, runnable )
q->connectTask( task );
shared_ptr<TaskCollection> coll( new TaskCollection );
std::vector<shared_ptr<Task> > tmp;
std::copy( runnable.begin(), runnable.end(), std::back_inserter( tmp ) );
coll->setTasks( tmp );
wizard->setTaskCollection( coll );
QTimer::singleShot( 0, q, SLOT(schedule()) );
} catch ( const Kleo::Exception & e ) {
reportError( e.error().encodedError(), e.message() );
} catch ( const std::exception & e ) {
reportError( gpg_error( GPG_ERR_UNEXPECTED ),
i18n("Caught unexpected exception in SignEncryptFilesController::Private::slotWizardOperationPrepared: %1",
QString::fromLocal8Bit( e.what() ) ) );
} catch ( ... ) {
reportError( gpg_error( GPG_ERR_UNEXPECTED ),
i18n("Caught unknown exception in SignEncryptFilesController::Private::slotWizardOperationPrepared") );
}
}
void SignEncryptFilesController::Private::schedule() {
if ( !cms )
if ( const shared_ptr<SignEncryptFilesTask> t = takeRunnable( CMS ) ) {
t->start();
cms = t;
}
if ( !openpgp )
if ( const shared_ptr<SignEncryptFilesTask> t = takeRunnable( OpenPGP ) ) {
t->start();
openpgp = t;
}
if ( !cms && !openpgp ) {
kleo_assert( runnable.empty() );
q->emitDoneOrError();
}
}
shared_ptr<SignEncryptFilesTask> SignEncryptFilesController::Private::takeRunnable( GpgME::Protocol proto ) {
const std::vector< shared_ptr<SignEncryptFilesTask> >::iterator it
= std::find_if( runnable.begin(), runnable.end(),
boost::bind( &Task::protocol, _1 ) == proto );
if ( it == runnable.end() )
return shared_ptr<SignEncryptFilesTask>();
const shared_ptr<SignEncryptFilesTask> result = *it;
runnable.erase( it );
return result;
}
void SignEncryptFilesController::doTaskDone( const Task * task, const shared_ptr<const Task::Result> & result )
{
Q_UNUSED( result )
assert( task );
// We could just delete the tasks here, but we can't use
// Qt::QueuedConnection here (we need sender()) and other slots
// might not yet have executed. Therefore, we push completed tasks
// into a burial container
if ( task == d->cms.get() ) {
d->completed.push_back( d->cms );
d->cms.reset();
} else if ( task == d->openpgp.get() ) {
d->completed.push_back( d->openpgp );
d->openpgp.reset();
}
QTimer::singleShot( 0, this, SLOT(schedule()) );
}
void SignEncryptFilesController::cancel() {
kDebug();
try {
if ( d->wizard )
d->wizard->close();
d->cancelAllTasks();
} catch ( const std::exception & e ) {
kDebug() << "Caught exception: " << e.what();
}
}
void SignEncryptFilesController::Private::cancelAllTasks() {
// we just kill all runnable tasks - this will not result in
// signal emissions.
runnable.clear();
// a cancel() will result in a call to
if ( cms )
cms->cancel();
if ( openpgp )
openpgp->cancel();
}
void SignEncryptFilesController::Private::ensureWizardCreated() {
if ( wizard )
return;
std::auto_ptr<NewSignEncryptFilesWizard> w( new NewSignEncryptFilesWizard );
w->setAttribute( Qt::WA_DeleteOnClose );
connect( w.get(), SIGNAL(operationPrepared()), q, SLOT(slotWizardOperationPrepared()), Qt::QueuedConnection );
connect( w.get(), SIGNAL(rejected()), q, SLOT(slotWizardCanceled()), Qt::QueuedConnection );
wizard = w.release();
updateWizardMode();
}
void SignEncryptFilesController::Private::ensureWizardVisible() {
ensureWizardCreated();
q->bringToForeground( wizard );
}
#include "moc_signencryptfilescontroller.cpp"
diff --git a/crypto/signencryptfilescontroller.h b/crypto/signencryptfilescontroller.h
index c97ae7c93..abc0c258f 100644
--- a/crypto/signencryptfilescontroller.h
+++ b/crypto/signencryptfilescontroller.h
@@ -1,104 +1,104 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/signencryptfilescontroller.h
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2007 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#ifndef __KLEOPATRA_CRYPTO_SIGNENCRYPTFILESCONTROLLER_H__
#define __KLEOPATRA_CRYPTO_SIGNENCRYPTFILESCONTROLLER_H__
#include <crypto/controller.h>
#include <utils/pimpl_ptr.h>
#include <gpgme++/global.h>
-#include <KMime/kmime_header_parsing.h>
+#include <kmime/kmime_header_parsing.h>
#include <boost/shared_ptr.hpp>
#include <vector>
namespace Kleo {
namespace Crypto {
class SignEncryptFilesController : public Controller {
Q_OBJECT
public:
explicit SignEncryptFilesController( QObject * parent=0 );
explicit SignEncryptFilesController( const boost::shared_ptr<const ExecutionContext> & ctx, QObject * parent=0 );
~SignEncryptFilesController();
void setProtocol( GpgME::Protocol proto );
GpgME::Protocol protocol() const;
//const char * protocolAsString() const;
enum Operation {
SignDisallowed = 0,
SignAllowed = 1,
SignForced = 2,
SignMask = SignAllowed|SignForced,
EncryptDisallowed = 0,
EncryptAllowed = 4,
EncryptForced = 8,
EncryptMask = EncryptAllowed|EncryptForced,
ArchiveDisallowed = 0,
ArchiveAllowed = 16,
ArchiveForced = 32,
ArchiveMask = ArchiveAllowed|ArchiveForced
};
void setOperationMode( unsigned int mode );
unsigned int operationMode() const;
void setFiles( const QStringList & files );
void start();
public Q_SLOTS:
void cancel();
private:
/* reimp */ void doTaskDone( const Task * task, const boost::shared_ptr<const Task::Result> & );
class Private;
kdtools::pimpl_ptr<Private> d;
Q_PRIVATE_SLOT( d, void slotWizardOperationPrepared() )
Q_PRIVATE_SLOT( d, void slotWizardCanceled() )
Q_PRIVATE_SLOT( d, void schedule() )
};
}
}
#endif /* __KLEOPATRA_UISERVER_SIGNENCRYPTFILESCONTROLLER_H__ */
diff --git a/crypto/verifychecksumscontroller.h b/crypto/verifychecksumscontroller.h
index 42b9877a6..5e069c8ea 100644
--- a/crypto/verifychecksumscontroller.h
+++ b/crypto/verifychecksumscontroller.h
@@ -1,78 +1,78 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/verifychecksumscontroller.h
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2010 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#ifndef __KLEOPATRA_CRYPTO_VERIFYCHECKSUMSCONTROLLER_H__
#define __KLEOPATRA_CRYPTO_VERIFYCHECKSUMSCONTROLLER_H__
#include <crypto/controller.h>
#ifndef QT_NO_DIRMODEL
#include <utils/pimpl_ptr.h>
#include <gpgme++/global.h>
-#include <KMime/kmime_header_parsing.h>
+#include <kmime/kmime_header_parsing.h>
#include <boost/shared_ptr.hpp>
#include <vector>
namespace Kleo {
namespace Crypto {
class VerifyChecksumsController : public Controller {
Q_OBJECT
public:
explicit VerifyChecksumsController( QObject * parent=0 );
explicit VerifyChecksumsController( const boost::shared_ptr<const ExecutionContext> & ctx, QObject * parent=0 );
~VerifyChecksumsController();
void setFiles( const QStringList & files );
void start();
public Q_SLOTS:
void cancel();
private:
class Private;
kdtools::pimpl_ptr<Private> d;
Q_PRIVATE_SLOT( d, void slotOperationFinished() )
};
}
}
#endif // QT_NO_DIRMODEL
#endif /* __KLEOPATRA_UISERVER_VERIFYCHECKSUMSCONTROLLER_H__ */
diff --git a/models/keycache.cpp b/models/keycache.cpp
index 65b08886d..f35600fb3 100644
--- a/models/keycache.cpp
+++ b/models/keycache.cpp
@@ -1,971 +1,971 @@
/* -*- mode: c++; c-basic-offset:4 -*-
models/keycache.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2007,2008 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include <config-kleopatra.h>
#include "keycache.h"
#include "keycache_p.h"
#include "predicates.h"
#include "smimevalidationpreferences.h"
#include <utils/filesystemwatcher.h>
#include <utils/progressmanager.h>
#include <kleo/stl_util.h>
#include <kleo/cryptobackendfactory.h>
#include <kleo/dn.h>
#include <kleo/keylistjob.h>
#include <kleo/listallkeysjob.h>
#include <gpgme++/error.h>
#include <gpgme++/key.h>
#include <gpgme++/decryptionresult.h>
#include <gpgme++/verificationresult.h>
#include <gpgme++/keylistresult.h>
#include <gpg-error.h>
-#include <KMime/kmime_header_parsing.h>
+#include <kmime/kmime_header_parsing.h>
#include <KLocalizedString>
#include <QPointer>
#include <QTimer>
#include <boost/bind.hpp>
#include <boost/mem_fn.hpp>
#include <boost/range.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/iterator/filter_iterator.hpp>
#include <utility>
#include <algorithm>
#include <functional>
#include <iterator>
using namespace Kleo;
using namespace GpgME;
using namespace boost;
using namespace KMime::Types;
static const unsigned int hours2ms = 1000 * 60 * 60;
//
//
// KeyCache
//
//
namespace {
make_comparator_str( ByEMail, .first.c_str() );
struct is_string_empty : std::unary_function<const char*,bool> {
bool operator()( const char * s ) const { return !s || !*s; }
};
}
class KeyCache::Private {
friend class ::Kleo::KeyCache;
KeyCache * const q;
public:
explicit Private( KeyCache * qq ) : q( qq ) {
connect( &m_autoKeyListingTimer, SIGNAL(timeout()), q, SLOT(startKeyListing()) );
updateAutoKeyListingTimer();
}
template < template <template <typename U> class Op> class Comp>
std::vector<Key>::const_iterator find( const std::vector<Key> & keys, const char * key ) const {
const std::vector<Key>::const_iterator it =
std::lower_bound( keys.begin(), keys.end(), key, Comp<std::less>() );
if ( it == keys.end() || Comp<std::equal_to>()( *it, key ) )
return it;
else
return keys.end();
}
template < template <template <typename U> class Op> class Comp>
std::vector<Subkey>::const_iterator find( const std::vector<Subkey> & keys, const char * key ) const {
const std::vector<Subkey>::const_iterator it =
std::lower_bound( keys.begin(), keys.end(), key, Comp<std::less>() );
if ( it == keys.end() || Comp<std::equal_to>()( *it, key ) )
return it;
else
return keys.end();
}
std::vector<Key>::const_iterator find_fpr( const char * fpr ) const {
return find<_detail::ByFingerprint>( by.fpr, fpr );
}
std::pair< std::vector< std::pair<std::string,Key> >::const_iterator,
std::vector< std::pair<std::string,Key> >::const_iterator >
find_email( const char * email ) const {
return std::equal_range( by.email.begin(), by.email.end(),
email, ByEMail<std::less>() );
}
std::vector<Key> find_mailbox( const Mailbox & mb, bool sign ) const;
std::vector<Subkey>::const_iterator find_subkeyid( const char * subkeyid ) const {
return find<_detail::ByKeyID>( by.subkeyid, subkeyid );
}
std::vector<Key>::const_iterator find_keyid( const char * keyid ) const {
return find<_detail::ByKeyID>( by.keyid, keyid );
}
std::vector<Key>::const_iterator find_shortkeyid( const char * shortkeyid ) const {
return find<_detail::ByShortKeyID>( by.shortkeyid, shortkeyid );
}
std::pair<
std::vector<Key>::const_iterator,
std::vector<Key>::const_iterator
> find_subjects( const char * chain_id ) const {
return std::equal_range( by.chainid.begin(), by.chainid.end(),
chain_id, _detail::ByChainID<std::less>() );
}
void refreshJobDone( const KeyListResult & result );
void updateAutoKeyListingTimer() {
setAutoKeyListingInterval( hours2ms * SMimeValidationPreferences().refreshInterval() );
}
void setAutoKeyListingInterval( int ms ) {
m_autoKeyListingTimer.stop();
m_autoKeyListingTimer.setInterval( ms );
if ( ms != 0 )
m_autoKeyListingTimer.start();
}
private:
QPointer<RefreshKeysJob> m_refreshJob;
std::vector<shared_ptr<FileSystemWatcher> > m_fsWatchers;
QTimer m_autoKeyListingTimer;
struct By {
std::vector<Key> fpr, keyid, shortkeyid, chainid;
std::vector< std::pair<std::string,Key> > email;
std::vector<Subkey> subkeyid;
} by;
};
shared_ptr<const KeyCache> KeyCache::instance() {
return mutableInstance();
}
shared_ptr<KeyCache> KeyCache::mutableInstance() {
static weak_ptr<KeyCache> self;
try {
return shared_ptr<KeyCache>( self );
} catch ( const bad_weak_ptr & ) {
const shared_ptr<KeyCache> s( new KeyCache );
self = s;
return s;
}
}
KeyCache::KeyCache()
: QObject(), d( new Private( this ) )
{
}
KeyCache::~KeyCache() {}
void KeyCache::enableFileSystemWatcher( bool enable )
{
Q_FOREACH( const shared_ptr<FileSystemWatcher> & i, d->m_fsWatchers )
i->setEnabled( enable );
}
void KeyCache::reload( GpgME::Protocol /*proto*/ )
{
if ( d->m_refreshJob )
return;
d->updateAutoKeyListingTimer();
enableFileSystemWatcher( false );
d->m_refreshJob = new RefreshKeysJob( this );
connect( d->m_refreshJob, SIGNAL(done(GpgME::KeyListResult)), this, SLOT(refreshJobDone(GpgME::KeyListResult)) );
d->m_refreshJob->start();
}
void KeyCache::cancelKeyListing()
{
if ( !d->m_refreshJob )
return;
d->m_refreshJob->cancel();
}
void KeyCache::addFileSystemWatcher( const shared_ptr<FileSystemWatcher>& watcher )
{
if ( !watcher )
return;
d->m_fsWatchers.push_back( watcher );
connect( watcher.get(), SIGNAL(directoryChanged(QString)),
this, SLOT(startKeyListing()) );
connect( watcher.get(), SIGNAL(fileChanged(QString)),
this, SLOT(startKeyListing()) );
watcher->setEnabled( d->m_refreshJob == 0 );
}
void KeyCache::Private::refreshJobDone( const KeyListResult& result )
{
emit q->keyListingDone( result );
q->enableFileSystemWatcher( true );
}
const Key & KeyCache::findByFingerprint( const char * fpr ) const {
const std::vector<Key>::const_iterator it = d->find_fpr( fpr );
if ( it == d->by.fpr.end() ) {
static const Key null;
return null;
} else {
return *it;
}
}
std::vector<Key> KeyCache::findByFingerprint( const std::vector<std::string> & fprs ) const {
std::vector<std::string> sorted;
sorted.reserve( fprs.size() );
std::remove_copy_if( fprs.begin(), fprs.end(), std::back_inserter( sorted ),
boost::bind( is_string_empty(), boost::bind( &std::string::c_str, _1 ) ) );
std::sort( sorted.begin(), sorted.end(), _detail::ByFingerprint<std::less>() );
std::vector<Key> result;
kdtools::set_intersection( d->by.fpr.begin(), d->by.fpr.end(),
sorted.begin(), sorted.end(),
std::back_inserter( result ),
_detail::ByFingerprint<std::less>() );
return result;
}
std::vector<Key> KeyCache::findByEMailAddress( const char * email ) const {
const std::pair<
std::vector< std::pair<std::string,Key> >::const_iterator,
std::vector< std::pair<std::string,Key> >::const_iterator
> pair = d->find_email( email );
std::vector<Key> result;
result.reserve( std::distance( pair.first, pair.second ) );
std::transform( pair.first, pair.second,
std::back_inserter( result ),
boost::bind( &std::pair<std::string,Key>::second, _1 ) );
return result;
}
std::vector<Key> KeyCache::findByEMailAddress( const std::string & email ) const {
return findByEMailAddress( email.c_str() );
}
const Key & KeyCache::findByShortKeyID( const char * id ) const {
const std::vector<Key>::const_iterator it = d->find_shortkeyid( id );
if ( it != d->by.shortkeyid.end() )
return *it;
static const Key null;
return null;
}
const Key & KeyCache::findByKeyIDOrFingerprint( const char * id ) const {
{
// try by.fpr first:
const std::vector<Key>::const_iterator it = d->find_fpr( id );
if ( it != d->by.fpr.end() )
return *it;
}{
// try by.keyid next:
const std::vector<Key>::const_iterator it = d->find_keyid( id );
if ( it != d->by.keyid.end() )
return *it;
}
static const Key null;
return null;
}
std::vector<Key> KeyCache::findByKeyIDOrFingerprint( const std::vector<std::string> & ids ) const {
std::vector<std::string> keyids;
std::remove_copy_if( ids.begin(), ids.end(), std::back_inserter( keyids ),
boost::bind( is_string_empty(), boost::bind( &std::string::c_str, _1 ) ) );
// this is just case-insensitive string search:
std::sort( keyids.begin(), keyids.end(), _detail::ByFingerprint<std::less>() );
std::vector<Key> result;
result.reserve( keyids.size() ); // dups shouldn't happen
kdtools::set_intersection( d->by.fpr.begin(), d->by.fpr.end(),
keyids.begin(), keyids.end(),
std::back_inserter( result ),
_detail::ByFingerprint<std::less>() );
if ( result.size() < keyids.size() ) {
// note that By{Fingerprint,KeyID,ShortKeyID} define the same
// order for _strings_
kdtools::set_intersection( d->by.keyid.begin(), d->by.keyid.end(),
keyids.begin(), keyids.end(),
std::back_inserter( result ),
_detail::ByKeyID<std::less>() );
}
// duplicates shouldn't happen, but make sure nonetheless:
std::sort( result.begin(), result.end(), _detail::ByFingerprint<std::less>() );
result.erase( std::unique( result.begin(), result.end(), _detail::ByFingerprint<std::equal_to>() ), result.end() );
// we skip looking into short key ids here, as it's highly
// unlikely they're used for this purpose. We might need to revise
// this decision, but only after testing.
return result;
}
std::vector<Subkey> KeyCache::findSubkeysByKeyID( const std::vector<std::string> & ids ) const {
std::vector<std::string> sorted;
sorted.reserve( ids.size() );
std::remove_copy_if( ids.begin(), ids.end(), std::back_inserter( sorted ),
boost::bind( is_string_empty(), boost::bind( &std::string::c_str, _1 ) ) );
std::sort( sorted.begin(), sorted.end(), _detail::ByKeyID<std::less>() );
std::vector<Subkey> result;
kdtools::set_intersection( d->by.subkeyid.begin(), d->by.subkeyid.end(),
sorted.begin(), sorted.end(),
std::back_inserter( result ),
_detail::ByKeyID<std::less>() );
return result;
}
std::vector<Key> KeyCache::findRecipients( const DecryptionResult & res ) const {
std::vector<std::string> keyids;
Q_FOREACH( const DecryptionResult::Recipient & r, res.recipients() )
if ( const char * kid = r.keyID() )
keyids.push_back( kid );
const std::vector<Subkey> subkeys = findSubkeysByKeyID( keyids );
std::vector<Key> result;
result.reserve( subkeys.size() );
std::transform( subkeys.begin(), subkeys.end(), std::back_inserter( result ), boost::bind( &Subkey::parent, _1 ) );
std::sort( result.begin(), result.end(), _detail::ByFingerprint<std::less>() );
result.erase( std::unique( result.begin(), result.end(), _detail::ByFingerprint<std::equal_to>() ), result.end() );
return result;
}
std::vector<Key> KeyCache::findSigners( const VerificationResult & res ) const {
std::vector<std::string> fprs;
Q_FOREACH( const Signature & s, res.signatures() )
if ( const char * fpr = s.fingerprint() )
fprs.push_back( fpr );
return findByKeyIDOrFingerprint( fprs );
}
std::vector<Key> KeyCache::findSigningKeysByMailbox( const Mailbox & mb ) const {
return d->find_mailbox( mb, true );
}
std::vector<Key> KeyCache::findEncryptionKeysByMailbox( const Mailbox & mb ) const {
return d->find_mailbox( mb, false );
}
namespace {
#define DO( op, meth, meth2 ) if ( op key.meth() ) {} else { qDebug( "rejecting for signing: %s: %s", #meth2, key.primaryFingerprint() ); return false; }
#define ACCEPT( meth ) DO( !!, meth, !meth )
#define REJECT( meth ) DO( !, meth, meth )
struct ready_for_signing : std::unary_function<Key,bool> {
bool operator()( const Key & key ) const {
#if 1
ACCEPT( hasSecret );
ACCEPT( canReallySign );
REJECT( isRevoked );
REJECT( isExpired );
REJECT( isDisabled );
REJECT( isInvalid );
return true;
#else
return key.hasSecret() &&
key.canReallySign() && !key.isRevoked() && !key.isExpired() && !key.isDisabled() && !key.isInvalid() ;
#endif
#undef DO
}
};
struct ready_for_encryption : std::unary_function<Key,bool> {
#define DO( op, meth, meth2 ) if ( op key.meth() ) {} else { qDebug( "rejecting for encrypting: %s: %s", #meth2, key.primaryFingerprint() ); return false; }
bool operator()( const Key & key ) const {
#if 1
ACCEPT( canEncrypt );
REJECT( isRevoked );
REJECT( isExpired );
REJECT( isDisabled );
REJECT( isInvalid );
return true;
#else
return
key.canEncrypt() && !key.isRevoked() && !key.isExpired() && !key.isDisabled() && !key.isInvalid() ;
#endif
}
#undef DO
#undef ACCEPT
#undef REJECT
};
}
std::vector<Key> KeyCache::Private::find_mailbox( const Mailbox & mb, bool sign ) const {
const QString email = mb.addrSpec().asString();
if ( email.isEmpty() )
return std::vector<Key>();
const std::pair<
std::vector< std::pair<std::string,Key> >::const_iterator,
std::vector< std::pair<std::string,Key> >::const_iterator
> pair = find_email( email.toUtf8().constData() );
std::vector<Key> result;
result.reserve( std::distance( pair.first, pair.second ) );
if ( sign )
kdtools::copy_2nd_if( pair.first, pair.second,
std::back_inserter( result ),
ready_for_signing() );
else
kdtools::copy_2nd_if( pair.first, pair.second,
std::back_inserter( result ),
ready_for_encryption() );
return result;
}
std::vector<Key> KeyCache::findSubjects( const GpgME::Key & key, Options options ) const {
return findSubjects( std::vector<Key>( 1, key ), options );
}
std::vector<Key> KeyCache::findSubjects( const std::vector<Key> & keys, Options options ) const {
return findSubjects( keys.begin(), keys.end(), options );
}
std::vector<Key> KeyCache::findSubjects( std::vector<Key>::const_iterator first, std::vector<Key>::const_iterator last, Options options ) const {
if ( first == last )
return std::vector<Key>();
std::vector<Key> result;
while ( first != last ) {
const std::pair<
std::vector<Key>::const_iterator,
std::vector<Key>::const_iterator
> pair = d->find_subjects( first->primaryFingerprint() );
result.insert( result.end(), pair.first, pair.second );
++first;
}
std::sort( result.begin(), result.end(), _detail::ByFingerprint<std::less>() );
result.erase( std::unique( result.begin(), result.end(), _detail::ByFingerprint<std::equal_to>() ), result.end() );
if ( options & RecursiveSearch ) {
const std::vector<Key> furtherSubjects = findSubjects( result, options );
std::vector<Key> combined;
combined.reserve( result.size() + furtherSubjects.size() );
std::merge( result.begin(), result.end(),
furtherSubjects.begin(), furtherSubjects.end(),
std::back_inserter( combined ),
_detail::ByFingerprint<std::less>() );
combined.erase( std::unique( combined.begin(), combined.end(), _detail::ByFingerprint<std::equal_to>() ), combined.end() );
result.swap( combined );
}
return result;
}
static const unsigned int LIKELY_CHAIN_DEPTH = 3;
std::vector<Key> KeyCache::findIssuers( const Key & key, Options options ) const {
if ( key.isNull() )
return std::vector<Key>();
std::vector<Key> result;
if ( options & IncludeSubject )
result.push_back( key );
if ( key.isRoot() )
return result;
const Key & issuer = findByFingerprint( key.chainID() );
if ( issuer.isNull() )
return result;
result.push_back( issuer );
if ( !( options & RecursiveSearch ) )
return result;
while ( !result.back().isNull() && !result.back().isRoot() )
result.push_back( findByFingerprint( result.back().chainID() ) );
if ( result.back().isNull() )
result.pop_back();
return result;
}
std::vector<Key> KeyCache::findIssuers( const std::vector<Key> & keys, Options options ) const {
return findIssuers( keys.begin(), keys.end(), options );
}
std::vector<Key> KeyCache::findIssuers( std::vector<Key>::const_iterator first, std::vector<Key>::const_iterator last, Options options ) const {
if ( first == last )
return std::vector<Key>();
// extract chain-ids, identifying issuers:
std::vector<const char *> chainIDs;
chainIDs.reserve( last - first );
std::transform( boost::make_filter_iterator( !boost::bind( &Key::isRoot, _1 ), first, last ),
boost::make_filter_iterator( !boost::bind( &Key::isRoot, _1 ), last, last ),
std::back_inserter( chainIDs ),
boost::bind( &Key::chainID, _1 ) );
std::sort( chainIDs.begin(), chainIDs.end(), _detail::ByFingerprint<std::less>() );
const std::vector<const char*>::iterator lastUniqueChainID = std::unique( chainIDs.begin(), chainIDs.end(), _detail::ByFingerprint<std::less>() );
std::vector<Key> result;
result.reserve( lastUniqueChainID - chainIDs.begin() );
kdtools::set_intersection( d->by.fpr.begin(), d->by.fpr.end(),
chainIDs.begin(), lastUniqueChainID,
std::back_inserter( result ),
_detail::ByFingerprint<std::less>() );
if ( options & IncludeSubject ) {
const unsigned int rs = result.size();
result.insert( result.end(), first, last );
std::inplace_merge( result.begin(), result.begin() + rs, result.end(),
_detail::ByFingerprint<std::less>() );
}
if ( !( options & RecursiveSearch ) )
return result;
const std::vector<Key> l2result = findIssuers( result, options & ~IncludeSubject );
const unsigned long result_size = result.size();
result.insert( result.end(), l2result.begin(), l2result.end() );
std::inplace_merge( result.begin(), result.begin() + result_size, result.end(),
_detail::ByFingerprint<std::less>() );
return result;
}
static std::string email( const UserID & uid ) {
const std::string email = uid.email();
if ( email.empty() )
return DN( uid.id() )[QLatin1String("EMAIL")].trimmed().toUtf8().constData();
if ( email[0] == '<' && email[email.size()-1] == '>' )
return email.substr( 1, email.size() - 2 );
else
return email;
}
static std::vector<std::string> emails( const Key & key ) {
std::vector<std::string> emails;
Q_FOREACH( const UserID & uid, key.userIDs() ) {
const std::string e = email( uid );
if ( !e.empty() )
emails.push_back( e );
}
std::sort( emails.begin(), emails.end(), ByEMail<std::less>() );
emails.erase( std::unique( emails.begin(), emails.end(), ByEMail<std::equal_to>() ), emails.end() );
return emails;
}
void KeyCache::remove( const Key & key ) {
if ( key.isNull() )
return;
const char * fpr = key.primaryFingerprint();
if ( !fpr )
return;
emit aboutToRemove( key );
{
const std::pair<std::vector<Key>::iterator,std::vector<Key>::iterator> range
= std::equal_range( d->by.fpr.begin(), d->by.fpr.end(), fpr,
_detail::ByFingerprint<std::less>() );
d->by.fpr.erase( range.first, range.second );
}
if ( const char * keyid = key.keyID() ) {
const std::pair<std::vector<Key>::iterator,std::vector<Key>::iterator> range
= std::equal_range( d->by.keyid.begin(), d->by.keyid.end(), keyid,
_detail::ByKeyID<std::less>() );
const std::vector<Key>::iterator it
= std::remove_if( begin( range ), end( range ), boost::bind( _detail::ByFingerprint<std::equal_to>(), fpr, _1 ) );
d->by.keyid.erase( it, end( range ) );
}
if ( const char * shortkeyid = key.shortKeyID() ) {
const std::pair<std::vector<Key>::iterator,std::vector<Key>::iterator> range
= std::equal_range( d->by.shortkeyid.begin(), d->by.shortkeyid.end(), shortkeyid,
_detail::ByShortKeyID<std::less>() );
const std::vector<Key>::iterator it
= std::remove_if( begin( range ), end( range ), boost::bind( _detail::ByFingerprint<std::equal_to>(), fpr, _1 ) );
d->by.shortkeyid.erase( it, end( range ) );
}
if ( const char * chainid = key.chainID() ) {
const std::pair<std::vector<Key>::iterator,std::vector<Key>::iterator> range
= std::equal_range( d->by.chainid.begin(), d->by.chainid.end(), chainid,
_detail::ByChainID<std::less>() );
const std::pair< std::vector<Key>::iterator, std::vector<Key>::iterator > range2
= std::equal_range( begin( range ), end( range ), fpr, _detail::ByFingerprint<std::less>() );
d->by.chainid.erase( begin( range2 ), end( range2 ) );
}
Q_FOREACH( const std::string & email, emails( key ) ) {
const std::pair<std::vector<std::pair<std::string,Key> >::iterator,std::vector<std::pair<std::string,Key> >::iterator> range
= std::equal_range( d->by.email.begin(), d->by.email.end(), email, ByEMail<std::less>() );
const std::vector< std::pair<std::string,Key> >::iterator it
= std::remove_if( begin( range ), end( range ), boost::bind( qstricmp, fpr, boost::bind( &Key::primaryFingerprint, boost::bind( &std::pair<std::string,Key>::second,_1 ) ) ) == 0 );
d->by.email.erase( it, end( range ) );
}
Q_FOREACH( const Subkey & subkey, key.subkeys() ) {
if ( const char * keyid = subkey.keyID() ) {
const std::pair<std::vector<Subkey>::iterator,std::vector<Subkey>::iterator> range
= std::equal_range( d->by.subkeyid.begin(), d->by.subkeyid.end(), keyid,
_detail::ByKeyID<std::less>() );
const std::pair< std::vector<Subkey>::iterator, std::vector<Subkey>::iterator > range2
= std::equal_range( begin( range ), end( range ), fpr, _detail::ByKeyID<std::less>() );
d->by.subkeyid.erase( begin( range2 ), end( range2 ) );
}
}
}
void KeyCache::remove( const std::vector<Key> & keys ) {
Q_FOREACH( const Key & key, keys )
remove( key );
}
const std::vector<GpgME::Key> & KeyCache::keys() const
{
return d->by.fpr;
}
std::vector<Key> KeyCache::secretKeys() const
{
std::vector<Key> keys = this->keys();
keys.erase( std::remove_if( keys.begin(), keys.end(), !boost::bind( &Key::hasSecret, _1 ) ), keys.end() );
return keys;
}
void KeyCache::refresh( const std::vector<Key> & keys ) {
// make this better...
clear();
insert( keys );
}
void KeyCache::insert( const Key & key ) {
insert( std::vector<Key>( 1, key ) );
}
namespace {
template <
template <template <typename T> class Op> class T1,
template <template <typename T> class Op> class T2
> struct lexicographically {
typedef bool result_type;
template <typename U, typename V>
bool operator()( const U & lhs, const V & rhs ) const {
return
T1<std::less>()( lhs, rhs ) ||
( T1<std::equal_to>()( lhs, rhs ) &&
T2<std::less>()( lhs, rhs ) )
;
}
};
}
void KeyCache::insert( const std::vector<Key> & keys ) {
// 1. remove those with empty fingerprints:
std::vector<Key> sorted;
sorted.reserve( keys.size() );
std::remove_copy_if( keys.begin(), keys.end(),
std::back_inserter( sorted ),
boost::bind( is_string_empty(), boost::bind( &Key::primaryFingerprint, _1 ) ) );
Q_FOREACH( const Key & key, sorted )
remove( key ); // this is sub-optimal, but makes implementation from here on much easier
// 2. sort by fingerprint:
std::sort( sorted.begin(), sorted.end(), _detail::ByFingerprint<std::less>() );
// 2a. insert into fpr index:
std::vector<Key> by_fpr;
by_fpr.reserve( sorted.size() + d->by.fpr.size() );
std::merge( sorted.begin(), sorted.end(),
d->by.fpr.begin(), d->by.fpr.end(),
std::back_inserter( by_fpr ),
_detail::ByFingerprint<std::less>() );
// 3. build email index:
std::vector< std::pair<std::string,Key> > pairs;
pairs.reserve( sorted.size() );
Q_FOREACH( const Key & key, sorted ) {
const std::vector<std::string> emails = ::emails( key );
Q_FOREACH( const std::string & e, emails )
pairs.push_back( std::make_pair( e, key ) );
}
std::sort( pairs.begin(), pairs.end(), ByEMail<std::less>() );
// 3a. insert into email index:
std::vector< std::pair<std::string,Key> > by_email;
by_email.reserve( pairs.size() + d->by.email.size() );
std::merge( pairs.begin(), pairs.end(),
d->by.email.begin(), d->by.email.end(),
std::back_inserter( by_email ),
ByEMail<std::less>() );
// 3.5: stable-sort by chain-id (effectively lexicographically<ByChainID,ByFingerprint>)
std::stable_sort( sorted.begin(), sorted.end(), _detail::ByChainID<std::less>() );
// 3.5a: insert into chain-id index:
std::vector<Key> by_chainid;
by_chainid.reserve( sorted.size() + d->by.chainid.size() );
std::merge( boost::make_filter_iterator( !boost::bind( &Key::isRoot, _1 ), sorted.begin(), sorted.end() ),
boost::make_filter_iterator( !boost::bind( &Key::isRoot, _1 ), sorted.end(), sorted.end() ),
d->by.chainid.begin(), d->by.chainid.end(),
std::back_inserter( by_chainid ),
lexicographically<_detail::ByChainID,_detail::ByFingerprint>() );
// 4. sort by key id:
std::sort( sorted.begin(), sorted.end(), _detail::ByKeyID<std::less>() );
// 4a. insert into keyid index:
std::vector<Key> by_keyid;
by_keyid.reserve( sorted.size() + d->by.keyid.size() );
std::merge( sorted.begin(), sorted.end(),
d->by.keyid.begin(), d->by.keyid.end(),
std::back_inserter( by_keyid ),
_detail::ByKeyID<std::less>() );
// 5. sort by short key id:
std::sort( sorted.begin(), sorted.end(), _detail::ByShortKeyID<std::less>() );
// 5a. insert into short keyid index:
std::vector<Key> by_shortkeyid;
by_shortkeyid.reserve( sorted.size() + d->by.shortkeyid.size() );
std::merge( sorted.begin(), sorted.end(),
d->by.shortkeyid.begin(), d->by.shortkeyid.end(),
std::back_inserter( by_shortkeyid ),
_detail::ByShortKeyID<std::less>() );
// 6. build subkey ID index:
std::vector<Subkey> subkeys;
subkeys.reserve( sorted.size() );
Q_FOREACH( const Key & key, sorted )
Q_FOREACH( const Subkey & subkey, key.subkeys() )
subkeys.push_back( subkey );
// 6a sort by key id:
std::sort( subkeys.begin(), subkeys.end(), _detail::ByKeyID<std::less>() );
// 6b. insert into subkey ID index:
std::vector<Subkey> by_subkeyid;
by_email.reserve( subkeys.size() + d->by.subkeyid.size() );
std::merge( subkeys.begin(), subkeys.end(),
d->by.subkeyid.begin(), d->by.subkeyid.end(),
std::back_inserter( by_subkeyid ),
_detail::ByKeyID<std::less>() );
// now commit (well, we already removed keys...)
by_fpr.swap( d->by.fpr );
by_keyid.swap( d->by.keyid );
by_shortkeyid.swap( d->by.shortkeyid );
by_email.swap( d->by.email );
by_subkeyid.swap( d->by.subkeyid );
by_chainid.swap( d->by.chainid );
Q_FOREACH( const Key & key, sorted )
emit added( key );
emit keysMayHaveChanged();
}
void KeyCache::clear() {
d->by = Private::By();
}
//
//
// RefreshKeysJob
//
//
class KeyCache::RefreshKeysJob::Private
{
RefreshKeysJob * const q;
public:
Private( KeyCache * cache, RefreshKeysJob * qq );
void doStart();
Error startKeyListing( const char* protocol );
void listAllKeysJobDone( const KeyListResult & res, const std::vector<Key> & nextKeys ) {
std::vector<Key> keys;
keys.reserve( m_keys.size() + nextKeys.size() );
if ( m_keys.empty() )
keys = nextKeys;
else
std::merge( m_keys.begin(), m_keys.end(),
nextKeys.begin(), nextKeys.end(),
std::back_inserter( keys ),
_detail::ByFingerprint<std::less>() );
m_keys.swap( keys );
jobDone( res );
}
void emitDone( const KeyListResult & result );
void updateKeyCache();
KeyCache * m_cache;
uint m_jobsPending;
std::vector<Key> m_keys;
KeyListResult m_mergedResult;
private:
void jobDone( const KeyListResult & res );
};
KeyCache::RefreshKeysJob::Private::Private( KeyCache * cache, RefreshKeysJob * qq ) : q( qq ), m_cache( cache ), m_jobsPending( 0 )
{
assert( m_cache );
}
void KeyCache::RefreshKeysJob::Private::jobDone( const KeyListResult & result )
{
QObject* const sender = q->sender();
if ( sender )
sender->disconnect( q );
assert( m_jobsPending > 0 );
--m_jobsPending;
m_mergedResult.mergeWith( result );
if ( m_jobsPending > 0 )
return;
updateKeyCache();
emitDone( m_mergedResult );
}
void KeyCache::RefreshKeysJob::Private::emitDone( const KeyListResult & res )
{
q->deleteLater();
emit q->done( res );
}
KeyCache::RefreshKeysJob::RefreshKeysJob( KeyCache * cache, QObject * parent ) : QObject( parent ), d( new Private( cache, this ) )
{
}
KeyCache::RefreshKeysJob::~RefreshKeysJob() {}
void KeyCache::RefreshKeysJob::start()
{
QTimer::singleShot( 0, this, SLOT(doStart()) );
}
void KeyCache::RefreshKeysJob::cancel()
{
emit canceled();
}
void KeyCache::RefreshKeysJob::Private::doStart()
{
assert( m_jobsPending == 0 );
m_mergedResult.mergeWith( KeyListResult( startKeyListing( "openpgp" ) ) );
m_mergedResult.mergeWith( KeyListResult( startKeyListing( "smime" ) ) );
if ( m_jobsPending != 0 )
return;
const bool hasError = m_mergedResult.error() || m_mergedResult.error().isCanceled();
emitDone( hasError ? m_mergedResult : KeyListResult( Error( GPG_ERR_UNSUPPORTED_OPERATION ) ) );
}
void KeyCache::RefreshKeysJob::Private::updateKeyCache()
{
std::vector<Key> cachedKeys = m_cache->keys();
std::sort( cachedKeys.begin(), cachedKeys.end(), _detail::ByFingerprint<std::less>() );
std::vector<Key> keysToRemove;
std::set_difference( cachedKeys.begin(), cachedKeys.end(),
m_keys.begin(), m_keys.end(),
std::back_inserter( keysToRemove ),
_detail::ByFingerprint<std::less>() );
m_cache->remove( keysToRemove );
m_cache->refresh( m_keys );
}
Error KeyCache::RefreshKeysJob::Private::startKeyListing( const char* backend )
{
const Kleo::CryptoBackend::Protocol * const protocol = Kleo::CryptoBackendFactory::instance()->protocol( backend );
if ( !protocol )
return Error();
Kleo::ListAllKeysJob * const job = protocol->listAllKeysJob( /*includeSigs*/false, /*validate*/true );
if ( !job )
return Error();
connect( job, SIGNAL(result(GpgME::KeyListResult,std::vector<GpgME::Key>)),
q, SLOT(listAllKeysJobDone(GpgME::KeyListResult,std::vector<GpgME::Key>)) );
const QString label = protocol == Kleo::CryptoBackendFactory::instance()->smime()
? i18n("Listing X.509 certificates")
: i18n("Listing OpenPGP certificates") ;
(void)ProgressManager::createForJob( job, label );
connect( q, SIGNAL(canceled()),
job, SLOT(slotCancel()) );
const Error error = job->start( true );
if ( !error && !error.isCanceled() )
++m_jobsPending;
return error;
}
#include "moc_keycache_p.cpp"
#include "moc_keycache.cpp"
diff --git a/uiserver/assuancommand.h b/uiserver/assuancommand.h
index f737b5570..0dc262331 100644
--- a/uiserver/assuancommand.h
+++ b/uiserver/assuancommand.h
@@ -1,374 +1,374 @@
/* -*- mode: c++; c-basic-offset:4 -*-
uiserver/assuancommand.h
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2007 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#ifndef __KLEOPATRA_UISERVER_ASSUANCOMMAND_H__
#define __KLEOPATRA_UISERVER_ASSUANCOMMAND_H__
#include <utils/pimpl_ptr.h>
#include <utils/types.h>
#include <gpgme++/global.h>
#include <gpgme++/error.h>
#ifdef HAVE_ASSUAN2
#include <gpg-error.h>
#endif
-#include <KMime/kmime_header_parsing.h>
+#include <kmime/kmime_header_parsing.h>
#include <qwindowdefs.h> // for WId
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <string>
#include <map>
#include <vector>
class QVariant;
class QIODevice;
class QObject;
class QStringList;
class QDialog;
class QFile;
struct assuan_context_s;
namespace Kleo {
class Input;
class Output;
class AssuanCommandFactory;
/*!
\brief Base class for GnuPG UI Server commands
\note large parts of this are outdated by now!
<h3>Implementing a new AssuanCommand</h3>
You do not directly inherit AssuanCommand, unless you want to
deal with implementing low-level, repetetive things like name()
in terms of staticName(). Assuming you don't, then you inherit
your command class from AssuanCommandMixin, passing your class
as the template argument to AssuanCommandMixin, like this:
\code
class MyFooCommand : public AssuanCommandMixin<MyFooCommand> {
\endcode
(http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)
You then choose a command name, and return that from the static
method staticName(), which is by convention queried by both
AssuanCommandMixin<> and GenericAssuanCommandFactory<>:
\code
static const char * staticName() { return "MYFOO"; }
\endcode
The string should be all-uppercase by convention, but the
UiServer implementation doesn't enforce this.
The next step is to implement start(), the starting point of
command execution:
<h3>Executing the command</h3>
\code
int start( const std::string & line ) {
\endcode
This should set everything up and check the parameters in \a
line and any options this command understands. If there's an
error, choose one of the gpg-error codes and create a
gpg_error_t from it using the protected makeError() function:
\code
return makeError( GPG_ERR_NOT_IMPLEMENTED );
\endcode
But usually, you will want to create a dialog, or call some
GpgME function from here. In case of errors from GpgME, you
shouldn't pipe them through makeError(), but return them
as-is. This will preserve the error source. Error created using
makeError() will have Kleopatra as their error source, so watch
out what you're doing :)
In addition to options and the command line, your command might
require \em{bulk data} input or output. That's what the bulk
input and output channels are for. You can check whether the
client handed you an input channel by checking that
bulkInputDevice() isn't NULL, likewise for bulkOutputDevice().
If everything is ok, you return 0. This indicates to the client
that the command has been accepted and is now in progress.
In this mode (start() returned 0), there are a bunch of options
for your command to do. Some commands may require additional
information from the client. The options passed to start() are
designed to be persistent across commands, and rather limited in
length (there's a strict line length limit in the assuan
protocol with no line continuation mechanism). The same is true
for command line arguments, which, in addition, you have to
parse yourself. Those usually apply only to this command, and
not to following ones.
If you need data that might be larger than the line length
limit, you can either expect it on the bulkInputDevice(), or, if
you have the need for more than one such data channel, or the
data is optional or conditional on some condition that can only
be determined during command execution, you can \em inquire the
missing information from the client.
As an example, a VERIFY command would expect the signed data on
the bulkInputDevice(). But if the input stream doesn't contain
an embedded (opaque) signature, indicating a \em detached
signature, it would go and inquire that data from the
client. Here's how it works:
\code
const int err = inquire( "DETACHED_SIGNATURE",
this, SLOT(slotDetachedSignature(int,QByteArray,QByteArray)) );
if ( err )
done( err );
\endcode
This should be self-explanatory: You give a slot to call when
the data has arrived. The slot's first argument is an error
code. The second the data (if any), and the third is just
repeating what you gave as inquire()'s first argument. As usual,
you can leave argument off of the end, if you are not interested
in them.
You can do as many inquiries as you want, but only one at a
time.
You should peridocally send status updates to the client. You do
that by calling sendStatus().
Once your command has finished executing, call done(). If it's
with an error code, call done(err) like above. \bold{Do not
forget to call done() when done!}. It will close
bulkInputDevice(), bulkOutputDevice(), and send an OK or ERR
message back to the client.
At that point, your command has finished executing, and a new
one can be accepted, or the connection closed.
Apropos connection closed. The only way for the client to cancel
an operation is to shut down the connection. In this case, the
canceled() function will be called. At that point, the
connection to the client will have been broken already, and all
you can do is pack your things and go down gracefully.
If _you_ detect that the user has canceled (your dialog contains
a cancel button, doesn't it?), then you should instead call
done( GPG_ERR_CANCELED ), like for normal operation.
<h3>Registering the command with UiServer</h3>
To register a command, you implement a AssuanCommandFactory for
your AssuanCommand subclass, and register it with the
UiServer. This can be made considerably easier using
GenericAssuanCommandFactory:
\code
UiServer server;
server.registerCommandFactory( shared_ptr<AssuanCommandFactory>( new GenericAssuanCommandFactory<MyFooCommand> ) );
// more registerCommandFactory calls...
server.start();
\endcode
*/
class AssuanCommand : public ExecutionContext, public boost::enable_shared_from_this<AssuanCommand> {
// defined in assuanserverconnection.cpp!
public:
AssuanCommand();
virtual ~AssuanCommand();
int start();
void canceled();
virtual const char * name() const = 0;
class Memento {
public:
virtual ~Memento() {}
};
template <typename T>
class TypedMemento : public Memento {
T m_t;
public:
explicit TypedMemento( const T & t ) : m_t( t ) {}
const T & get() const { return m_t; }
T & get() { return m_t; }
};
template <typename T>
static boost::shared_ptr< TypedMemento<T> > make_typed_memento( const T & t ) {
return boost::shared_ptr< TypedMemento<T> >( new TypedMemento<T>( t ) );
}
static int makeError( int code );
// convenience methods:
enum Mode { NoMode, EMail, FileManager };
Mode checkMode() const;
enum CheckProtocolOption {
AllowProtocolMissing=0x01
};
GpgME::Protocol checkProtocol( Mode mode, int options=0 ) const;
/* reimp */ void applyWindowID( QWidget* w ) const {
doApplyWindowID( w );
}
WId parentWId() const;
void setNohup( bool on );
bool isNohup() const;
bool isDone() const;
QString sessionTitle() const;
unsigned int sessionId() const;
bool informativeRecipients() const;
bool informativeSenders() const;
const std::vector<KMime::Types::Mailbox> & recipients() const;
const std::vector<KMime::Types::Mailbox> & senders() const;
bool hasMemento( const QByteArray & tag ) const;
boost::shared_ptr<Memento> memento( const QByteArray & tag ) const;
template <typename T>
boost::shared_ptr<T> mementoAs( const QByteArray & tag ) const {
return boost::dynamic_pointer_cast<T>( this->memento( tag ) );
}
QByteArray registerMemento( const boost::shared_ptr<Memento> & mem );
QByteArray registerMemento( const QByteArray & tag, const boost::shared_ptr<Memento> & mem );
void removeMemento( const QByteArray & tag );
template <typename T>
T mementoContent( const QByteArray & tag ) const {
if ( boost::shared_ptr< TypedMemento<T> > m = mementoAs< TypedMemento<T> >( tag ) )
return m->get();
else
return T();
}
bool hasOption( const char * opt ) const;
QVariant option( const char * opt ) const;
const std::map<std::string,QVariant> & options() const;
const std::vector< boost::shared_ptr<Input> > & inputs() const;
const std::vector< boost::shared_ptr<Input> > & messages() const;
const std::vector< boost::shared_ptr<Output> > & outputs() const;
QStringList fileNames() const;
unsigned int numFiles() const;
void sendStatus( const char * keyword, const QString & text );
void sendStatusEncoded( const char * keyword, const std::string & text );
void sendData( const QByteArray & data, bool moreToCome=false );
int inquire( const char * keyword, QObject * receiver, const char * slot, unsigned int maxSize=0 );
void done( const GpgME::Error& err = GpgME::Error() );
void done( const GpgME::Error& err, const QString & details );
void done( int err ) { done( GpgME::Error(err) ); }
void done( int err, const QString & details ) { done( GpgME::Error(err), details ); }
private:
virtual void doCanceled() = 0;
virtual int doStart() = 0;
private:
void doApplyWindowID( QWidget * w ) const;
private:
const std::map< QByteArray, boost::shared_ptr<Memento> > & mementos() const;
private:
friend class ::Kleo::AssuanCommandFactory;
class Private;
kdtools::pimpl_ptr<Private> d;
};
class AssuanCommandFactory {
public:
virtual ~AssuanCommandFactory() {}
virtual boost::shared_ptr<AssuanCommand> create() const = 0;
virtual const char * name() const = 0;
#ifndef HAVE_ASSUAN2
typedef int(*_Handler)( assuan_context_s*, char *);
#else
typedef gpg_error_t(*_Handler)( assuan_context_s*, char *);
#endif
virtual _Handler _handler() const = 0;
#ifndef HAVE_ASSUAN2
static int _handle( assuan_context_s*, char *, const char * );
#else
static gpg_error_t _handle( assuan_context_s*, char *, const char * );
#endif
};
template <typename Command>
class GenericAssuanCommandFactory : public AssuanCommandFactory {
/* reimp */ AssuanCommandFactory::_Handler _handler() const { return &GenericAssuanCommandFactory::_handle; }
#ifndef HAVE_ASSUAN2
static int _handle( assuan_context_s* _ctx, char * _line ) {
#else
static gpg_error_t _handle( assuan_context_s* _ctx, char * _line ) {
#endif
return AssuanCommandFactory::_handle( _ctx, _line, Command::staticName() );
}
/* reimp */ boost::shared_ptr<AssuanCommand> create() const { return make(); }
/* reimp */ const char * name() const { return Command::staticName(); }
public:
static boost::shared_ptr<Command> make() { return boost::shared_ptr<Command>( new Command ); }
};
template <typename Derived, typename Base=AssuanCommand>
class AssuanCommandMixin : public Base {
protected:
/* reimp */ const char * name() const { return Derived::staticName(); }
};
}
#endif /* __KLEOPATRA_UISERVER_ASSUANCOMMAND_H__ */
diff --git a/uiserver/assuanserverconnection.cpp b/uiserver/assuanserverconnection.cpp
index b830eb26a..433900011 100644
--- a/uiserver/assuanserverconnection.cpp
+++ b/uiserver/assuanserverconnection.cpp
@@ -1,1556 +1,1556 @@
/* -*- mode: c++; c-basic-offset:4 -*-
uiserver/assuanserverconnection.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2007 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#ifndef QT_NO_CAST_TO_ASCII
# define QT_NO_CAST_TO_ASCII
#endif
#ifndef QT_NO_CAST_FROM_ASCII
# define QT_NO_CAST_FROM_ASCII
#endif
#include <config-kleopatra.h>
#include <version-kleopatra.h>
#include "assuanserverconnection.h"
#include "assuancommand.h"
#include "sessiondata.h"
#include <models/keycache.h> // :(
#include <utils/input.h>
#include <utils/output.h>
#include <utils/gnupg-helper.h>
#include <utils/detail_p.h>
#include <utils/hex.h>
#include <utils/log.h>
#include <utils/kleo_assert.h>
#include <utils/getpid.h>
#include <kleo/stl_util.h>
#include <kleo/exception.h>
#include <gpgme++/data.h>
#include <gpgme++/key.h>
-#include <KMime/kmime_header_parsing.h>
+#include <kmime/kmime_header_parsing.h>
#include <KDebug>
#include <KLocalizedString>
#include <KWindowSystem>
#include <QSocketNotifier>
#include <QTimer>
#include <QVariant>
#include <QPointer>
#include <QFileInfo>
#include <QStringList>
#include <QRegExp>
#include <QWidget>
#include <kleo-assuan.h>
#ifndef Q_MOC_RUN // QTBUG-22829
#include <boost/type_traits/remove_pointer.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/bind.hpp>
#include <boost/mem_fn.hpp>
#include <boost/mpl/if.hpp>
#endif
#include <vector>
#include <map>
#include <string>
#include <memory>
#include <algorithm>
#include <errno.h>
#ifdef __GNUC__
# include <ext/algorithm> // for is_sorted
#endif
#ifdef Q_OS_WIN32
# include <io.h>
# include <process.h>
#else
# include <sys/types.h>
# include <unistd.h>
#endif
#ifdef Q_WS_X11
# include <qx11info_x11.h>
# include <X11/Xlib.h>
#endif
using namespace Kleo;
using namespace boost;
static const unsigned int INIT_SOCKET_FLAGS = 3; // says info assuan...
//static int(*USE_DEFAULT_HANDLER)(assuan_context_t,char*) = 0;
static const int FOR_READING = 0;
static const unsigned int MAX_ACTIVE_FDS = 32;
#ifdef HAVE_ASSUAN2
static void my_assuan_release( assuan_context_t ctx ) {
if ( ctx )
assuan_release( ctx );
}
#endif
// shared_ptr for assuan_context_t w/ deleter enforced to assuan_deinit_server:
typedef shared_ptr< remove_pointer<assuan_context_t>::type > AssuanContextBase;
struct AssuanContext : AssuanContextBase {
AssuanContext() : AssuanContextBase() {}
#ifndef HAVE_ASSUAN2
explicit AssuanContext( assuan_context_t ctx ) : AssuanContextBase( ctx, &assuan_deinit_server ) {}
#else
explicit AssuanContext( assuan_context_t ctx ) : AssuanContextBase( ctx, &my_assuan_release ) {}
#endif
#ifndef HAVE_ASSUAN2
void reset( assuan_context_t ctx=0 ) { AssuanContextBase::reset( ctx, &assuan_deinit_server ); }
#else
void reset( assuan_context_t ctx=0 ) { AssuanContextBase::reset( ctx, &my_assuan_release ); }
#endif
};
static inline gpg_error_t assuan_process_done_msg( assuan_context_t ctx, gpg_error_t err, const char * err_msg ) {
return assuan_process_done( ctx, assuan_set_error( ctx, err, err_msg ) );
}
static inline gpg_error_t assuan_process_done_msg( assuan_context_t ctx, gpg_error_t err, const std::string & err_msg ) {
return assuan_process_done_msg( ctx, err, err_msg.c_str() );
}
static inline gpg_error_t assuan_process_done_msg( assuan_context_t ctx, gpg_error_t err, const QString & err_msg ) {
return assuan_process_done_msg( ctx, err, err_msg.toUtf8().constData() );
}
static std::map<std::string,std::string> upcase_option( const char * option, std::map<std::string,std::string> options ) {
std::string value;
bool value_found = false;
std::map<std::string,std::string>::iterator it = options.begin();
while ( it != options.end() )
if ( qstricmp( it->first.c_str(), option ) == 0 ) {
value = it->second;
options.erase( it++ );
value_found = true;
} else {
++it;
}
if ( value_found )
options[option] = value;
return options;
}
static std::map<std::string,std::string> parse_commandline( const char * line ) {
std::map<std::string,std::string> result;
if ( line ) {
const char * begin = line;
const char * lastEQ = 0;
while ( *line ) {
if ( *line == ' ' || *line == '\t' ) {
if ( begin != line ) {
if ( begin[0] == '-' && begin[1] == '-' )
begin += 2; // skip initial "--"
if ( lastEQ && lastEQ > begin )
result[ std::string( begin, lastEQ - begin ) ] = hexdecode( std::string( lastEQ+1, line - (lastEQ+1) ) );
else
result[ std::string( begin, line - begin ) ] = std::string();
}
begin = line + 1;
} else if ( *line == '=' ) {
if ( line == begin )
throw Exception( gpg_error( GPG_ERR_ASS_SYNTAX ),
i18n("No option name given") );
else
lastEQ = line;
}
++line;
}
if ( begin != line ) {
if ( begin[0] == '-' && begin[1] == '-' )
begin += 2; // skip initial "--"
if ( lastEQ && lastEQ > begin )
result[ std::string( begin, lastEQ - begin ) ] = hexdecode( std::string( lastEQ+1, line - (lastEQ+1 ) ) );
else
result[ begin ] = std::string();
}
}
return result;
}
static WId wid_from_string( const QString & winIdStr, bool * ok=0 ) {
return
#if defined(Q_OS_WIN32)
reinterpret_cast<WId>
#else
static_cast<WId>
#endif
( winIdStr.toULongLong( ok, 16 ) );
}
static void apply_window_id( QWidget * widget, const QString & winIdStr ) {
if ( !widget || winIdStr.isEmpty() )
return;
bool ok = false;
const WId wid = wid_from_string( winIdStr, &ok );
if ( !ok ) {
kDebug() << "window-id value" << wid << "doesn't look like a number";
return;
}
if ( QWidget * pw = QWidget::find( wid ) )
widget->setParent( pw, widget->windowFlags() );
else {
KWindowSystem::setMainWindow( widget, wid );
}
}
//
//
// AssuanServerConnection:
//
//
class AssuanServerConnection::Private : public QObject {
Q_OBJECT
friend class ::Kleo::AssuanServerConnection;
friend class ::Kleo::AssuanCommandFactory;
friend class ::Kleo::AssuanCommand;
AssuanServerConnection * const q;
public:
Private( assuan_fd_t fd_, const std::vector< shared_ptr<AssuanCommandFactory> > & factories_, AssuanServerConnection * qq );
~Private();
Q_SIGNALS:
void startKeyManager();
public Q_SLOTS:
void slotReadActivity( int ) {
assert( ctx );
#ifndef HAVE_ASSUAN2
if ( const int err = assuan_process_next( ctx.get() ) ) {
#else
int done = false;
if ( const int err = assuan_process_next( ctx.get(), &done ) || done ) {
#endif
//if ( err == -1 || gpg_err_code(err) == GPG_ERR_EOF ) {
topHalfDeletion();
if ( nohupedCommands.empty() )
bottomHalfDeletion();
//} else {
//assuan_process_done( ctx.get(), err );
//return;
//}
}
}
int startCommandBottomHalf();
private:
void nohupDone( AssuanCommand * cmd ) {
const std::vector< shared_ptr<AssuanCommand> >::iterator it
= std::find_if( nohupedCommands.begin(), nohupedCommands.end(),
boost::bind( &shared_ptr<AssuanCommand>::get, _1 ) == cmd );
assert( it != nohupedCommands.end() );
nohupedCommands.erase( it );
if ( nohupedCommands.empty() && closed )
bottomHalfDeletion();
}
void commandDone( AssuanCommand * cmd ) {
if ( !cmd || cmd != currentCommand.get() )
return;
currentCommand.reset();
}
void topHalfDeletion() {
if ( currentCommand )
currentCommand->canceled();
if ( fd != ASSUAN_INVALID_FD ) {
#if defined(Q_OS_WIN32)
CloseHandle( fd );
#else
::close( fd );
#endif
}
notifiers.clear();
closed = true;
}
void bottomHalfDeletion() {
if ( sessionId )
SessionDataHandler::instance()->exitSession( sessionId );
cleanup();
const QPointer<Private> that = this;
emit q->closed( q );
if ( that ) // still there
q->deleteLater();
}
private:
#ifndef HAVE_ASSUAN2
static void reset_handler( assuan_context_t ctx_ ) {
#else
static gpg_error_t reset_handler( assuan_context_t ctx_, char * ) {
#endif
assert( assuan_get_pointer( ctx_ ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
conn.reset();
#ifdef HAVE_ASSUAN2
return 0;
#endif
}
#ifndef HAVE_ASSUAN2
static int option_handler( assuan_context_t ctx_, const char * key, const char * value ) {
#else
static gpg_error_t option_handler( assuan_context_t ctx_, const char * key, const char * value ) {
#endif
assert( assuan_get_pointer( ctx_ ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
if ( key && key[0] == '-' && key[1] == '-' )
key += 2; // skip "--"
conn.options[key] = QString::fromUtf8( value );
return 0;
//return gpg_error( GPG_ERR_UNKNOWN_OPTION );
}
#ifndef HAVE_ASSUAN2
static int session_handler( assuan_context_t ctx_, char * line ) {
#else
static gpg_error_t session_handler( assuan_context_t ctx_, char * line ) {
#endif
assert( assuan_get_pointer( ctx_ ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
const QString str = QString::fromUtf8( line );
QRegExp rx( QLatin1String( "(\\d+)(?:\\s+(.*))?" ) );
if ( !rx.exactMatch( str ) ) {
static const QString errorString = i18n("Parse error");
return assuan_process_done_msg( ctx_, gpg_error( GPG_ERR_ASS_SYNTAX ), errorString );
}
bool ok = false;
if ( const qulonglong id = rx.cap( 1 ).toULongLong( &ok ) ) {
if ( ok && id <= std::numeric_limits<unsigned int>::max() ) {
SessionDataHandler::instance()->enterSession( id );
conn.sessionId = id;
} else {
static const QString errorString = i18n("Parse error: numeric session id too large");
return assuan_process_done_msg( ctx_, gpg_error( GPG_ERR_ASS_SYNTAX ), errorString );
}
}
if ( !rx.cap( 2 ).isEmpty() )
conn.sessionTitle = rx.cap( 2 );
kDebug() << "session_handler: "
<< "id=" << static_cast<unsigned long>( conn.sessionId )
<< ", title=" << qPrintable( conn.sessionTitle );
return assuan_process_done( ctx_, 0 );
}
#ifndef HAVE_ASSUAN2
static int capabilities_handler( assuan_context_t ctx_, char * line ) {
#else
static gpg_error_t capabilities_handler( assuan_context_t ctx_, char * line ) {
#endif
if ( !QByteArray( line ).trimmed().isEmpty() ) {
static const QString errorString = i18n("CAPABILITIES does not take arguments");
return assuan_process_done_msg( ctx_, gpg_error( GPG_ERR_ASS_PARAMETER ), errorString );
}
static const char capabilities[] =
"SENDER=info\n"
"RECIPIENT=info\n"
"SESSION\n"
;
return assuan_process_done( ctx_, assuan_send_data( ctx_, capabilities, sizeof capabilities - 1 ) );
}
#ifndef HAVE_ASSUAN2
static int getinfo_handler( assuan_context_t ctx_, char * line ) {
#else
static gpg_error_t getinfo_handler( assuan_context_t ctx_, char * line ) {
#endif
assert( assuan_get_pointer( ctx_ ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
if ( qstrcmp( line, "version" ) == 0 ) {
static const char version[] = "Kleopatra " KLEOPATRA_VERSION_STRING ;
return assuan_process_done( ctx_, assuan_send_data( ctx_, version, sizeof version - 1 ) );
}
QByteArray ba;
if ( qstrcmp( line, "pid" ) == 0 )
ba = QByteArray::number( mygetpid() );
else if ( qstrcmp( line, "options" ) == 0 )
ba = conn.dumpOptions();
else if ( qstrcmp( line, "x-mementos" ) == 0 )
ba = conn.dumpMementos();
else if ( qstrcmp( line, "senders" ) == 0 )
ba = conn.dumpSenders();
else if ( qstrcmp( line, "recipients" ) == 0 )
ba = conn.dumpRecipients();
else if ( qstrcmp( line, "x-files" ) == 0 )
ba = conn.dumpFiles();
else {
static const QString errorString = i18n("Unknown value for WHAT");
return assuan_process_done_msg( ctx_, gpg_error( GPG_ERR_ASS_PARAMETER ), errorString );
}
return assuan_process_done( ctx_, assuan_send_data( ctx_, ba.constData(), ba.size() ) );
}
#ifndef HAVE_ASSUAN2
static int start_keymanager_handler( assuan_context_t ctx_, char * line ) {
#else
static gpg_error_t start_keymanager_handler( assuan_context_t ctx_, char * line ) {
#endif
assert( assuan_get_pointer( ctx_ ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
if ( line && *line ) {
static const QString errorString = i18n("START_KEYMANAGER does not take arguments");
return assuan_process_done_msg( ctx_, gpg_error( GPG_ERR_ASS_PARAMETER ), errorString );
}
emit conn.q->startKeyManagerRequested();
return assuan_process_done( ctx_, 0 );
}
#ifndef HAVE_ASSUAN2
static int start_confdialog_handler( assuan_context_t ctx_, char * line ) {
#else
static gpg_error_t start_confdialog_handler( assuan_context_t ctx_, char * line ) {
#endif
assert( assuan_get_pointer( ctx_ ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
if ( line && *line ) {
static const QString errorString = i18n("START_CONFDIALOG does not take arguments");
return assuan_process_done_msg( ctx_, gpg_error( GPG_ERR_ASS_PARAMETER ), errorString );
}
emit conn.q->startConfigDialogRequested();
return assuan_process_done( ctx_, 0 );
}
template <bool in> struct Input_or_Output : mpl::if_c<in,Input,Output> {};
// format: TAG (FD|FD=\d+|FILE=...)
template <bool in, typename T_memptr>
#ifndef HAVE_ASSUAN2
static int IO_handler( assuan_context_t ctx_, char * line_, T_memptr which ) {
#else
static gpg_error_t IO_handler( assuan_context_t ctx_, char * line_, T_memptr which ) {
#endif
assert( assuan_get_pointer( ctx_ ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
char *binOpt = strstr ( line_, "--binary" );
if ( binOpt && !in ) {
/* Note there is also --armor and --base64 allowed but we don't need
* to parse those because they are default.
* We remove it here so that it is not parsed as an Option.*/
memset (binOpt, ' ', 8 );
}
try {
/*const*/ std::map<std::string,std::string> options = upcase_option( "FD", upcase_option( "FILE", parse_commandline( line_ ) ) );
if ( options.size() < 1 || options.size() > 2 )
throw gpg_error( GPG_ERR_ASS_SYNTAX );
shared_ptr< typename Input_or_Output<in>::type > io;
if ( options.count( "FD" ) ) {
if ( options.count( "FILE" ) )
throw gpg_error( GPG_ERR_CONFLICT );
assuan_fd_t fd = ASSUAN_INVALID_FD;
const std::string fdstr = options["FD"];
if ( fdstr.empty() ) {
if ( const gpg_error_t err = assuan_receivefd( conn.ctx.get(), &fd ) )
throw err;
} else {
#if defined(Q_OS_WIN32)
fd = (assuan_fd_t)lexical_cast<intptr_t>( fdstr );
#else
fd = lexical_cast<assuan_fd_t>( fdstr );
#endif
}
io = Input_or_Output<in>::type::createFromPipeDevice( fd, in ? i18n( "Message #%1", (conn.*which).size() + 1 ) : QString() );
options.erase( "FD" );
} else if ( options.count( "FILE" ) ) {
if ( options.count( "FD" ) )
throw gpg_error( GPG_ERR_CONFLICT );
const QString filePath = QFile::decodeName( options["FILE"].c_str() );
if ( filePath.isEmpty() )
throw Exception( gpg_error( GPG_ERR_ASS_SYNTAX ), i18n("Empty file path") );
const QFileInfo fi( filePath );
if ( !fi.isAbsolute() )
throw Exception( gpg_error( GPG_ERR_INV_ARG ), i18n("Only absolute file paths are allowed") );
if ( !fi.isFile() )
throw Exception( gpg_error( GPG_ERR_INV_ARG ), i18n("Only files are allowed in INPUT/OUTPUT FILE") );
else
io = Input_or_Output<in>::type::createFromFile( fi.absoluteFilePath(), true );
options.erase( "FILE" );
} else {
throw gpg_error( GPG_ERR_ASS_PARAMETER );
}
if ( options.size() )
throw gpg_error( GPG_ERR_UNKNOWN_OPTION );
(conn.*which).push_back( io );
if ( binOpt && !in ) {
Output* out = reinterpret_cast <Output*>( io.get() );
out->setBinaryOpt( true );
kDebug() << "Configured output for binary data";
}
kDebug() << "AssuanServerConnection: added" << io->label();
return assuan_process_done( conn.ctx.get(), 0 );
} catch ( const GpgME::Exception & e ) {
return assuan_process_done_msg( conn.ctx.get(), e.error().encodedError(), e.message().c_str() );
} catch ( const std::exception & ) {
return assuan_process_done( conn.ctx.get(), gpg_error( GPG_ERR_ASS_SYNTAX ) );
} catch ( const gpg_error_t e ) {
return assuan_process_done( conn.ctx.get(), e );
} catch ( ... ) {
return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_UNEXPECTED ), "unknown exception caught" );
}
}
#ifndef HAVE_ASSUAN2
static int input_handler( assuan_context_t ctx, char * line ) {
#else
static gpg_error_t input_handler( assuan_context_t ctx, char * line ) {
#endif
return IO_handler<true>( ctx, line, &Private::inputs );
}
#ifndef HAVE_ASSUAN2
static int output_handler( assuan_context_t ctx, char * line ) {
#else
static gpg_error_t output_handler( assuan_context_t ctx, char * line ) {
#endif
return IO_handler<false>( ctx, line, &Private::outputs );
}
#ifndef HAVE_ASSUAN2
static int message_handler( assuan_context_t ctx, char * line ) {
#else
static gpg_error_t message_handler( assuan_context_t ctx, char * line ) {
#endif
return IO_handler<true>( ctx, line, &Private::messages );
}
#ifndef HAVE_ASSUAN2
static int file_handler( assuan_context_t ctx_, char * line ) {
#else
static gpg_error_t file_handler( assuan_context_t ctx_, char * line ) {
#endif
assert( assuan_get_pointer( ctx_ ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
try {
const QFileInfo fi( QFile::decodeName( hexdecode( line ).c_str() ) );
if ( !fi.isAbsolute() )
throw Exception( gpg_error( GPG_ERR_INV_ARG ), i18n("Only absolute file paths are allowed") );
if ( !fi.exists() )
throw gpg_error( GPG_ERR_ENOENT );
if ( !fi.isReadable() || ( fi.isDir() && !fi.isExecutable() ) )
throw gpg_error( GPG_ERR_EPERM );
conn.files.push_back( fi.absoluteFilePath() );
return assuan_process_done( conn.ctx.get(), 0 );
} catch ( const Exception & e ) {
return assuan_process_done_msg( conn.ctx.get(), e.error().encodedError(), e.message().toUtf8().constData() );
} catch ( const gpg_error_t e ) {
return assuan_process_done( conn.ctx.get(), e );
} catch ( ... ) {
return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_UNEXPECTED ), i18n("unknown exception caught").toUtf8().constData() );
}
}
static bool parse_informative( const char * & begin, GpgME::Protocol & protocol ) {
protocol = GpgME::UnknownProtocol;
bool informative = false;
const char * pos = begin;
while ( true ) {
while ( *pos == ' ' || *pos == '\t' )
++pos;
if ( qstrnicmp( pos, "--info", strlen("--info") ) == 0 ) {
informative = true;
pos += strlen("--info");
if ( *pos == '=' ) {
++pos;
break;
}
} else if ( qstrnicmp( pos, "--protocol=", strlen("--protocol=") ) == 0 ) {
pos += strlen("--protocol=");
if ( qstrnicmp( pos, "OpenPGP", strlen("OpenPGP") ) == 0 ) {
protocol = GpgME::OpenPGP;
pos += strlen("OpenPGP");
} else if ( qstrnicmp( pos, "CMS", strlen("CMS") ) == 0 ) {
protocol = GpgME::CMS;
pos += strlen("CMS");
} else {
;
}
} else if ( qstrncmp( pos, "-- ", strlen("-- ") ) == 0 ) {
pos += 3;
while ( *pos == ' ' || *pos == '\t' )
++pos;
break;
} else
break;
}
begin = pos;
return informative;
}
template <typename T_memptr, typename T_memptr2>
#ifndef HAVE_ASSUAN2
static int recipient_sender_handler( T_memptr mp, T_memptr2 info, assuan_context_t ctx, char * line, bool sender=false ) {
#else
static gpg_error_t recipient_sender_handler( T_memptr mp, T_memptr2 info, assuan_context_t ctx, char * line, bool sender=false ) {
#endif
assert( assuan_get_pointer( ctx ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx ) );
if ( !line || !*line )
return assuan_process_done( conn.ctx.get(), gpg_error( GPG_ERR_INV_ARG ) );
const char * begin = line;
const char * const end = begin + qstrlen( line );
GpgME::Protocol proto = GpgME::UnknownProtocol;
const bool informative = parse_informative( begin, proto );
if ( !(conn.*mp).empty() && informative != (conn.*info) )
return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_CONFLICT ),
i18n("Cannot mix --info with non-info SENDER or RECIPIENT").toUtf8().constData() );
KMime::Types::Mailbox mb;
if ( !KMime::HeaderParsing::parseMailbox( begin, end, mb ) )
return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_INV_ARG ),
i18n("Argument is not a valid RFC-2822 mailbox").toUtf8().constData() );
if ( begin != end )
return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_INV_ARG ),
i18n("Garbage after valid RFC-2822 mailbox detected").toUtf8().constData() );
(conn.*info) = informative;
(conn.*mp).push_back( mb );
const QString email = mb.addrSpec().asString();
(void)assuan_write_line( conn.ctx.get(), qPrintable( QString().sprintf( "# ok, parsed as \"%s\"", qPrintable( email ) ) ) );
if ( sender && !informative )
return AssuanCommandFactory::_handle( conn.ctx.get(), line, "PREP_SIGN" );
else
return assuan_process_done( ctx, 0 );
}
#ifndef HAVE_ASSUAN2
static int recipient_handler( assuan_context_t ctx, char * line ) {
#else
static gpg_error_t recipient_handler( assuan_context_t ctx, char * line ) {
#endif
return recipient_sender_handler( &Private::recipients, &Private::informativeRecipients, ctx, line );
}
#ifndef HAVE_ASSUAN2
static int sender_handler( assuan_context_t ctx, char * line ) {
#else
static gpg_error_t sender_handler( assuan_context_t ctx, char * line ) {
#endif
return recipient_sender_handler( &Private::senders, &Private::informativeSenders, ctx, line, true );
}
QByteArray dumpOptions() const {
QByteArray result;
for ( std::map<std::string,QVariant>::const_iterator it = options.begin(), end = options.end() ; it != end ; ++it )
result += it->first.c_str() + it->second.toString().toUtf8() + '\n';
return result;
}
static QByteArray dumpStringList( const QStringList & sl ) {
return sl.join( QLatin1String( "\n" ) ).toUtf8();
}
template <typename T_container>
static QByteArray dumpStringList( const T_container & c ) {
QStringList sl;
std::copy( c.begin(), c.end(), std::back_inserter( sl ) );
return dumpStringList( sl );
}
template <typename T_container>
static QByteArray dumpMailboxes( const T_container & c ) {
QStringList sl;
std::transform( c.begin(), c.end(),
std::back_inserter( sl ),
boost::bind( &KMime::Types::Mailbox::prettyAddress, _1 ) );
return dumpStringList( sl );
}
QByteArray dumpSenders() const {
return dumpMailboxes( senders );
}
QByteArray dumpRecipients() const {
return dumpMailboxes( recipients );
}
QByteArray dumpMementos() const {
QByteArray result;
for ( std::map< QByteArray, shared_ptr<AssuanCommand::Memento> >::const_iterator it = mementos.begin(), end = mementos.end() ; it != end ; ++it ) {
char buf[2 + 2*sizeof(void*) + 2];
sprintf( buf, "0x%p\n", ( void* )it->second.get() );
buf[sizeof(buf)-1] = '\0';
result += it->first + QByteArray::fromRawData( buf, sizeof buf );
}
return result;
}
QByteArray dumpFiles() const {
return dumpStringList( kdtools::copy<QStringList>( files ) );
}
void cleanup();
void reset() {
options.clear();
senders.clear();
informativeSenders = false;
recipients.clear();
informativeRecipients = false;
sessionTitle.clear();
sessionId = 0;
mementos.clear();
files.clear();
std::for_each( inputs.begin(), inputs.end(),
boost::bind( &Input::finalize, _1 ) );
inputs.clear();
std::for_each( outputs.begin(), outputs.end(),
boost::bind( &Output::finalize, _1 ) );
outputs.clear();
std::for_each( messages.begin(), messages.end(),
boost::bind( &Input::finalize, _1 ) );
messages.clear();
bias = GpgME::UnknownProtocol;
}
assuan_fd_t fd;
AssuanContext ctx;
bool closed : 1;
bool cryptoCommandsEnabled : 1;
bool commandWaitingForCryptoCommandsEnabled : 1;
bool currentCommandIsNohup : 1;
bool informativeSenders; // address taken, so no : 1
bool informativeRecipients; // address taken, so no : 1
GpgME::Protocol bias;
QString sessionTitle;
unsigned int sessionId;
std::vector< shared_ptr<QSocketNotifier> > notifiers;
std::vector< shared_ptr<AssuanCommandFactory> > factories; // sorted: _detail::ByName<std::less>
shared_ptr<AssuanCommand> currentCommand;
std::vector< shared_ptr<AssuanCommand> > nohupedCommands;
std::map<std::string,QVariant> options;
std::vector<KMime::Types::Mailbox> senders, recipients;
std::vector< shared_ptr<Input> > inputs, messages;
std::vector< shared_ptr<Output> > outputs;
std::vector<QString> files;
std::map< QByteArray, shared_ptr<AssuanCommand::Memento> > mementos;
};
void AssuanServerConnection::Private::cleanup() {
assert( nohupedCommands.empty() );
reset();
currentCommand.reset();
currentCommandIsNohup = false;
commandWaitingForCryptoCommandsEnabled = false;
notifiers.clear();
ctx.reset();
fd = ASSUAN_INVALID_FD;
}
AssuanServerConnection::Private::Private( assuan_fd_t fd_, const std::vector< shared_ptr<AssuanCommandFactory> > & factories_, AssuanServerConnection * qq )
: QObject(),
q( qq ),
fd( fd_ ),
closed( false ),
cryptoCommandsEnabled( false ),
commandWaitingForCryptoCommandsEnabled( false ),
currentCommandIsNohup( false ),
informativeSenders( false ),
informativeRecipients( false ),
bias( GpgME::UnknownProtocol ),
sessionId( 0 ),
factories( factories_ )
{
#ifdef __GNUC__
assert( __gnu_cxx::is_sorted( factories_.begin(), factories_.end(), _detail::ByName<std::less>() ) );
#endif
if ( fd == ASSUAN_INVALID_FD )
throw Exception( gpg_error( GPG_ERR_INV_ARG ), "pre-assuan_init_socket_server_ext" );
#ifndef HAVE_ASSUAN2
assuan_context_t naked_ctx = 0;
if ( const gpg_error_t err = assuan_init_socket_server_ext( &naked_ctx, fd, INIT_SOCKET_FLAGS ) )
#else
{
assuan_context_t naked_ctx = 0;
if ( const gpg_error_t err = assuan_new( &naked_ctx ) )
throw Exception( err, "assuan_new" );
ctx.reset( naked_ctx );
}
if ( const gpg_error_t err = assuan_init_socket_server( ctx.get(), fd, INIT_SOCKET_FLAGS ) )
#endif
throw Exception( err, "assuan_init_socket_server_ext" );
#ifndef HAVE_ASSUAN2
ctx.reset( naked_ctx ); naked_ctx = 0;
#endif
// for callbacks, associate the context with this connection:
assuan_set_pointer( ctx.get(), this );
FILE* const logFile = Log::instance()->logFile();
assuan_set_log_stream( ctx.get(), logFile ? logFile : stderr );
// register FDs with the event loop:
assuan_fd_t fds[MAX_ACTIVE_FDS];
const int numFDs = assuan_get_active_fds( ctx.get(), FOR_READING, fds, MAX_ACTIVE_FDS );
assert( numFDs != -1 ); // == 1
if ( !numFDs || fds[0] != fd ) {
const shared_ptr<QSocketNotifier> sn( new QSocketNotifier( (intptr_t)fd, QSocketNotifier::Read ), mem_fn( &QObject::deleteLater ) );
connect( sn.get(), SIGNAL(activated(int)), this, SLOT(slotReadActivity(int)) );
notifiers.push_back( sn );
}
notifiers.reserve( notifiers.size() + numFDs );
for ( int i = 0 ; i < numFDs ; ++i ) {
const shared_ptr<QSocketNotifier> sn( new QSocketNotifier( (intptr_t)fds[i], QSocketNotifier::Read ), mem_fn( &QObject::deleteLater ) );
connect( sn.get(), SIGNAL(activated(int)), this, SLOT(slotReadActivity(int)) );
notifiers.push_back( sn );
}
// register our INPUT/OUTPUT/MESSGAE/FILE handlers:
#ifndef HAVE_ASSUAN2
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "INPUT", input_handler ) )
#else
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "INPUT", input_handler, "" ) )
#endif
throw Exception( err, "register \"INPUT\" handler" );
#ifndef HAVE_ASSUAN2
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "MESSAGE", message_handler ) )
#else
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "MESSAGE", message_handler, "" ) )
#endif
throw Exception( err, "register \"MESSAGE\" handler" );
#ifndef HAVE_ASSUAN2
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "OUTPUT", output_handler ) )
#else
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "OUTPUT", output_handler, "" ) )
#endif
throw Exception( err, "register \"OUTPUT\" handler" );
#ifndef HAVE_ASSUAN2
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "FILE", file_handler ) )
#else
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "FILE", file_handler, "" ) )
#endif
throw Exception( err, "register \"FILE\" handler" );
// register user-defined commands:
Q_FOREACH( shared_ptr<AssuanCommandFactory> fac, factories )
#ifndef HAVE_ASSUAN2
if ( const gpg_error_t err = assuan_register_command( ctx.get(), fac->name(), fac->_handler() ) )
#else
if ( const gpg_error_t err = assuan_register_command( ctx.get(), fac->name(), fac->_handler(), "" ) )
#endif
throw Exception( err, std::string( "register \"" ) + fac->name() + "\" handler" );
#ifndef HAVE_ASSUAN2
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "GETINFO", getinfo_handler ) )
#else
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "GETINFO", getinfo_handler, "" ) )
#endif
throw Exception( err, "register \"GETINFO\" handler" );
#ifndef HAVE_ASSUAN2
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "START_KEYMANAGER", start_keymanager_handler ) )
#else
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "START_KEYMANAGER", start_keymanager_handler, "" ) )
#endif
throw Exception( err, "register \"START_KEYMANAGER\" handler" );
#ifndef HAVE_ASSUAN2
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "START_CONFDIALOG", start_confdialog_handler ) )
#else
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "START_CONFDIALOG", start_confdialog_handler, "" ) )
#endif
throw Exception( err, "register \"START_CONFDIALOG\" handler" );
#ifndef HAVE_ASSUAN2
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "RECIPIENT", recipient_handler ) )
#else
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "RECIPIENT", recipient_handler, "" ) )
#endif
throw Exception( err, "register \"RECIPIENT\" handler" );
#ifndef HAVE_ASSUAN2
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "SENDER", sender_handler ) )
#else
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "SENDER", sender_handler, "" ) )
#endif
throw Exception( err, "register \"SENDER\" handler" );
#ifndef HAVE_ASSUAN2
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "SESSION", session_handler ) )
#else
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "SESSION", session_handler, "" ) )
#endif
throw Exception( err, "register \"SESSION\" handler" );
#ifndef HAVE_ASSUAN2
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "CAPABILITIES", capabilities_handler ) )
#else
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "CAPABILITIES", capabilities_handler, "" ) )
#endif
throw Exception( err, "register \"CAPABILITIES\" handler" );
assuan_set_hello_line( ctx.get(), "GPG UI server (Kleopatra/" KLEOPATRA_VERSION_STRING ") ready to serve" );
//assuan_set_hello_line( ctx.get(), GPG UI server (qApp->applicationName() + " v" + kapp->applicationVersion() + "ready to serve" )
// some notifiers we're interested in:
if ( const gpg_error_t err = assuan_register_reset_notify( ctx.get(), reset_handler ) )
throw Exception( err, "register reset notify" );
if ( const gpg_error_t err = assuan_register_option_handler( ctx.get(), option_handler ) )
throw Exception( err, "register option handler" );
// and last, we need to call assuan_accept, which doesn't block
// (d/t INIT_SOCKET_FLAGS), but performs vital connection
// establishing handling:
if ( const gpg_error_t err = assuan_accept( ctx.get() ) )
throw Exception( err, "assuan_accept" );
}
AssuanServerConnection::Private::~Private() {
cleanup();
}
AssuanServerConnection::AssuanServerConnection( assuan_fd_t fd, const std::vector< shared_ptr<AssuanCommandFactory> > & factories, QObject * p )
: QObject( p ), d( new Private( fd, factories, this ) )
{
}
AssuanServerConnection::~AssuanServerConnection() {}
void AssuanServerConnection::enableCryptoCommands( bool on ) {
if ( on == d->cryptoCommandsEnabled )
return;
d->cryptoCommandsEnabled = on;
if ( d->commandWaitingForCryptoCommandsEnabled )
QTimer::singleShot( 0, d.get(), SLOT(startCommandBottomHalf()) );
}
//
//
// AssuanCommand:
//
//
namespace Kleo {
class InquiryHandler : public QObject {
Q_OBJECT
public:
#if defined(HAVE_ASSUAN2) || defined(HAVE_ASSUAN_INQUIRE_EXT)
explicit InquiryHandler( const char * keyword_, QObject * p=0 )
: QObject( p ),
# if !defined(HAVE_ASSUAN2) && !defined(HAVE_NEW_STYLE_ASSUAN_INQUIRE_EXT)
buffer( 0 ),
buflen( 0 ),
# endif
keyword( keyword_ )
{
}
# if defined(HAVE_ASSUAN2) || defined(HAVE_NEW_STYLE_ASSUAN_INQUIRE_EXT)
# ifndef HAVE_ASSUAN2
static int handler( void * cb_data, int rc, unsigned char * buffer, size_t buflen )
# else
static gpg_error_t handler( void * cb_data, gpg_error_t rc, unsigned char * buffer, size_t buflen )
# endif
{
assert( cb_data );
InquiryHandler * this_ = static_cast<InquiryHandler*>(cb_data);
emit this_->signal( rc, QByteArray::fromRawData( reinterpret_cast<const char*>(buffer), buflen ), this_->keyword );
std::free( buffer );
delete this_;
return 0;
}
# else
static int handler( void * cb_data, int rc )
{
assert( cb_data );
InquiryHandler * this_ = static_cast<InquiryHandler*>(cb_data);
emit this_->signal( rc, QByteArray::fromRawData( reinterpret_cast<const char*>(this_->buffer), this_->buflen ), this_->keyword );
std::free( this_->buffer );
delete this_;
return 0;
}
# endif
private:
#if !defined(HAVE_ASSUAN2) && !defined(HAVE_NEW_STYLE_ASSUAN_INQUIRE_EXT)
friend class ::Kleo::AssuanCommand;
unsigned char * buffer;
size_t buflen;
#endif
const char * keyword;
#endif // defined(HAVE_ASSUAN2) || defined(HAVE_ASSUAN_INQUIRE_EXT)
Q_SIGNALS:
void signal( int rc, const QByteArray & data, const QByteArray & keyword );
};
} // namespace Kleo
class AssuanCommand::Private {
public:
Private()
: informativeRecipients( false ),
informativeSenders( false ),
bias( GpgME::UnknownProtocol ),
done( false ),
nohup( false )
{
}
std::map<std::string,QVariant> options;
std::vector< shared_ptr<Input> > inputs, messages;
std::vector< shared_ptr<Output> > outputs;
std::vector<QString> files;
std::vector<KMime::Types::Mailbox> recipients, senders;
bool informativeRecipients, informativeSenders;
GpgME::Protocol bias;
QString sessionTitle;
unsigned int sessionId;
QByteArray utf8ErrorKeepAlive;
AssuanContext ctx;
bool done;
bool nohup;
};
AssuanCommand::AssuanCommand()
: d( new Private )
{
}
AssuanCommand::~AssuanCommand() {
}
int AssuanCommand::start() {
try {
if ( const int err = doStart() )
if ( !d->done )
done( err );
return 0;
} catch ( const Exception & e ) {
if ( !d->done )
done( e.error_code(), e.message() );
return 0;
} catch ( const GpgME::Exception & e ) {
if ( !d->done )
done( e.error(), QString::fromLocal8Bit( e.message().c_str() ) );
return 0;
} catch ( const std::exception & e ) {
if ( !d->done )
done( makeError( GPG_ERR_INTERNAL ), i18n("Caught unexpected exception: %1", QString::fromLocal8Bit( e.what() ) ) );
return 0;
} catch ( ... ) {
if ( !d->done )
done( makeError( GPG_ERR_INTERNAL ), i18n("Caught unknown exception - please report this error to the developers." ) );
return 0;
}
}
void AssuanCommand::canceled() {
d->done = true;
doCanceled();
}
// static
int AssuanCommand::makeError( int code ) {
return makeGnuPGError( code );
}
bool AssuanCommand::hasOption( const char * opt ) const {
return d->options.count( opt );
}
QVariant AssuanCommand::option( const char * opt ) const {
const std::map<std::string,QVariant>::const_iterator it = d->options.find( opt );
if ( it == d->options.end() )
return QVariant();
else
return it->second;
}
const std::map<std::string,QVariant> & AssuanCommand::options() const {
return d->options;
}
namespace {
template <typename U, typename V>
std::vector<U> keys( const std::map<U,V> & map ) {
std::vector<U> result;
result.resize( map.size() );
for ( typename std::map<U,V>::const_iterator it = map.begin(), end = map.end() ; it != end ; ++it )
result.push_back( it->first );
return result;
}
}
const std::map< QByteArray, shared_ptr<AssuanCommand::Memento> > & AssuanCommand::mementos() const {
// oh, hack :(
assert( assuan_get_pointer( d->ctx.get() ) );
const AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( d->ctx.get() ) );
return conn.mementos;
}
bool AssuanCommand::hasMemento( const QByteArray & tag ) const {
if ( const unsigned int id = sessionId() )
return SessionDataHandler::instance()->sessionData(id)->mementos.count( tag ) || mementos().count( tag ) ;
else
return mementos().count( tag );
}
shared_ptr<AssuanCommand::Memento> AssuanCommand::memento( const QByteArray & tag ) const {
if ( const unsigned int id = sessionId() ) {
const shared_ptr<SessionDataHandler> sdh = SessionDataHandler::instance();
const shared_ptr<SessionData> sd = sdh->sessionData(id);
const std::map< QByteArray, shared_ptr<Memento> >::const_iterator it = sd->mementos.find( tag );
if ( it != sd->mementos.end() )
return it->second;
}
const std::map< QByteArray, shared_ptr<Memento> >::const_iterator it = mementos().find( tag );
if ( it == mementos().end() )
return shared_ptr<Memento>();
else
return it->second;
}
QByteArray AssuanCommand::registerMemento( const shared_ptr<Memento> & mem ) {
const QByteArray tag = QByteArray::number( reinterpret_cast<qulonglong>( mem.get() ), 36 );
return registerMemento( tag, mem );
}
QByteArray AssuanCommand::registerMemento( const QByteArray & tag, const shared_ptr<Memento> & mem ) {
// oh, hack :(
assert( assuan_get_pointer( d->ctx.get() ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( d->ctx.get() ) );
if ( const unsigned int id = sessionId() )
SessionDataHandler::instance()->sessionData(id)->mementos[tag] = mem;
else
conn.mementos[tag] = mem;
return tag;
}
void AssuanCommand::removeMemento( const QByteArray & tag ) {
// oh, hack :(
assert( assuan_get_pointer( d->ctx.get() ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( d->ctx.get() ) );
conn.mementos.erase( tag );
if ( const unsigned int id = sessionId() )
SessionDataHandler::instance()->sessionData(id)->mementos.erase( tag );
}
const std::vector< shared_ptr<Input> > & AssuanCommand::inputs() const {
return d->inputs;
}
const std::vector< shared_ptr<Input> > & AssuanCommand::messages() const {
return d->messages;
}
const std::vector< shared_ptr<Output> > & AssuanCommand::outputs() const {
return d->outputs;
}
QStringList AssuanCommand::fileNames() const {
return kdtools::copy<QStringList>( d->files );
}
unsigned int AssuanCommand::numFiles() const {
return d->files.size();
}
void AssuanCommand::sendStatus( const char * keyword, const QString & text ) {
sendStatusEncoded( keyword, text.toUtf8().constData() );
}
void AssuanCommand::sendStatusEncoded( const char * keyword, const std::string & text ) {
if ( d->nohup )
return;
if ( const int err = assuan_write_status( d->ctx.get(), keyword, text.c_str() ) )
throw Exception( err, i18n( "Cannot send \"%1\" status", QString::fromLatin1( keyword ) ) );
}
void AssuanCommand::sendData( const QByteArray & data, bool moreToCome ) {
if ( d->nohup )
return;
if ( const gpg_error_t err = assuan_send_data( d->ctx.get(), data.constData(), data.size() ) )
throw Exception( err, i18n( "Cannot send data" ) );
if ( !moreToCome )
if ( const gpg_error_t err = assuan_send_data( d->ctx.get(), 0, 0 ) ) // flush
throw Exception( err, i18n( "Cannot flush data" ) );
}
int AssuanCommand::inquire( const char * keyword, QObject * receiver, const char * slot, unsigned int maxSize ) {
assert( keyword );
assert( receiver );
assert( slot );
if ( d->nohup )
return makeError( GPG_ERR_INV_OP );
#if defined(HAVE_ASSUAN2) || defined(HAVE_ASSUAN_INQUIRE_EXT)
std::auto_ptr<InquiryHandler> ih( new InquiryHandler( keyword, receiver ) );
receiver->connect( ih.get(), SIGNAL(signal(int,QByteArray,QByteArray)), slot );
if ( const gpg_error_t err = assuan_inquire_ext( d->ctx.get(), keyword,
# if !defined(HAVE_ASSUAN2) && !defined(HAVE_NEW_STYLE_ASSUAN_INQUIRE_EXT)
&ih->buffer, &ih->buflen,
# endif
maxSize, InquiryHandler::handler, ih.get() ) )
return err;
ih.release();
return 0;
#else
return makeError( GPG_ERR_NOT_SUPPORTED ); // libassuan too old
#endif // defined(HAVE_ASSUAN2) || defined(HAVE_ASSUAN_INQUIRE_EXT)
}
void AssuanCommand::done( const GpgME::Error& err, const QString & details ) {
if ( d->ctx && !d->done && !details.isEmpty() ) {
kDebug() << "Error: " << details;
d->utf8ErrorKeepAlive = details.toUtf8();
if ( !d->nohup )
assuan_set_error( d->ctx.get(), err.encodedError(), d->utf8ErrorKeepAlive.constData() );
}
done( err );
}
void AssuanCommand::done( const GpgME::Error& err ) {
if ( !d->ctx ) {
kDebug() << err.asString() << ": called with NULL ctx.";
return;
}
if ( d->done ) {
kDebug() << err.asString() << ": called twice!";
return;
}
d->done = true;
std::for_each( d->messages.begin(), d->messages.end(),
boost::bind( &Input::finalize, _1 ) );
std::for_each( d->inputs.begin(), d->inputs.end(),
boost::bind( &Input::finalize, _1 ) );
std::for_each( d->outputs.begin(), d->outputs.end(),
boost::bind( &Output::finalize, _1 ) );
d->messages.clear();
d->inputs.clear();
d->outputs.clear();
d->files.clear();
// oh, hack :(
assert( assuan_get_pointer( d->ctx.get() ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( d->ctx.get() ) );
if ( d->nohup ) {
conn.nohupDone( this );
return;
}
const gpg_error_t rc = assuan_process_done( d->ctx.get(), err.encodedError() );
if ( gpg_err_code( rc ) != GPG_ERR_NO_ERROR )
qFatal( "AssuanCommand::done: assuan_process_done returned error %d (%s)",
static_cast<int>(rc), gpg_strerror(rc) );
d->utf8ErrorKeepAlive.clear();
conn.commandDone( this );
}
void AssuanCommand::setNohup( bool nohup ) {
d->nohup = nohup;
}
bool AssuanCommand::isNohup() const {
return d->nohup;
}
bool AssuanCommand::isDone() const {
return d->done;
}
QString AssuanCommand::sessionTitle() const {
return d->sessionTitle;
}
unsigned int AssuanCommand::sessionId() const {
return d->sessionId;
}
bool AssuanCommand::informativeSenders() const {
return d->informativeSenders;
}
bool AssuanCommand::informativeRecipients() const {
return d->informativeRecipients;
}
const std::vector<KMime::Types::Mailbox> & AssuanCommand::recipients() const {
return d->recipients;
}
const std::vector<KMime::Types::Mailbox> & AssuanCommand::senders() const {
return d->senders;
}
#ifndef HAVE_ASSUAN2
int AssuanCommandFactory::_handle( assuan_context_t ctx, char * line, const char * commandName ) {
#else
gpg_error_t AssuanCommandFactory::_handle( assuan_context_t ctx, char * line, const char * commandName ) {
#endif
assert( assuan_get_pointer( ctx ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx ) );
try {
const std::vector< shared_ptr<AssuanCommandFactory> >::const_iterator it
= std::lower_bound( conn.factories.begin(), conn.factories.end(), commandName, _detail::ByName<std::less>() );
kleo_assert( it != conn.factories.end() );
kleo_assert( *it );
kleo_assert( qstricmp( (*it)->name(), commandName ) == 0 );
const shared_ptr<AssuanCommand> cmd = (*it)->create();
kleo_assert( cmd );
cmd->d->ctx = conn.ctx;
cmd->d->options = conn.options;
cmd->d->inputs.swap( conn.inputs ); kleo_assert( conn.inputs.empty() );
cmd->d->messages.swap( conn.messages ); kleo_assert( conn.messages.empty() );
cmd->d->outputs.swap( conn.outputs ); kleo_assert( conn.outputs.empty() );
cmd->d->files.swap( conn.files ); kleo_assert( conn.files.empty() );
cmd->d->senders.swap( conn.senders ); kleo_assert( conn.senders.empty() );
cmd->d->recipients.swap( conn.recipients ); kleo_assert( conn.recipients.empty() );
cmd->d->informativeRecipients = conn.informativeRecipients;
cmd->d->informativeSenders = conn.informativeSenders;
cmd->d->bias = conn.bias;
cmd->d->sessionTitle = conn.sessionTitle;
cmd->d->sessionId = conn.sessionId;
const std::map<std::string,std::string> cmdline_options = parse_commandline( line );
for ( std::map<std::string,std::string>::const_iterator it = cmdline_options.begin(), end = cmdline_options.end() ; it != end ; ++it )
cmd->d->options[it->first] = QString::fromUtf8( it->second.c_str() );
bool nohup = false;
if ( cmd->d->options.count( "nohup" ) ) {
if ( !cmd->d->options["nohup"].toString().isEmpty() )
return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_ASS_PARAMETER ), "--nohup takes no argument" );
nohup = true;
cmd->d->options.erase( "nohup" );
}
conn.currentCommand = cmd;
conn.currentCommandIsNohup = nohup;
QTimer::singleShot( 0, &conn, SLOT(startCommandBottomHalf()) );
return 0;
} catch ( const Exception & e ) {
return assuan_process_done_msg( conn.ctx.get(), e.error_code(), e.message() );
} catch ( const std::exception & e ) {
return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_UNEXPECTED ), e.what() );
} catch ( ... ) {
return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_UNEXPECTED ), i18n("Caught unknown exception") );
}
}
int AssuanServerConnection::Private::startCommandBottomHalf() {
commandWaitingForCryptoCommandsEnabled = currentCommand && !cryptoCommandsEnabled;
if ( !cryptoCommandsEnabled )
return 0;
const shared_ptr<AssuanCommand> cmd = currentCommand;
if ( !cmd )
return 0;
currentCommand.reset();
const bool nohup = currentCommandIsNohup;
currentCommandIsNohup = false;
try {
if ( const int err = cmd->start() ) {
if ( cmd->isDone() )
return err;
else
return assuan_process_done( ctx.get(), err );
}
if ( cmd->isDone() )
return 0;
if ( nohup ) {
cmd->setNohup( true );
nohupedCommands.push_back( cmd );
return assuan_process_done_msg( ctx.get(), 0, "Command put in the background to continue executing after connection end." );
} else {
currentCommand = cmd;
return 0;
}
} catch ( const Exception & e ) {
return assuan_process_done_msg( ctx.get(), e.error_code(), e.message() );
} catch ( const std::exception & e ) {
return assuan_process_done_msg( ctx.get(), gpg_error( GPG_ERR_UNEXPECTED ), e.what() );
} catch ( ... ) {
return assuan_process_done_msg( ctx.get(), gpg_error( GPG_ERR_UNEXPECTED ), i18n("Caught unknown exception") );
}
}
//
//
// AssuanCommand convenience methods
//
//
/*!
Checks the \c --mode parameter.
\returns The parameter as an AssuanCommand::Mode enum value.
If no \c --mode was given, or it's value wasn't recognized, throws
an Kleo::Exception.
*/
AssuanCommand::Mode AssuanCommand::checkMode() const {
if ( !hasOption( "mode" ) )
throw Exception( makeError( GPG_ERR_MISSING_VALUE ), i18n( "Required --mode option missing" ) );
const QString modeString = option("mode").toString().toLower();
if ( modeString == QLatin1String( "filemanager" ) )
return FileManager;
if ( modeString == QLatin1String( "email" ) )
return EMail;
throw Exception( makeError( GPG_ERR_INV_ARG ), i18n( "invalid mode: \"%1\"", modeString ) );
}
/*!
Checks the \c --protocol parameter.
\returns The parameter as a GpgME::Protocol enum value.
If \c --protocol was given, but has an invalid value, throws an
Kleo::Exception.
If no \c --protocol was given, checks the connection bias, if
available, otherwise, in FileManager mode, returns
GpgME::UnknownProtocol, but if \a mode == \c EMail, throws an
Kleo::Exception instead.
*/
GpgME::Protocol AssuanCommand::checkProtocol( Mode mode, int options ) const {
if ( !hasOption("protocol") )
if ( d->bias != GpgME::UnknownProtocol )
return d->bias;
else if ( mode == AssuanCommand::EMail && ( options & AllowProtocolMissing ) == 0 )
throw Exception( makeError( GPG_ERR_MISSING_VALUE ), i18n( "Required --protocol option missing" ) );
else
return GpgME::UnknownProtocol;
else
if ( mode == AssuanCommand::FileManager )
throw Exception( makeError( GPG_ERR_INV_FLAG ), i18n("--protocol is not allowed here") );
const QString protocolString = option("protocol").toString().toLower();
if ( protocolString == QLatin1String( "openpgp" ) )
return GpgME::OpenPGP;
if ( protocolString == QLatin1String( "cms" ) )
return GpgME::CMS;
throw Exception( makeError( GPG_ERR_INV_ARG ), i18n( "invalid protocol \"%1\"", protocolString ) );
}
void AssuanCommand::doApplyWindowID( QWidget * widget ) const {
if ( !widget || !hasOption( "window-id" ) )
return;
apply_window_id( widget, option("window-id").toString() );
}
WId AssuanCommand::parentWId() const {
return wid_from_string( option("window-id").toString() );
}
#include "assuanserverconnection.moc"
diff --git a/utils/formatting.cpp b/utils/formatting.cpp
index c6ecb9d8e..08293c7e2 100644
--- a/utils/formatting.cpp
+++ b/utils/formatting.cpp
@@ -1,620 +1,620 @@
/* -*- mode: c++; c-basic-offset:4 -*-
utils/formatting.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2007 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include <config-kleopatra.h>
#include "formatting.h"
#include <utils/kleo_assert.h>
#include <kleo/dn.h>
-#include <KMime/kmime_header_parsing.h>
+#include <kmime/kmime_header_parsing.h>
#include <gpgme++/key.h>
#include <gpgme++/importresult.h>
#include <KLocalizedString>
#include <KGlobal>
#include <KLocale>
#include <QString>
#include <QStringList>
#include <QDateTime>
#include <QTextDocument> // for Qt::escape
using namespace GpgME;
using namespace Kleo;
using namespace KMime::Types;
using namespace KMime::HeaderParsing;
//
// Name
//
QString Formatting::prettyName( int proto, const char * id, const char * name_, const char * comment_ ) {
if ( proto == OpenPGP ) {
const QString name = QString::fromUtf8( name_ );
if ( name.isEmpty() )
return QString();
const QString comment = QString::fromUtf8( comment_ );
if ( comment.isEmpty() )
return name;
return QString::fromLatin1( "%1 (%2)" ).arg( name, comment );
}
if ( proto == CMS ) {
const DN subject( id );
const QString cn = subject[QLatin1String("CN")].trimmed();
if ( cn.isEmpty() )
return subject.prettyDN();
return cn;
}
return QString();
}
QString Formatting::prettyNameAndEMail( int proto, const char * id, const char * name_, const char * email_, const char * comment_ ) {
return prettyNameAndEMail( proto, QString::fromUtf8( id ), QString::fromUtf8( name_ ), prettyEMail( email_, id ), QString::fromUtf8( comment_ ) );
}
QString Formatting::prettyNameAndEMail( int proto, const QString & id, const QString & name, const QString & email, const QString & comment ) {
if ( proto == OpenPGP ) {
if ( name.isEmpty() ) {
if ( email.isEmpty() )
return QString();
else if ( comment.isEmpty() )
return QString::fromLatin1( "<%1>" ).arg( email );
else
return QString::fromLatin1( "(%2) <%1>" ).arg( email, comment );
}
if ( email.isEmpty() ) {
if ( comment.isEmpty() )
return name;
else
return QString::fromLatin1( "%1 (%2)" ).arg( name, comment );
}
if ( comment.isEmpty() )
return QString::fromLatin1( "%1 <%2>" ).arg( name, email );
else
return QString::fromLatin1( "%1 (%3) <%2>" ).arg( name, email, comment );
}
if ( proto == CMS ) {
const DN subject( id );
const QString cn = subject[QLatin1String("CN")].trimmed();
if ( cn.isEmpty() )
return subject.prettyDN();
return cn;
}
return QString();
}
QString Formatting::prettyUserID( const UserID & uid ) {
if ( uid.parent().protocol() == OpenPGP )
return prettyNameAndEMail( uid );
const QByteArray id = QByteArray( uid.id() ).trimmed();
if ( id.startsWith( '<' ) )
return prettyEMail( uid.email(), uid.id() );
if ( id.startsWith( '(' ) )
// ### parse uri/dns:
return QString::fromUtf8( uid.id() );
else
return DN( uid.id() ).prettyDN();
}
QString Formatting::prettyKeyID( const char * id ) {
if ( !id )
return QString();
return QLatin1String("0x") + QString::fromLatin1( id ).toUpper();
}
QString Formatting::prettyNameAndEMail( const UserID & uid ) {
return prettyNameAndEMail( uid.parent().protocol(), uid.id(), uid.name(), uid.email(), uid.comment() );
}
QString Formatting::prettyNameAndEMail( const Key & key ) {
return prettyNameAndEMail( key.userID( 0 ) );
}
QString Formatting::prettyName( const Key & key ) {
return prettyName( key.userID( 0 ) );
}
QString Formatting::prettyName( const UserID & uid ) {
return prettyName( uid.parent().protocol(), uid.id(), uid.name(), uid.comment() );
}
QString Formatting::prettyName( const UserID::Signature & sig ) {
return prettyName( OpenPGP, sig.signerUserID(), sig.signerName(), sig.signerComment() );
}
//
// EMail
//
QString Formatting::prettyEMail( const Key & key ) {
for ( unsigned int i = 0, end = key.numUserIDs() ; i < end ; ++i ) {
const QString email = prettyEMail( key.userID( i ) );
if ( !email.isEmpty() )
return email;
}
return QString();
}
QString Formatting::prettyEMail( const UserID & uid ) {
return prettyEMail( uid.email(), uid.id() );
}
QString Formatting::prettyEMail( const UserID::Signature & sig ) {
return prettyEMail( sig.signerEmail(), sig.signerUserID() );
}
QString Formatting::prettyEMail( const char * email_, const char * id ) {
Mailbox mailBox;
if ( email_ && parseMailbox( email_, email_ + strlen( email_ ), mailBox ) )
return mailBox.addrSpec().asPrettyString();
else
return DN( id )[QLatin1String("EMAIL")].trimmed();
}
//
// Tooltip
//
namespace {
static QString protect_whitespace( QString s ) {
static const QLatin1Char SP( ' ' ), NBSP( '\xA0' );
return s.replace( SP, NBSP );
}
template <typename T_arg>
QString format_row( const QString & field, const T_arg & arg ) {
return i18n( "<tr><th>%1:</th><td>%2</td></tr>", protect_whitespace( field ), arg );
}
QString format_row( const QString & field, const QString & arg ) {
return i18n( "<tr><th>%1:</th><td>%2</td></tr>", protect_whitespace( field ), Qt::escape( arg ) );
}
QString format_row( const QString & field, const char * arg ) {
return format_row( field, QString::fromUtf8( arg ) );
}
QString format_keytype( const Key & key ) {
const Subkey subkey = key.subkey( 0 );
if ( key.hasSecret() )
return i18n( "%1-bit %2 (secret key available)", subkey.length(), QLatin1String(subkey.publicKeyAlgorithmAsString()) );
else
return i18n( "%1-bit %2", subkey.length(), QLatin1String(subkey.publicKeyAlgorithmAsString()) );
}
QString format_keyusage( const Key & key ) {
QStringList capabilities;
if ( key.canReallySign() ) {
if ( key.isQualified() )
capabilities.push_back( i18n( "Signing EMails and Files (Qualified)" ) );
else
capabilities.push_back( i18n( "Signing EMails and Files" ) );
}
if ( key.canEncrypt() )
capabilities.push_back( i18n( "Encrypting EMails and Files" ) );
if ( key.canCertify() )
capabilities.push_back( i18n( "Certifying other Certificates" ) );
if ( key.canAuthenticate() )
capabilities.push_back( i18n( "Authenticate against Servers" ) );
return capabilities.join( QLatin1String(", ") );
}
static QString time_t2string( time_t t ) {
QDateTime dt;
dt.setTime_t( t );
return KGlobal::locale()->formatDateTime( dt, KLocale::ShortDate );
}
static QString make_red( const QString & txt ) {
return QLatin1String( "<font color=\"red\">" ) + Qt::escape( txt ) + QLatin1String( "</font>" );
}
}
QString Formatting::toolTip( const Key & key, int flags ) {
if ( flags == 0 || ( key.protocol() != CMS && key.protocol() != OpenPGP ) )
return QString();
const Subkey subkey = key.subkey( 0 );
QString result;
if ( flags & Validity )
if ( key.protocol() == OpenPGP || ( key.keyListMode() & Validate ) )
if ( key.isRevoked() )
result += make_red( i18n( "This certificate has been revoked." ) );
else if ( key.isExpired() )
result += make_red( i18n( "This certificate has expired." ) );
else if ( key.isDisabled() )
result += i18n( "This certificate has been disabled locally." );
else
result += i18n( "This certificate is currently valid." );
else
result += i18n( "The validity of this certificate cannot be checked at the moment." );
if ( flags == Validity )
return result;
result += QLatin1String( "<table border=\"0\">" );
if ( key.protocol() == CMS ) {
if ( flags & SerialNumber )
result += format_row( i18n("Serial number"), key.issuerSerial() );
if ( flags & Issuer )
result += format_row( i18n("Issuer"), key.issuerName() );
}
if ( flags & UserIDs ) {
const std::vector<UserID> uids = key.userIDs();
if ( !uids.empty() )
result += format_row( key.protocol() == CMS
? i18n("Subject")
: i18n("User-ID"), prettyUserID( uids.front() ) );
if ( uids.size() > 1 )
for ( std::vector<UserID>::const_iterator it = uids.begin() + 1, end = uids.end() ; it != end ; ++it )
if ( !it->isRevoked() && !it->isInvalid() )
result += format_row( i18n("a.k.a."), prettyUserID( *it ) );
}
if ( flags & ExpiryDates )
result += format_row( i18n("Validity"),
subkey.neverExpires()
? i18n( "from %1 until forever", time_t2string( subkey.creationTime() ) )
: i18n( "from %1 through %2", time_t2string( subkey.creationTime() ), time_t2string( subkey.expirationTime() ) ) );
if ( flags & CertificateType )
result += format_row( i18n("Certificate type"), format_keytype( key ) );
if ( flags & CertificateUsage )
result += format_row( i18n("Certificate usage"), format_keyusage( key ) );
if ( flags & KeyID )
result += format_row( i18n("Key-ID"), QString::fromLatin1( key.shortKeyID() ) ) ;
if ( flags & Fingerprint )
result += format_row( i18n("Fingerprint"), key.primaryFingerprint() );
if ( flags & OwnerTrust )
if ( key.protocol() == OpenPGP )
result += format_row( i18n("Ownertrust"), ownerTrustShort( key ) );
else if ( key.isRoot() )
result += format_row( i18n("Trusted issuer?"),
key.userID(0).validity() == UserID::Ultimate ? i18n("Yes") :
/* else */ i18n("No") );
if ( flags & StorageLocation )
if ( const char * card = subkey.cardSerialNumber() )
result += format_row( i18n("Stored"), i18nc("stored...","on SmartCard with serial no. %1", QString::fromUtf8( card ) ) );
else
result += format_row( i18n("Stored"), i18nc("stored...","on this computer") );
result += QLatin1String( "</table>" );
return result;
}
//
// Creation and Expiration
//
namespace {
static QDate time_t2date( time_t t ) {
if ( !t )
return QDate();
QDateTime dt;
dt.setTime_t( t );
return dt.date();
}
static QString date2string( const QDate & date ) {
return KGlobal::locale()->formatDate( date, KLocale::ShortDate );
}
template <typename T>
QString expiration_date_string( const T & tee ) {
return tee.neverExpires() ? QString() : date2string( time_t2date( tee.expirationTime() ) ) ;
}
template <typename T>
QDate creation_date( const T & tee ) {
return time_t2date( tee.creationTime() );
}
template <typename T>
QDate expiration_date( const T & tee ) {
return time_t2date( tee.expirationTime() );
}
}
QString Formatting::expirationDateString( const Key & key ) {
return expiration_date_string( key.subkey( 0 ) );
}
QString Formatting::expirationDateString( const Subkey & subkey ) {
return expiration_date_string( subkey );
}
QString Formatting::expirationDateString( const UserID::Signature & sig ) {
return expiration_date_string( sig );
}
QDate Formatting::expirationDate( const Key & key ) {
return expiration_date( key.subkey( 0 ) );
}
QDate Formatting::expirationDate( const Subkey & subkey ) {
return expiration_date( subkey );
}
QDate Formatting::expirationDate( const UserID::Signature & sig ) {
return expiration_date( sig );
}
QString Formatting::creationDateString( const Key & key ) {
return date2string( creation_date( key.subkey( 0 ) ) );
}
QString Formatting::creationDateString( const Subkey & subkey ) {
return date2string( creation_date( subkey ) );
}
QString Formatting::creationDateString( const UserID::Signature & sig ) {
return date2string( creation_date( sig ) );
}
QDate Formatting::creationDate( const Key & key ) {
return creation_date( key.subkey( 0 ) );
}
QDate Formatting::creationDate( const Subkey & subkey ) {
return creation_date( subkey );
}
QDate Formatting::creationDate( const UserID::Signature & sig ) {
return creation_date( sig );
}
//
// Types
//
QString Formatting::displayName( Protocol p ) {
if ( p == CMS )
return i18nc("X.509/CMS encryption standard", "X.509");
if ( p == OpenPGP )
return i18n("OpenPGP");
return i18nc("Unknown encryption protocol", "Unknown");
}
QString Formatting::type( const Key & key ) {
return displayName( key.protocol() );
}
QString Formatting::type( const Subkey & subkey ) {
return QString::fromUtf8( subkey.publicKeyAlgorithmAsString() );
}
//
// Status / Validity
//
QString Formatting::ownerTrustShort( const Key & key ) {
return ownerTrustShort( key.ownerTrust() );
}
QString Formatting::ownerTrustShort( Key::OwnerTrust trust ) {
switch ( trust ) {
case Key::Unknown: return i18nc("unknown trust level", "unknown");
case Key::Never: return i18n("untrusted");
case Key::Marginal: return i18nc("marginal trust", "marginal");
case Key::Full: return i18nc("full trust", "full");
case Key::Ultimate: return i18nc("ultimate trust", "ultimate");
case Key::Undefined: return i18nc("undefined trust", "undefined");
default:
assert( !"unexpected owner trust value" );
break;
}
return QString();
}
QString Formatting::validityShort( const Subkey & subkey ) {
if ( subkey.isRevoked() )
return i18n("revoked");
if ( subkey.isExpired() )
return i18n("expired");
if ( subkey.isDisabled() )
return i18n("disabled");
if ( subkey.isInvalid() )
return i18n("invalid");
return i18nc("as in good/valid signature", "good");
}
QString Formatting::validityShort( const UserID & uid ) {
if ( uid.isRevoked() )
return i18n("revoked");
if ( uid.isInvalid() )
return i18n("invalid");
switch ( uid.validity() ) {
case UserID::Unknown: return i18nc("unknown trust level", "unknown");
case UserID::Undefined: return i18nc("undefined trust", "undefined");
case UserID::Never: return i18n("untrusted");
case UserID::Marginal: return i18nc("marginal trust", "marginal");
case UserID::Full: return i18nc("full trust", "full");
case UserID::Ultimate: return i18nc("ultimate trust", "ultimate");
}
return QString();
}
QString Formatting::validityShort( const UserID::Signature & sig ) {
switch ( sig.status() ) {
case UserID::Signature::NoError:
if ( !sig.isInvalid() ) {
if ( sig.certClass() > 0 )
return i18n("class %1", sig.certClass() );
else
return i18nc("good/valid signature", "good");
}
// fall through:
case UserID::Signature::GeneralError:
return i18n("invalid");
case UserID::Signature::SigExpired: return i18n("expired");
case UserID::Signature::KeyExpired: return i18n("certificate expired");
case UserID::Signature::BadSignature: return i18nc("fake/invalid signature", "bad");
case UserID::Signature::NoPublicKey: return QString();
}
return QString();
}
QString Formatting::formatKeyLink( const Key & key ) {
if ( key.isNull() )
return QString();
return QString::fromLatin1( "<a href=\"key:%1\">%2</a>" ).arg( QLatin1String(key.primaryFingerprint()), Formatting::prettyName( key ) );
}
QString Formatting::formatForComboBox( const GpgME::Key & key ) {
const QString name = prettyName( key );
QString mail = prettyEMail( key );
if ( !mail.isEmpty() )
mail = QLatin1Char('<') + mail + QLatin1Char('>');
return i18nc( "name, email, key id", "%1 %2 (%3)", name, mail, QLatin1String(key.shortKeyID()) ).simplified();
}
namespace {
static QString keyToString( const Key & key ) {
kleo_assert( !key.isNull() );
const QString email = Formatting::prettyEMail( key );
const QString name = Formatting::prettyName( key );
if ( name.isEmpty() )
return email;
else if ( email.isEmpty() )
return name;
else
return QString::fromLatin1( "%1 <%2>" ).arg( name, email );
}
}
const char * Formatting::summaryToString( const Signature::Summary summary )
{
if ( summary & Signature::Red )
return "RED";
if ( summary & Signature::Green )
return "GREEN";
return "YELLOW";
}
QString Formatting::signatureToString( const Signature & sig, const Key & key )
{
if ( sig.isNull() )
return QString();
const bool red = (sig.summary() & Signature::Red);
const bool valid = (sig.summary() & Signature::Valid);
if ( red )
if ( key.isNull() )
if ( const char * fpr = sig.fingerprint() )
return i18n("Bad signature by unknown certificate %1: %2", QString::fromLatin1( fpr ), QString::fromLocal8Bit( sig.status().asString() ) );
else
return i18n("Bad signature by an unknown certificate: %1", QString::fromLocal8Bit( sig.status().asString() ) );
else
return i18n("Bad signature by %1: %2", keyToString( key ), QString::fromLocal8Bit( sig.status().asString() ) );
else if ( valid )
if ( key.isNull() )
if ( const char * fpr = sig.fingerprint() )
return i18n("Good signature by unknown certificate %1.", QString::fromLatin1( fpr ) );
else
return i18n("Good signature by an unknown certificate.");
else
return i18n("Good signature by %1.", keyToString( key ) );
else
if ( key.isNull() )
if ( const char * fpr = sig.fingerprint() )
return i18n("Invalid signature by unknown certificate %1: %2", QString::fromLatin1( fpr ), QString::fromLocal8Bit( sig.status().asString() ) );
else
return i18n("Invalid signature by an unknown certificate: %1", QString::fromLocal8Bit( sig.status().asString() ) );
else
return i18n("Invalid signature by %1: %2", keyToString( key ), QString::fromLocal8Bit( sig.status().asString() ) );
}
//
// ImportResult
//
QString Formatting::importMetaData( const Import & import, const QStringList & ids ) {
const QString result = importMetaData( import );
if ( result.isEmpty() )
return QString();
else
return result + QLatin1Char('\n') +
i18n("This certificate was imported from the following sources:") + QLatin1Char('\n') +
ids.join(QLatin1String("\n"));
}
QString Formatting::importMetaData( const Import & import ) {
if ( import.isNull() )
return QString();
if ( import.error().isCanceled() )
return i18n( "The import of this certificate was canceled." );
if ( import.error() )
return i18n( "An error occurred importing this certificate: %1",
QString::fromLocal8Bit( import.error().asString() ) );
const unsigned int status = import.status();
if ( status & Import::NewKey )
return ( status & Import::ContainedSecretKey )
? i18n( "This certificate was new to your keystore. The secret key is available." )
: i18n( "This certificate is new to your keystore." ) ;
QStringList results;
if ( status & Import::NewUserIDs )
results.push_back( i18n( "New user-ids were added to this certificate by the import." ) );
if ( status & Import::NewSignatures )
results.push_back( i18n( "New signatures were added to this certificate by the import." ) );
if ( status & Import::NewSubkeys )
results.push_back( i18n( "New subkeys were added to this certificate by the import." ) );
return results.empty()
? i18n( "The import contained no new data for this certificate. It is unchanged.")
: results.join( QLatin1String("\n") );
}
//
// Overview in CertificateDetailsDialog
//
QString Formatting::formatOverview( const Key & key ) {
return toolTip( key, AllOptions );
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, Jul 12, 10:31 AM (1 d, 11 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
c6/ab/2b5433d44009850f71c063aaa1fd

Event Timeline