certmanager/lib

qgpgmejob.cpp

00001 /*
00002     qgpgmejob.cpp
00003 
00004     This file is part of libkleopatra, the KDE keymanagement library
00005     Copyright (c) 2004 Klarälvdalens Datakonsult AB
00006 
00007     Libkleopatra is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU General Public License as
00009     published by the Free Software Foundation; either version 2 of the
00010     License, or (at your option) any later version.
00011 
00012     Libkleopatra is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program; if not, write to the Free Software
00019     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00020 
00021     In addition, as a special exception, the copyright holders give
00022     permission to link the code of this program with any edition of
00023     the TQt library by Trolltech AS, Norway (or with modified versions
00024     of TQt that use the same license as TQt), and distribute linked
00025     combinations including the two.  You must obey the GNU General
00026     Public License in all respects for all of the code used other than
00027     TQt.  If you modify this file, you may extend this exception to
00028     your version of the file, but you are not obligated to do so.  If
00029     you do not wish to do so, delete this exception statement from
00030     your version.
00031 */
00032 
00033 #ifdef HAVE_CONFIG_H
00034 #include <config.h>
00035 #endif
00036 
00037 #include "qgpgmejob.h"
00038 #include "qgpgmeprogresstokenmapper.h"
00039 
00040 #include <kleo/job.h>
00041 #include <ui/passphrasedialog.h>
00042 
00043 #include <qgpgme/eventloopinteractor.h>
00044 #include <qgpgme/dataprovider.h>
00045 
00046 #include <gpgmepp/context.h>
00047 #include <gpgmepp/data.h>
00048 
00049 #include <tdelocale.h>
00050 #include <kstandarddirs.h>
00051 
00052 #include <tqstring.h>
00053 #include <tqstringlist.h>
00054 
00055 #include <algorithm>
00056 
00057 #include <assert.h>
00058 #include <stdlib.h>
00059 #include <string.h>
00060 
00061 namespace {
00062   class InvarianceChecker {
00063   public:
00064 #ifdef NDEBUG
00065     InvarianceChecker( const Kleo::QGpgMEJob * ) {}
00066 #else
00067     InvarianceChecker( const Kleo::QGpgMEJob * job )
00068       : _this( job )
00069     {
00070       assert( _this );
00071       _this->checkInvariants();
00072     }
00073     ~InvarianceChecker() {
00074       _this->checkInvariants();
00075     }
00076   private:
00077     const Kleo::QGpgMEJob * _this;
00078 #endif
00079   };
00080 }
00081 
00082 Kleo::QGpgMEJob::QGpgMEJob( Kleo::Job * _this, GpgME::Context * context )
00083   : GpgME::ProgressProvider(),
00084     GpgME::PassphraseProvider(),
00085     mThis( _this ),
00086     mCtx( context ),
00087     mInData( 0 ),
00088     mInDataDataProvider( 0 ),
00089     mOutData( 0 ),
00090     mOutDataDataProvider( 0 ),
00091     mPatterns( 0 ),
00092     mReplacedPattern( 0 ),
00093     mNumPatterns( 0 ),
00094     mChunkSize( 1024 ),
00095     mPatternStartIndex( 0 ), mPatternEndIndex( 0 )
00096 {
00097   InvarianceChecker check( this );
00098   assert( context );
00099   TQObject::connect( QGpgME::EventLoopInteractor::instance(), TQT_SIGNAL(aboutToDestroy()),
00100             _this, TQT_SLOT(slotCancel()) );
00101   context->setProgressProvider( this );
00102   // (mmutz) work around a gpgme bug in versions at least <= 0.9.0.
00103   //         These versions will return GPG_ERR_NOT_IMPLEMENTED from
00104   //         a CMS sign operation when a passphrase callback is set.
00105   if ( context->protocol() == GpgME::Context::OpenPGP )
00106     context->setPassphraseProvider( this );
00107 }
00108 
00109 void Kleo::QGpgMEJob::checkInvariants() const {
00110 #ifndef NDEBUG
00111   if ( mPatterns ) {
00112     assert( mPatterns[mNumPatterns] == 0 );
00113     if ( mPatternEndIndex > 0 ) {
00114       assert( mPatternEndIndex > mPatternStartIndex );
00115       assert( mPatternEndIndex - mPatternStartIndex == mChunkSize );
00116     } else {
00117       assert( mPatternEndIndex == mPatternStartIndex );
00118     }
00119     if ( mPatternEndIndex < mNumPatterns ) {
00120       assert( mPatterns[mPatternEndIndex] == 0 );
00121       assert( mReplacedPattern != 0 );
00122     } else {
00123       assert( mReplacedPattern == 0 );
00124     }
00125   } else {
00126     assert( mNumPatterns == 0 );
00127     assert( mPatternStartIndex == 0 );
00128     assert( mPatternEndIndex == 0 );
00129     assert( mReplacedPattern == 0 );
00130   }
00131 #endif
00132 }
00133 
00134 Kleo::QGpgMEJob::~QGpgMEJob() {
00135   InvarianceChecker check( this );
00136   delete mCtx; mCtx = 0;
00137   delete mInData; mInData = 0;
00138   delete mInDataDataProvider; mInDataDataProvider = 0;
00139   delete mOutData; mOutData = 0;
00140   delete mOutDataDataProvider; mOutDataDataProvider = 0;
00141   deleteAllPatterns();
00142 }
00143 
00144 void Kleo::QGpgMEJob::deleteAllPatterns() {
00145   if ( mPatterns )
00146     for ( unsigned int i = 0 ; i < mNumPatterns ; ++i )
00147       free( (void*)mPatterns[i] );
00148   free( (void*)mReplacedPattern ); mReplacedPattern = 0;
00149   delete[] mPatterns; mPatterns = 0;
00150   mPatternEndIndex = mPatternStartIndex = mNumPatterns = 0;
00151 }
00152 
00153 void Kleo::QGpgMEJob::hookupContextToEventLoopInteractor() {
00154   mCtx->setManagedByEventLoopInteractor( true );
00155   TQObject::connect( QGpgME::EventLoopInteractor::instance(),
00156             TQT_SIGNAL(operationDoneEventSignal(GpgME::Context*,const GpgME::Error&)),
00157             mThis, TQT_SLOT(slotOperationDoneEvent(GpgME::Context*,const GpgME::Error&)) );
00158 }
00159 
00160 void Kleo::QGpgMEJob::setPatterns( const TQStringList & sl, bool allowEmpty ) {
00161   InvarianceChecker check( this );
00162   deleteAllPatterns();
00163   // create a new null-terminated C array of char* from patterns:
00164   mPatterns = new const char*[ sl.size() + 1 ];
00165   const char* * pat_it = mPatterns;
00166   mNumPatterns = 0;
00167   for ( TQStringList::const_iterator it = sl.begin() ; it != sl.end() ; ++it ) {
00168     if ( (*it).isNull() )
00169       continue;
00170     if ( (*it).isEmpty() && !allowEmpty )
00171       continue;
00172     *pat_it++ = strdup( (*it).utf8().data() );
00173     ++mNumPatterns;
00174   }
00175   *pat_it++ = 0;
00176   mReplacedPattern = 0;
00177   mPatternEndIndex = mChunkSize = mNumPatterns;
00178 }
00179 
00180 void Kleo::QGpgMEJob::setChunkSize( unsigned int chunksize ) {
00181   InvarianceChecker check( this );
00182   if ( mReplacedPattern ) {
00183     mPatterns[mPatternEndIndex] = mReplacedPattern;
00184     mReplacedPattern = 0;
00185   }
00186   mChunkSize = std::min( chunksize, mNumPatterns );
00187   mPatternStartIndex = 0;
00188   mPatternEndIndex = mChunkSize;
00189   mReplacedPattern = mPatterns[mPatternEndIndex];
00190   mPatterns[mPatternEndIndex] = 0;
00191 }
00192 
00193 const char* * Kleo::QGpgMEJob::nextChunk() {
00194   InvarianceChecker check( this );
00195   if ( mReplacedPattern ) {
00196     mPatterns[mPatternEndIndex] = mReplacedPattern;
00197     mReplacedPattern = 0;
00198   }
00199   mPatternStartIndex += mChunkSize;
00200   mPatternEndIndex += mChunkSize;
00201   if ( mPatternEndIndex < mNumPatterns ) { // could safely be <=, but the last entry is NULL anyway
00202     mReplacedPattern = mPatterns[mPatternEndIndex];
00203     mPatterns[mPatternEndIndex] = 0;
00204   }
00205   return patterns();
00206 }
00207 
00208 const char* * Kleo::QGpgMEJob::patterns() const {
00209   InvarianceChecker check( this );
00210   if ( mPatternStartIndex < mNumPatterns )
00211     return mPatterns + mPatternStartIndex;
00212   return 0;
00213 }
00214 
00215 GpgME::Error Kleo::QGpgMEJob::setSigningKeys( const std::vector<GpgME::Key> & signers ) {
00216   mCtx->clearSigningKeys();
00217   for ( std::vector<GpgME::Key>::const_iterator it = signers.begin() ; it != signers.end() ; ++it ) {
00218     if ( (*it).isNull() )
00219       continue;
00220     if ( const GpgME::Error err = mCtx->addSigningKey( *it ) )
00221       return err;
00222   }
00223   return 0;
00224 }
00225 
00226 void Kleo::QGpgMEJob::createInData( const TQByteArray & in ) {
00227   mInDataDataProvider = new QGpgME::TQByteArrayDataProvider( in );
00228   mInData = new GpgME::Data( mInDataDataProvider );
00229   assert( !mInData->isNull() );
00230 }
00231 
00232 void Kleo::QGpgMEJob::createOutData() {
00233   mOutDataDataProvider = new QGpgME::TQByteArrayDataProvider();
00234   mOutData = new GpgME::Data( mOutDataDataProvider );
00235   assert( !mOutData->isNull() );
00236 }
00237 
00238 static const unsigned int GetAuditLogFlags = GpgME::Context::AuditLogWithHelp|GpgME::Context::HtmlAuditLog;
00239 
00240 static TQString audit_log_as_html( GpgME::Context * ctx, GpgME::Error & err ) {
00241     assert( ctx );
00242     QGpgME::TQByteArrayDataProvider dp;
00243     GpgME::Data data( &dp );
00244     assert( !data.isNull() );
00245     if ( ( err = ctx->getAuditLog( data, GetAuditLogFlags ) ) )
00246         return TQString();
00247     const TQByteArray ba = dp.data();
00248     return TQString::fromUtf8( ba.data(), ba.size() );
00249 }
00250 
00251 void Kleo::QGpgMEJob::doSlotOperationDoneEvent( GpgME::Context * context, const GpgME::Error & e ) {
00252   if ( context == mCtx ) {
00253     doEmitDoneSignal();
00254     doOperationDoneEvent( e );
00255     mThis->deleteLater();
00256   }
00257 }
00258 
00259 void Kleo::QGpgMEJob::getAuditLog() {
00260     if ( !mCtx )
00261         return;
00262     mAuditLogAsHtml = audit_log_as_html( mCtx, mAuditLogError );
00263 }
00264 
00265 void Kleo::QGpgMEJob::doSlotCancel() {
00266   mCtx->cancelPendingOperation();
00267 }
00268 
00269 void Kleo::QGpgMEJob::showProgress( const char * what, int type, int current, int total ) {
00270   doEmitProgressSignal( QGpgMEProgressTokenMapper::instance()->map( what, type, current, total ), current, total );
00271 }
00272 
00273 char * Kleo::QGpgMEJob::getPassphrase( const char * useridHint, const char * /*description*/,
00274                        bool previousWasBad, bool & canceled ) {
00275   // DF: here, description is the key fingerprint, twice, then "17 0". Not really descriptive.
00276   //     So I'm ignoring TQString::fromLocal8Bit( description ) )
00277   TQString msg = previousWasBad ?
00278                 i18n( "You need a passphrase to unlock the secret key for user:<br/> %1 (retry)" ) :
00279                 i18n( "You need a passphrase to unlock the secret key for user:<br/> %1" );
00280   msg = msg.arg( TQString::fromUtf8( useridHint ) ) + "<br/><br/>";
00281   msg.prepend( "<qt>" );
00282   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." ) + "<br/>";
00283   const TQString gpgAgent = TDEStandardDirs::findExe( "gpg-agent" );
00284   if ( !gpgAgent.isEmpty() ) {
00285     msg += i18n( "gpg-agent was found in %1, but does not appear to be running." )
00286            .arg( gpgAgent );
00287   } else {
00288     msg += i18n( "gpg-agent is part of gnupg-%1, which you can download from %2" )
00289            .arg( "1.9" )
00290            .arg( "http://www.gnupg.org/download" );  // add #gnupg2 if you can make this a real link
00291   }
00292   msg += "<br/>";
00293   msg += i18n( "For information on how to set up gpg-agent, see %1" )
00294          .arg( "http://userbase.kde.org/KMail/PGP_MIME" );
00295   msg += "<br/><br/>";
00296   msg += i18n( "Enter passphrase:" );
00297   Kleo::PassphraseDialog dlg( msg, i18n("Passphrase Dialog") );
00298   if ( dlg.exec() != TQDialog::Accepted ) {
00299     canceled = true;
00300     return 0;
00301   }
00302   canceled = false;
00303   // gpgme++ free()s it, and we need to copy as long as dlg isn't deleted :o
00304   return strdup( dlg.passphrase() );
00305 }