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 void Kleo::QGpgMEJob::doSlotOperationDoneEvent( GpgME::Context * context, const GpgME::Error & e ) {
00238 if ( context == mCtx ) {
00239 doEmitDoneSignal();
00240 doOperationDoneEvent( e );
00241 mThis->deleteLater();
00242 }
00243 }
00244
00245 void Kleo::QGpgMEJob::doSlotCancel() {
00246 mCtx->cancelPendingOperation();
00247 }
00248
00249 void Kleo::QGpgMEJob::showProgress( const char * what, int type, int current, int total ) {
00250 doEmitProgressSignal( QGpgMEProgressTokenMapper::instance()->map( what, type, current, total ), current, total );
00251 }
00252
00253 char * Kleo::QGpgMEJob::getPassphrase( const char * useridHint, const char * ,
00254 bool previousWasBad, bool & canceled ) {
00255
00256
00257 QString msg = previousWasBad ?
00258 i18n( "You need a passphrase to unlock the secret key for user:<br/> %1 (retry)" ) :
00259 i18n( "You need a passphrase to unlock the secret key for user:<br/> %1" );
00260 msg = msg.arg( QString::fromUtf8( useridHint ) ) + "<br/><br/>";
00261 msg.prepend( "<qt>" );
00262 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/>";
00263 const QString gpgAgent = KStandardDirs::findExe( "gpg-agent" );
00264 if ( !gpgAgent.isEmpty() ) {
00265 msg += i18n( "gpg-agent was found in %1, but does not appear to be running." )
00266 .arg( gpgAgent );
00267 } else {
00268 msg += i18n( "gpg-agent is part of gnupg-%1, which you can download from %2" )
00269 .arg( "1.9" )
00270 .arg( "http://www.gnupg.org/download" );
00271 }
00272 msg += "<br/>";
00273 msg += i18n( "For information on how to set up gpg-agent, see %1" )
00274 .arg( "http://kmail.kde.org/kmail-pgpmime-howto.html" );
00275 msg += "<br/><br/>";
00276 msg += i18n( "Enter passphrase:" );
00277 Kleo::PassphraseDialog dlg( msg, i18n("Passphrase Dialog") );
00278 if ( dlg.exec() != QDialog::Accepted ) {
00279 canceled = true;
00280 return 0;
00281 }
00282 canceled = false;
00283
00284 return strdup( dlg.passphrase() );
00285 }