00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
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 <klocale.h>
00050 #include <kstandarddirs.h>
00051
00052 #include <qstring.h>
00053 #include <qstringlist.h>
00054
00055 #include <algorithm>
00056
00057 #include <assert.h>
00058 #include <string.h>
00059
00060 namespace {
00061 class InvarianceChecker {
00062 public:
00063 #ifdef NDEBUG
00064 InvarianceChecker( const Kleo::QGpgMEJob * ) {}
00065 #else
00066 InvarianceChecker( const Kleo::QGpgMEJob * job )
00067 : _this( job )
00068 {
00069 assert( _this );
00070 _this->checkInvariants();
00071 }
00072 ~InvarianceChecker() {
00073 _this->checkInvariants();
00074 }
00075 private:
00076 const Kleo::QGpgMEJob * _this;
00077 #endif
00078 };
00079 }
00080
00081 Kleo::QGpgMEJob::QGpgMEJob( Kleo::Job * _this, GpgME::Context * context )
00082 : GpgME::ProgressProvider(),
00083 GpgME::PassphraseProvider(),
00084 mThis( _this ),
00085 mCtx( context ),
00086 mInData( 0 ),
00087 mInDataDataProvider( 0 ),
00088 mOutData( 0 ),
00089 mOutDataDataProvider( 0 ),
00090 mPatterns( 0 ),
00091 mReplacedPattern( 0 ),
00092 mNumPatterns( 0 ),
00093 mChunkSize( 1024 ),
00094 mPatternStartIndex( 0 ), mPatternEndIndex( 0 )
00095 {
00096 InvarianceChecker check( this );
00097 assert( context );
00098 QObject::connect( QGpgME::EventLoopInteractor::instance(), SIGNAL(aboutToDestroy()),
00099 _this, SLOT(slotCancel()) );
00100 context->setProgressProvider( this );
00101
00102
00103
00104 if ( context->protocol() == GpgME::Context::OpenPGP )
00105 context->setPassphraseProvider( this );
00106 }
00107
00108 void Kleo::QGpgMEJob::checkInvariants() const {
00109 #ifndef NDEBUG
00110 if ( mPatterns ) {
00111 assert( mPatterns[mNumPatterns] == 0 );
00112 if ( mPatternEndIndex > 0 ) {
00113 assert( mPatternEndIndex > mPatternStartIndex );
00114 assert( mPatternEndIndex - mPatternStartIndex == mChunkSize );
00115 } else {
00116 assert( mPatternEndIndex == mPatternStartIndex );
00117 }
00118 if ( mPatternEndIndex < mNumPatterns ) {
00119 assert( mPatterns[mPatternEndIndex] == 0 );
00120 assert( mReplacedPattern != 0 );
00121 } else {
00122 assert( mReplacedPattern == 0 );
00123 }
00124 } else {
00125 assert( mNumPatterns == 0 );
00126 assert( mPatternStartIndex == 0 );
00127 assert( mPatternEndIndex == 0 );
00128 assert( mReplacedPattern == 0 );
00129 }
00130 #endif
00131 }
00132
00133 Kleo::QGpgMEJob::~QGpgMEJob() {
00134 InvarianceChecker check( this );
00135 delete mCtx; mCtx = 0;
00136 delete mInData; mInData = 0;
00137 delete mInDataDataProvider; mInDataDataProvider = 0;
00138 delete mOutData; mOutData = 0;
00139 delete mOutDataDataProvider; mOutDataDataProvider = 0;
00140 deleteAllPatterns();
00141 }
00142
00143 void Kleo::QGpgMEJob::deleteAllPatterns() {
00144 if ( mPatterns )
00145 for ( unsigned int i = 0 ; i < mNumPatterns ; ++i )
00146 free( (void*)mPatterns[i] );
00147 free( (void*)mReplacedPattern ); mReplacedPattern = 0;
00148 delete[] mPatterns; mPatterns = 0;
00149 mPatternEndIndex = mPatternStartIndex = mNumPatterns = 0;
00150 }
00151
00152 void Kleo::QGpgMEJob::hookupContextToEventLoopInteractor() {
00153 mCtx->setManagedByEventLoopInteractor( true );
00154 QObject::connect( QGpgME::EventLoopInteractor::instance(),
00155 SIGNAL(operationDoneEventSignal(GpgME::Context*,const GpgME::Error&)),
00156 mThis, SLOT(slotOperationDoneEvent(GpgME::Context*,const GpgME::Error&)) );
00157 }
00158
00159 void Kleo::QGpgMEJob::setPatterns( const QStringList & sl, bool allowEmpty ) {
00160 InvarianceChecker check( this );
00161 deleteAllPatterns();
00162
00163 mPatterns = new const char*[ sl.size() + 1 ];
00164 const char* * pat_it = mPatterns;
00165 mNumPatterns = 0;
00166 for ( QStringList::const_iterator it = sl.begin() ; it != sl.end() ; ++it ) {
00167 if ( (*it).isNull() )
00168 continue;
00169 if ( (*it).isEmpty() && !allowEmpty )
00170 continue;
00171 *pat_it++ = strdup( (*it).utf8().data() );
00172 ++mNumPatterns;
00173 }
00174 *pat_it++ = 0;
00175 mReplacedPattern = 0;
00176 mPatternEndIndex = mChunkSize = mNumPatterns;
00177 }
00178
00179 void Kleo::QGpgMEJob::setChunkSize( unsigned int chunksize ) {
00180 InvarianceChecker check( this );
00181 if ( mReplacedPattern ) {
00182 mPatterns[mPatternEndIndex] = mReplacedPattern;
00183 mReplacedPattern = 0;
00184 }
00185 mChunkSize = std::min( chunksize, mNumPatterns );
00186 mPatternStartIndex = 0;
00187 mPatternEndIndex = mChunkSize;
00188 mReplacedPattern = mPatterns[mPatternEndIndex];
00189 mPatterns[mPatternEndIndex] = 0;
00190 }
00191
00192 const char* * Kleo::QGpgMEJob::nextChunk() {
00193 InvarianceChecker check( this );
00194 if ( mReplacedPattern ) {
00195 mPatterns[mPatternEndIndex] = mReplacedPattern;
00196 mReplacedPattern = 0;
00197 }
00198 mPatternStartIndex += mChunkSize;
00199 mPatternEndIndex += mChunkSize;
00200 if ( mPatternEndIndex < mNumPatterns ) {
00201 mReplacedPattern = mPatterns[mPatternEndIndex];
00202 mPatterns[mPatternEndIndex] = 0;
00203 }
00204 return patterns();
00205 }
00206
00207 const char* * Kleo::QGpgMEJob::patterns() const {
00208 InvarianceChecker check( this );
00209 if ( mPatternStartIndex < mNumPatterns )
00210 return mPatterns + mPatternStartIndex;
00211 return 0;
00212 }
00213
00214 GpgME::Error Kleo::QGpgMEJob::setSigningKeys( const std::vector<GpgME::Key> & signers ) {
00215 mCtx->clearSigningKeys();
00216 for ( std::vector<GpgME::Key>::const_iterator it = signers.begin() ; it != signers.end() ; ++it ) {
00217 if ( (*it).isNull() )
00218 continue;
00219 if ( const GpgME::Error err = mCtx->addSigningKey( *it ) )
00220 return err;
00221 }
00222 return 0;
00223 }
00224
00225 void Kleo::QGpgMEJob::createInData( const QByteArray & in ) {
00226 mInDataDataProvider = new QGpgME::QByteArrayDataProvider( in );
00227 mInData = new GpgME::Data( mInDataDataProvider );
00228 assert( !mInData->isNull() );
00229 }
00230
00231 void Kleo::QGpgMEJob::createOutData() {
00232 mOutDataDataProvider = new QGpgME::QByteArrayDataProvider();
00233 mOutData = new GpgME::Data( mOutDataDataProvider );
00234 assert( !mOutData->isNull() );
00235 }
00236
00237 static const unsigned int GetAuditLogFlags = GpgME::Context::AuditLogWithHelp|GpgME::Context::HtmlAuditLog;
00238
00239 static QString audit_log_as_html( GpgME::Context * ctx, GpgME::Error & err ) {
00240 assert( ctx );
00241 QGpgME::QByteArrayDataProvider dp;
00242 GpgME::Data data( &dp );
00243 assert( !data.isNull() );
00244 if ( ( err = ctx->getAuditLog( data, GetAuditLogFlags ) ) )
00245 return QString();
00246 const QByteArray ba = dp.data();
00247 return QString::fromUtf8( ba.data(), ba.size() );
00248 }
00249
00250 void Kleo::QGpgMEJob::doSlotOperationDoneEvent( GpgME::Context * context, const GpgME::Error & e ) {
00251 if ( context == mCtx ) {
00252 doEmitDoneSignal();
00253 doOperationDoneEvent( e );
00254 mThis->deleteLater();
00255 }
00256 }
00257
00258 void Kleo::QGpgMEJob::getAuditLog() {
00259 if ( !mCtx )
00260 return;
00261 mAuditLogAsHtml = audit_log_as_html( mCtx, mAuditLogError );
00262 }
00263
00264 void Kleo::QGpgMEJob::doSlotCancel() {
00265 mCtx->cancelPendingOperation();
00266 }
00267
00268 void Kleo::QGpgMEJob::showProgress( const char * what, int type, int current, int total ) {
00269 doEmitProgressSignal( QGpgMEProgressTokenMapper::instance()->map( what, type, current, total ), current, total );
00270 }
00271
00272 char * Kleo::QGpgMEJob::getPassphrase( const char * useridHint, const char * ,
00273 bool previousWasBad, bool & canceled ) {
00274
00275
00276 QString msg = previousWasBad ?
00277 i18n( "You need a passphrase to unlock the secret key for user:<br/> %1 (retry)" ) :
00278 i18n( "You need a passphrase to unlock the secret key for user:<br/> %1" );
00279 msg = msg.arg( QString::fromUtf8( useridHint ) ) + "<br/><br/>";
00280 msg.prepend( "<qt>" );
00281 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/>";
00282 const QString gpgAgent = KStandardDirs::findExe( "gpg-agent" );
00283 if ( !gpgAgent.isEmpty() ) {
00284 msg += i18n( "gpg-agent was found in %1, but does not appear to be running." )
00285 .arg( gpgAgent );
00286 } else {
00287 msg += i18n( "gpg-agent is part of gnupg-%1, which you can download from %2" )
00288 .arg( "1.9" )
00289 .arg( "http://www.gnupg.org/download" );
00290 }
00291 msg += "<br/>";
00292 msg += i18n( "For information on how to set up gpg-agent, see %1" )
00293 .arg( "http://kmail.kde.org/kmail-pgpmime-howto.html" );
00294 msg += "<br/><br/>";
00295 msg += i18n( "Enter passphrase:" );
00296 Kleo::PassphraseDialog dlg( msg, i18n("Passphrase Dialog") );
00297 if ( dlg.exec() != QDialog::Accepted ) {
00298 canceled = true;
00299 return 0;
00300 }
00301 canceled = false;
00302
00303 return strdup( dlg.passphrase() );
00304 }