qgpgmejob.cpp
1/*
2 qgpgmejob.cpp
3
4 This file is part of libkleopatra, the KDE keymanagement library
5 Copyright (c) 2004 Klarälvdalens Datakonsult AB
6
7 Libkleopatra is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11
12 Libkleopatra is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
21 In addition, as a special exception, the copyright holders give
22 permission to link the code of this program with any edition of
23 the TQt library by Trolltech AS, Norway (or with modified versions
24 of TQt that use the same license as TQt), and distribute linked
25 combinations including the two. You must obey the GNU General
26 Public License in all respects for all of the code used other than
27 TQt. If you modify this file, you may extend this exception to
28 your version of the file, but you are not obligated to do so. If
29 you do not wish to do so, delete this exception statement from
30 your version.
31*/
32
33#ifdef HAVE_CONFIG_H
34#include <config.h>
35#endif
36
37#include "qgpgmejob.h"
38#include "qgpgmeprogresstokenmapper.h"
39
40#include <kleo/job.h>
41#include <ui/passphrasedialog.h>
42
43#include <qgpgme/eventloopinteractor.h>
44#include <qgpgme/dataprovider.h>
45
46#include <gpgmepp/context.h>
47#include <gpgmepp/data.h>
48
49#include <tdelocale.h>
50#include <tdestandarddirs.h>
51
52#include <tqstring.h>
53#include <tqstringlist.h>
54
55#include <algorithm>
56
57#include <assert.h>
58#include <stdlib.h>
59#include <string.h>
60
61namespace {
62 class InvarianceChecker {
63 public:
64#ifdef NDEBUG
65 InvarianceChecker( const Kleo::QGpgMEJob * ) {}
66#else
67 InvarianceChecker( const Kleo::QGpgMEJob * job )
68 : _this( job )
69 {
70 assert( _this );
71 _this->checkInvariants();
72 }
73 ~InvarianceChecker() {
74 _this->checkInvariants();
75 }
76 private:
77 const Kleo::QGpgMEJob * _this;
78#endif
79 };
80}
81
82Kleo::QGpgMEJob::QGpgMEJob( Kleo::Job * _this, GpgME::Context * context )
83 : GpgME::ProgressProvider(),
84 GpgME::PassphraseProvider(),
85 mThis( _this ),
86 mCtx( context ),
87 mInData( 0 ),
88 mInDataDataProvider( 0 ),
89 mOutData( 0 ),
90 mOutDataDataProvider( 0 ),
91 mPatterns( 0 ),
92 mReplacedPattern( 0 ),
93 mNumPatterns( 0 ),
94 mChunkSize( 1024 ),
95 mPatternStartIndex( 0 ), mPatternEndIndex( 0 )
96{
97 InvarianceChecker check( this );
98 assert( context );
99 TQObject::connect( QGpgME::EventLoopInteractor::instance(), TQ_SIGNAL(aboutToDestroy()),
100 _this, TQ_SLOT(slotCancel()) );
101 context->setProgressProvider( this );
102 // (mmutz) work around a gpgme bug in versions at least <= 0.9.0.
103 // These versions will return GPG_ERR_NOT_IMPLEMENTED from
104 // a CMS sign operation when a passphrase callback is set.
105 if ( context->protocol() == GpgME::Context::OpenPGP )
106 context->setPassphraseProvider( this );
107}
108
109void Kleo::QGpgMEJob::checkInvariants() const {
110#ifndef NDEBUG
111 if ( mPatterns ) {
112 assert( mPatterns[mNumPatterns] == 0 );
113 if ( mPatternEndIndex > 0 ) {
114 assert( mPatternEndIndex > mPatternStartIndex );
115 assert( mPatternEndIndex - mPatternStartIndex == mChunkSize );
116 } else {
117 assert( mPatternEndIndex == mPatternStartIndex );
118 }
119 if ( mPatternEndIndex < mNumPatterns ) {
120 assert( mPatterns[mPatternEndIndex] == 0 );
121 assert( mReplacedPattern != 0 );
122 } else {
123 assert( mReplacedPattern == 0 );
124 }
125 } else {
126 assert( mNumPatterns == 0 );
127 assert( mPatternStartIndex == 0 );
128 assert( mPatternEndIndex == 0 );
129 assert( mReplacedPattern == 0 );
130 }
131#endif
132}
133
134Kleo::QGpgMEJob::~QGpgMEJob() {
135 InvarianceChecker check( this );
136 delete mCtx; mCtx = 0;
137 delete mInData; mInData = 0;
138 delete mInDataDataProvider; mInDataDataProvider = 0;
139 delete mOutData; mOutData = 0;
140 delete mOutDataDataProvider; mOutDataDataProvider = 0;
141 deleteAllPatterns();
142}
143
144void Kleo::QGpgMEJob::deleteAllPatterns() {
145 if ( mPatterns )
146 for ( unsigned int i = 0 ; i < mNumPatterns ; ++i )
147 free( (void*)mPatterns[i] );
148 free( (void*)mReplacedPattern ); mReplacedPattern = 0;
149 delete[] mPatterns; mPatterns = 0;
150 mPatternEndIndex = mPatternStartIndex = mNumPatterns = 0;
151}
152
154 mCtx->setManagedByEventLoopInteractor( true );
155 TQObject::connect( QGpgME::EventLoopInteractor::instance(),
156 TQ_SIGNAL(operationDoneEventSignal(GpgME::Context*,const GpgME::Error&)),
157 mThis, TQ_SLOT(slotOperationDoneEvent(GpgME::Context*,const GpgME::Error&)) );
158}
159
160void Kleo::QGpgMEJob::setPatterns( const TQStringList & sl, bool allowEmpty ) {
161 InvarianceChecker check( this );
162 deleteAllPatterns();
163 // create a new null-terminated C array of char* from patterns:
164 mPatterns = new const char*[ sl.size() + 1 ];
165 const char* * pat_it = mPatterns;
166 mNumPatterns = 0;
167 for ( TQStringList::const_iterator it = sl.begin() ; it != sl.end() ; ++it ) {
168 if ( (*it).isNull() )
169 continue;
170 if ( (*it).isEmpty() && !allowEmpty )
171 continue;
172 *pat_it++ = strdup( (*it).utf8().data() );
173 ++mNumPatterns;
174 }
175 *pat_it++ = 0;
176 mReplacedPattern = 0;
177 mPatternEndIndex = mChunkSize = mNumPatterns;
178}
179
180void Kleo::QGpgMEJob::setChunkSize( unsigned int chunksize ) {
181 InvarianceChecker check( this );
182 if ( mReplacedPattern ) {
183 mPatterns[mPatternEndIndex] = mReplacedPattern;
184 mReplacedPattern = 0;
185 }
186 mChunkSize = std::min( chunksize, mNumPatterns );
187 mPatternStartIndex = 0;
188 mPatternEndIndex = mChunkSize;
189 mReplacedPattern = mPatterns[mPatternEndIndex];
190 mPatterns[mPatternEndIndex] = 0;
191}
192
194 InvarianceChecker check( this );
195 if ( mReplacedPattern ) {
196 mPatterns[mPatternEndIndex] = mReplacedPattern;
197 mReplacedPattern = 0;
198 }
199 mPatternStartIndex += mChunkSize;
200 mPatternEndIndex += mChunkSize;
201 if ( mPatternEndIndex < mNumPatterns ) { // could safely be <=, but the last entry is NULL anyway
202 mReplacedPattern = mPatterns[mPatternEndIndex];
203 mPatterns[mPatternEndIndex] = 0;
204 }
205 return patterns();
206}
207
208const char* * Kleo::QGpgMEJob::patterns() const {
209 InvarianceChecker check( this );
210 if ( mPatternStartIndex < mNumPatterns )
211 return mPatterns + mPatternStartIndex;
212 return 0;
213}
214
215GpgME::Error Kleo::QGpgMEJob::setSigningKeys( const std::vector<GpgME::Key> & signers ) {
216 mCtx->clearSigningKeys();
217 for ( std::vector<GpgME::Key>::const_iterator it = signers.begin() ; it != signers.end() ; ++it ) {
218 if ( (*it).isNull() )
219 continue;
220 if ( const GpgME::Error err = mCtx->addSigningKey( *it ) )
221 return err;
222 }
223 return 0;
224}
225
226void Kleo::QGpgMEJob::createInData( const TQByteArray & in ) {
227 mInDataDataProvider = new QGpgME::TQByteArrayDataProvider( in );
228 mInData = new GpgME::Data( mInDataDataProvider );
229 assert( !mInData->isNull() );
230}
231
233 mOutDataDataProvider = new QGpgME::TQByteArrayDataProvider();
234 mOutData = new GpgME::Data( mOutDataDataProvider );
235 assert( !mOutData->isNull() );
236}
237
238static const unsigned int GetAuditLogFlags = GpgME::Context::AuditLogWithHelp|GpgME::Context::HtmlAuditLog;
239
240static TQString audit_log_as_html( GpgME::Context * ctx, GpgME::Error & err ) {
241 assert( ctx );
242 QGpgME::TQByteArrayDataProvider dp;
243 GpgME::Data data( &dp );
244 assert( !data.isNull() );
245 if ( ( err = ctx->getAuditLog( data, GetAuditLogFlags ) ) )
246 return TQString();
247 const TQByteArray ba = dp.data();
248 return TQString::fromUtf8( ba.data(), ba.size() );
249}
250
251void Kleo::QGpgMEJob::doSlotOperationDoneEvent( GpgME::Context * context, const GpgME::Error & e ) {
252 if ( context == mCtx ) {
253 doEmitDoneSignal();
254 doOperationDoneEvent( e );
255 mThis->deleteLater();
256 }
257}
258
260 if ( !mCtx )
261 return;
262 mAuditLogAsHtml = audit_log_as_html( mCtx, mAuditLogError );
263}
264
265void Kleo::QGpgMEJob::doSlotCancel() {
266 mCtx->cancelPendingOperation();
267}
268
269void Kleo::QGpgMEJob::showProgress( const char * what, int type, int current, int total ) {
270 doEmitProgressSignal( QGpgMEProgressTokenMapper::instance()->map( what, type, current, total ), current, total );
271}
272
273char * Kleo::QGpgMEJob::getPassphrase( const char * useridHint, const char * /*description*/,
274 bool previousWasBad, bool & canceled ) {
275 // DF: here, description is the key fingerprint, twice, then "17 0". Not really descriptive.
276 // So I'm ignoring TQString::fromLocal8Bit( description ) )
277 TQString msg = previousWasBad ?
278 i18n( "You need a passphrase to unlock the secret key for user:<br/> %1 (retry)" ) :
279 i18n( "You need a passphrase to unlock the secret key for user:<br/> %1" );
280 msg = msg.arg( TQString::fromUtf8( useridHint ) ) + "<br/><br/>";
281 msg.prepend( "<qt>" );
282 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/>";
283 const TQString gpgAgent = TDEStandardDirs::findExe( "gpg-agent" );
284 if ( !gpgAgent.isEmpty() ) {
285 msg += i18n( "gpg-agent was found in %1, but does not appear to be running." )
286 .arg( gpgAgent );
287 } else {
288 msg += i18n( "gpg-agent is part of gnupg-%1, which you can download from %2" )
289 .arg( "1.9" )
290 .arg( "http://www.gnupg.org/download" ); // add #gnupg2 if you can make this a real link
291 }
292 msg += "<br/>";
293 msg += i18n( "For information on how to set up gpg-agent, see %1" )
294 .arg( "http://userbase.kde.org/KMail/PGP_MIME" );
295 msg += "<br/><br/>";
296 msg += i18n( "Enter passphrase:" );
297 Kleo::PassphraseDialog dlg( msg, i18n("Passphrase Dialog") );
298 if ( dlg.exec() != TQDialog::Accepted ) {
299 canceled = true;
300 return 0;
301 }
302 canceled = false;
303 // gpgme++ free()s it, and we need to copy as long as dlg isn't deleted :o
304 return strdup( dlg.passphrase().utf8() );
305}
An abstract base class for asynchronous crypto operations.
Definition: job.h:64
This is a hackish helper class to avoid code duplication in this backend's Kleo::Job subclasses.
Definition: qgpgmejob.h:78
void createOutData()
Definition: qgpgmejob.cpp:232
void doSlotOperationDoneEvent(GpgME::Context *context, const GpgME::Error &e)
Definition: qgpgmejob.cpp:251
void getAuditLog()
Definition: qgpgmejob.cpp:259
const char ** nextChunk()
Definition: qgpgmejob.cpp:193
void setPatterns(const TQStringList &sl, bool allowEmpty=false)
Definition: qgpgmejob.cpp:160
GpgME::Error setSigningKeys(const std::vector< GpgME::Key > &signers)
Definition: qgpgmejob.cpp:215
void setChunkSize(unsigned int size)
Definition: qgpgmejob.cpp:180
void hookupContextToEventLoopInteractor()
Definition: qgpgmejob.cpp:153
void createInData(const TQByteArray &in)
Definition: qgpgmejob.cpp:226
const char ** patterns() const
Definition: qgpgmejob.cpp:208