From 460c52653ab0dcca6f19a4f492ed2c5e4e963ab0 Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdepim@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- certmanager/lib/backends/qgpgme/qgpgmejob.cpp | 304 ++++++++++++++++++++++++++ 1 file changed, 304 insertions(+) create mode 100644 certmanager/lib/backends/qgpgme/qgpgmejob.cpp (limited to 'certmanager/lib/backends/qgpgme/qgpgmejob.cpp') diff --git a/certmanager/lib/backends/qgpgme/qgpgmejob.cpp b/certmanager/lib/backends/qgpgme/qgpgmejob.cpp new file mode 100644 index 000000000..897e5ff7c --- /dev/null +++ b/certmanager/lib/backends/qgpgme/qgpgmejob.cpp @@ -0,0 +1,304 @@ +/* + qgpgmejob.cpp + + This file is part of libkleopatra, the KDE keymanagement library + Copyright (c) 2004 Klarälvdalens Datakonsult AB + + Libkleopatra 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. + + Libkleopatra 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. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "qgpgmejob.h" +#include "qgpgmeprogresstokenmapper.h" + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + +namespace { + class InvarianceChecker { + public: +#ifdef NDEBUG + InvarianceChecker( const Kleo::QGpgMEJob * ) {} +#else + InvarianceChecker( const Kleo::QGpgMEJob * job ) + : _this( job ) + { + assert( _this ); + _this->checkInvariants(); + } + ~InvarianceChecker() { + _this->checkInvariants(); + } + private: + const Kleo::QGpgMEJob * _this; +#endif + }; +} + +Kleo::QGpgMEJob::QGpgMEJob( Kleo::Job * _this, GpgME::Context * context ) + : GpgME::ProgressProvider(), + GpgME::PassphraseProvider(), + mThis( _this ), + mCtx( context ), + mInData( 0 ), + mInDataDataProvider( 0 ), + mOutData( 0 ), + mOutDataDataProvider( 0 ), + mPatterns( 0 ), + mReplacedPattern( 0 ), + mNumPatterns( 0 ), + mChunkSize( 1024 ), + mPatternStartIndex( 0 ), mPatternEndIndex( 0 ) +{ + InvarianceChecker check( this ); + assert( context ); + QObject::connect( QGpgME::EventLoopInteractor::instance(), SIGNAL(aboutToDestroy()), + _this, SLOT(slotCancel()) ); + context->setProgressProvider( this ); + // (mmutz) work around a gpgme bug in versions at least <= 0.9.0. + // These versions will return GPG_ERR_NOT_IMPLEMENTED from + // a CMS sign operation when a passphrase callback is set. + if ( context->protocol() == GpgME::Context::OpenPGP ) + context->setPassphraseProvider( this ); +} + +void Kleo::QGpgMEJob::checkInvariants() const { +#ifndef NDEBUG + if ( mPatterns ) { + assert( mPatterns[mNumPatterns] == 0 ); + if ( mPatternEndIndex > 0 ) { + assert( mPatternEndIndex > mPatternStartIndex ); + assert( mPatternEndIndex - mPatternStartIndex == mChunkSize ); + } else { + assert( mPatternEndIndex == mPatternStartIndex ); + } + if ( mPatternEndIndex < mNumPatterns ) { + assert( mPatterns[mPatternEndIndex] == 0 ); + assert( mReplacedPattern != 0 ); + } else { + assert( mReplacedPattern == 0 ); + } + } else { + assert( mNumPatterns == 0 ); + assert( mPatternStartIndex == 0 ); + assert( mPatternEndIndex == 0 ); + assert( mReplacedPattern == 0 ); + } +#endif +} + +Kleo::QGpgMEJob::~QGpgMEJob() { + InvarianceChecker check( this ); + delete mCtx; mCtx = 0; + delete mInData; mInData = 0; + delete mInDataDataProvider; mInDataDataProvider = 0; + delete mOutData; mOutData = 0; + delete mOutDataDataProvider; mOutDataDataProvider = 0; + deleteAllPatterns(); +} + +void Kleo::QGpgMEJob::deleteAllPatterns() { + if ( mPatterns ) + for ( unsigned int i = 0 ; i < mNumPatterns ; ++i ) + free( (void*)mPatterns[i] ); + free( (void*)mReplacedPattern ); mReplacedPattern = 0; + delete[] mPatterns; mPatterns = 0; + mPatternEndIndex = mPatternStartIndex = mNumPatterns = 0; +} + +void Kleo::QGpgMEJob::hookupContextToEventLoopInteractor() { + mCtx->setManagedByEventLoopInteractor( true ); + QObject::connect( QGpgME::EventLoopInteractor::instance(), + SIGNAL(operationDoneEventSignal(GpgME::Context*,const GpgME::Error&)), + mThis, SLOT(slotOperationDoneEvent(GpgME::Context*,const GpgME::Error&)) ); +} + +void Kleo::QGpgMEJob::setPatterns( const QStringList & sl, bool allowEmpty ) { + InvarianceChecker check( this ); + deleteAllPatterns(); + // create a new null-terminated C array of char* from patterns: + mPatterns = new const char*[ sl.size() + 1 ]; + const char* * pat_it = mPatterns; + mNumPatterns = 0; + for ( QStringList::const_iterator it = sl.begin() ; it != sl.end() ; ++it ) { + if ( (*it).isNull() ) + continue; + if ( (*it).isEmpty() && !allowEmpty ) + continue; + *pat_it++ = strdup( (*it).utf8().data() ); + ++mNumPatterns; + } + *pat_it++ = 0; + mReplacedPattern = 0; + mPatternEndIndex = mChunkSize = mNumPatterns; +} + +void Kleo::QGpgMEJob::setChunkSize( unsigned int chunksize ) { + InvarianceChecker check( this ); + if ( mReplacedPattern ) { + mPatterns[mPatternEndIndex] = mReplacedPattern; + mReplacedPattern = 0; + } + mChunkSize = std::min( chunksize, mNumPatterns ); + mPatternStartIndex = 0; + mPatternEndIndex = mChunkSize; + mReplacedPattern = mPatterns[mPatternEndIndex]; + mPatterns[mPatternEndIndex] = 0; +} + +const char* * Kleo::QGpgMEJob::nextChunk() { + InvarianceChecker check( this ); + if ( mReplacedPattern ) { + mPatterns[mPatternEndIndex] = mReplacedPattern; + mReplacedPattern = 0; + } + mPatternStartIndex += mChunkSize; + mPatternEndIndex += mChunkSize; + if ( mPatternEndIndex < mNumPatterns ) { // could safely be <=, but the last entry is NULL anyway + mReplacedPattern = mPatterns[mPatternEndIndex]; + mPatterns[mPatternEndIndex] = 0; + } + return patterns(); +} + +const char* * Kleo::QGpgMEJob::patterns() const { + InvarianceChecker check( this ); + if ( mPatternStartIndex < mNumPatterns ) + return mPatterns + mPatternStartIndex; + return 0; +} + +GpgME::Error Kleo::QGpgMEJob::setSigningKeys( const std::vector & signers ) { + mCtx->clearSigningKeys(); + for ( std::vector::const_iterator it = signers.begin() ; it != signers.end() ; ++it ) { + if ( (*it).isNull() ) + continue; + if ( const GpgME::Error err = mCtx->addSigningKey( *it ) ) + return err; + } + return 0; +} + +void Kleo::QGpgMEJob::createInData( const QByteArray & in ) { + mInDataDataProvider = new QGpgME::QByteArrayDataProvider( in ); + mInData = new GpgME::Data( mInDataDataProvider ); + assert( !mInData->isNull() ); +} + +void Kleo::QGpgMEJob::createOutData() { + mOutDataDataProvider = new QGpgME::QByteArrayDataProvider(); + mOutData = new GpgME::Data( mOutDataDataProvider ); + assert( !mOutData->isNull() ); +} + +static const unsigned int GetAuditLogFlags = GpgME::Context::AuditLogWithHelp|GpgME::Context::HtmlAuditLog; + +static QString audit_log_as_html( GpgME::Context * ctx ) { + if ( !ctx ) + return QString(); + QGpgME::QByteArrayDataProvider dp; + GpgME::Data data( &dp ); + assert( !data.isNull() ); + if ( const GpgME::Error err = ctx->getAuditLog( data, GetAuditLogFlags ) ) + return QString(); + else + return QString::fromUtf8( dp.data().data() ); +} + +void Kleo::QGpgMEJob::doSlotOperationDoneEvent( GpgME::Context * context, const GpgME::Error & e ) { + if ( context == mCtx ) { + getAuditLog(); + doEmitDoneSignal(); + doOperationDoneEvent( e ); + mThis->deleteLater(); + } +} + +void Kleo::QGpgMEJob::getAuditLog() { + mAuditLogAsHtml = audit_log_as_html( mCtx ); +} + +void Kleo::QGpgMEJob::doSlotCancel() { + mCtx->cancelPendingOperation(); +} + +void Kleo::QGpgMEJob::showProgress( const char * what, int type, int current, int total ) { + doEmitProgressSignal( QGpgMEProgressTokenMapper::instance()->map( what, type, current, total ), current, total ); +} + +char * Kleo::QGpgMEJob::getPassphrase( const char * useridHint, const char * /*description*/, + bool previousWasBad, bool & canceled ) { + // DF: here, description is the key fingerprint, twice, then "17 0". Not really descriptive. + // So I'm ignoring QString::fromLocal8Bit( description ) ) + QString msg = previousWasBad ? + i18n( "You need a passphrase to unlock the secret key for user:
%1 (retry)" ) : + i18n( "You need a passphrase to unlock the secret key for user:
%1" ); + msg = msg.arg( QString::fromUtf8( useridHint ) ) + "

"; + msg.prepend( "" ); + msg += i18n( "This dialog will reappear every time the passphrase is needed. For a more secure solution that also allows caching the passphrase, use gpg-agent." ) + "
"; + const QString gpgAgent = KStandardDirs::findExe( "gpg-agent" ); + if ( !gpgAgent.isEmpty() ) { + msg += i18n( "gpg-agent was found in %1, but does not appear to be running." ) + .arg( gpgAgent ); + } else { + msg += i18n( "gpg-agent is part of gnupg-%1, which you can download from %2" ) + .arg( "1.9" ) + .arg( "http://www.gnupg.org/download" ); // add #gnupg2 if you can make this a real link + } + msg += "
"; + msg += i18n( "For information on how to set up gpg-agent, see %1" ) + .arg( "http://kmail.kde.org/kmail-pgpmime-howto.html" ); + msg += "

"; + msg += i18n( "Enter passphrase:" ); + Kleo::PassphraseDialog dlg( msg, i18n("Passphrase Dialog") ); + if ( dlg.exec() != QDialog::Accepted ) { + canceled = true; + return 0; + } + canceled = false; + // gpgme++ free()s it, and we need to copy as long as dlg isn't deleted :o + return strdup( dlg.passphrase() ); +} -- cgit v1.2.1