certmanager/lib

keyrequester.cpp
1/*
2 keyrequester.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 Based on kpgpui.cpp
34 Copyright (C) 2001,2002 the KPGP authors
35 See file libtdenetwork/AUTHORS.kpgp for details
36
37 This file is part of KPGP, the KDE PGP/GnuPG support library.
38
39 KPGP is free software; you can redistribute it and/or modify
40 it under the terms of the GNU General Public License as published by
41 the Free Software Foundation; either version 2 of the License, or
42 (at your option) any later version.
43
44 You should have received a copy of the GNU General Public License
45 along with this program; if not, write to the Free Software Foundation,
46 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
47 */
48
49#ifdef HAVE_CONFIG_H
50#include <config.h>
51#endif
52
53#include "keyrequester.h"
54
55#include "keyselectiondialog.h"
56
57#include <kleo/keylistjob.h>
58#include <kleo/dn.h>
59#include <kleo/cryptobackendfactory.h>
60
61// gpgme++
62#include <gpgmepp/key.h>
63#include <gpgmepp/keylistresult.h>
64
65// KDE
66#include <tdelocale.h>
67#include <kiconloader.h>
68#include <kdialog.h>
69#include <kdebug.h>
70#include <tdemessagebox.h>
71#include <kpushbutton.h>
72
73// TQt
74#include <tqapplication.h>
75#include <tqlayout.h>
76#include <tqtooltip.h>
77#include <tqstring.h>
78#include <tqstringlist.h>
79#include <tqlabel.h>
80#include <tqregexp.h>
81
82#include <assert.h>
83
84Kleo::KeyRequester::KeyRequester( unsigned int allowedKeys, bool multipleKeys,
85 TQWidget * parent, const char * name )
86 : TQWidget( parent, name ),
87 mOpenPGPBackend( 0 ),
88 mSMIMEBackend( 0 ),
89 mMulti( multipleKeys ),
90 mKeyUsage( allowedKeys ),
91 mJobs( 0 ),
92 d( 0 )
93{
94 init();
95}
96
97Kleo::KeyRequester::KeyRequester( TQWidget * parent, const char * name )
98 : TQWidget( parent, name ),
99 mOpenPGPBackend( 0 ),
100 mSMIMEBackend( 0 ),
101 mMulti( false ),
102 mKeyUsage( 0 ),
103 mJobs( 0 ),
104 d( 0 )
105{
106 init();
107}
108
109void Kleo::KeyRequester::init()
110{
111 TQHBoxLayout * hlay = new TQHBoxLayout( this, 0, KDialog::spacingHint() );
112
113 // the label where the key id is to be displayed:
114 mLabel = new TQLabel( this );
115 mLabel->setFrameStyle( TQFrame::Panel | TQFrame::Sunken );
116
117 // the button to unset any key:
118 mEraseButton = new KPushButton( this );
119 mEraseButton->setAutoDefault( false );
120 mEraseButton->setSizePolicy( TQSizePolicy( TQSizePolicy::Minimum,
121 TQSizePolicy::Minimum ) );
122 mEraseButton->setIconSet( SmallIconSet( TQApplication::reverseLayout() ? "locationbar_erase" : "clear_left" ) );
123 TQToolTip::add( mEraseButton, i18n("Clear") );
124
125 // the button to call the KeySelectionDialog:
126 mDialogButton = new TQPushButton( i18n("Change..."), this );
127 mDialogButton->setAutoDefault( false );
128
129 hlay->addWidget( mLabel, 1 );
130 hlay->addWidget( mEraseButton );
131 hlay->addWidget( mDialogButton );
132
133 connect( mEraseButton, TQ_SIGNAL(clicked()), TQ_SLOT(slotEraseButtonClicked()) );
134 connect( mDialogButton, TQ_SIGNAL(clicked()), TQ_SLOT(slotDialogButtonClicked()) );
135
136 setSizePolicy( TQSizePolicy( TQSizePolicy::MinimumExpanding,
137 TQSizePolicy::Fixed ) );
138
139 setAllowedKeys( mKeyUsage );
140}
141
142Kleo::KeyRequester::~KeyRequester() {
143
144}
145
146const std::vector<GpgME::Key> & Kleo::KeyRequester::keys() const {
147 return mKeys;
148}
149
150const GpgME::Key & Kleo::KeyRequester::key() const {
151 if ( mKeys.empty() )
152 return GpgME::Key::null;
153 else
154 return mKeys.front();
155}
156
157void Kleo::KeyRequester::setKeys( const std::vector<GpgME::Key> & keys ) {
158 mKeys.clear();
159 for ( std::vector<GpgME::Key>::const_iterator it = keys.begin() ; it != keys.end() ; ++it )
160 if ( !it->isNull() )
161 mKeys.push_back( *it );
162 updateKeys();
163}
164
165void Kleo::KeyRequester::setKey( const GpgME::Key & key ) {
166 mKeys.clear();
167 if ( !key.isNull() )
168 mKeys.push_back( key );
169 updateKeys();
170}
171
172TQString Kleo::KeyRequester::fingerprint() const {
173 if ( mKeys.empty() )
174 return TQString();
175 else
176 return mKeys.front().primaryFingerprint();
177}
178
179TQStringList Kleo::KeyRequester::fingerprints() const {
180 TQStringList result;
181 for ( std::vector<GpgME::Key>::const_iterator it = mKeys.begin() ; it != mKeys.end() ; ++it )
182 if ( !it->isNull() )
183 if ( const char * fpr = it->primaryFingerprint() )
184 result.push_back( fpr );
185 return result;
186}
187
188void Kleo::KeyRequester::setFingerprint( const TQString & fingerprint ) {
189 startKeyListJob( fingerprint );
190}
191
192void Kleo::KeyRequester::setFingerprints( const TQStringList & fingerprints ) {
193 startKeyListJob( fingerprints );
194}
195
196void Kleo::KeyRequester::updateKeys() {
197 if ( mKeys.empty() ) {
198 mLabel->clear();
199 return;
200 }
201 if ( mKeys.size() > 1 )
202 setMultipleKeysEnabled( true );
203
204 TQStringList labelTexts;
205 TQString toolTipText;
206 for ( std::vector<GpgME::Key>::const_iterator it = mKeys.begin() ; it != mKeys.end() ; ++it ) {
207 if ( it->isNull() )
208 continue;
209 const TQString fpr = it->primaryFingerprint();
210 labelTexts.push_back( fpr.right(8) );
211 toolTipText += fpr.right(8) + ": ";
212 if ( const char * uid = it->userID(0).id() )
213 if ( it->protocol() == GpgME::Context::OpenPGP )
214 toolTipText += TQString::fromUtf8( uid );
215 else
216 toolTipText += Kleo::DN( uid ).prettyDN();
217 else
218 toolTipText += i18n("<unknown>");
219 toolTipText += '\n';
220 }
221
222 mLabel->setText( labelTexts.join(", ") );
223 TQToolTip::remove( mLabel );
224 TQToolTip::add( mLabel, toolTipText );
225}
226
227#ifndef __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
228#define __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
229static void showKeyListError( TQWidget * parent, const GpgME::Error & err ) {
230 assert( err );
231 const TQString msg = i18n( "<qt><p>An error occurred while fetching "
232 "the keys from the backend:</p>"
233 "<p><b>%1</b></p></qt>" )
234 .arg( TQString::fromLocal8Bit( err.asString() ) );
235
236 KMessageBox::error( parent, msg, i18n( "Key Listing Failed" ) );
237}
238#endif // __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
239
240void Kleo::KeyRequester::startKeyListJob( const TQStringList & fingerprints ) {
241 if ( !mSMIMEBackend && !mOpenPGPBackend )
242 return;
243
244 mTmpKeys.clear();
245 mJobs = 0;
246
247 unsigned int count = 0;
248 for ( TQStringList::const_iterator it = fingerprints.begin() ; it != fingerprints.end() ; ++it )
249 if ( !(*it).stripWhiteSpace().isEmpty() )
250 ++count;
251
252 if ( !count ) {
253 // don't fall into the trap that an empty pattern means
254 // "return all keys" :)
255 setKey( GpgME::Key::null );
256 return;
257 }
258
259 if ( mOpenPGPBackend ) {
260 KeyListJob * job = mOpenPGPBackend->keyListJob( false ); // local, no sigs
261 if ( !job ) {
262 KMessageBox::error( this,
263 i18n("The OpenPGP backend does not support listing keys. "
264 "Check your installation."),
265 i18n("Key Listing Failed") );
266 } else {
267 connect( job, TQ_SIGNAL(result(const GpgME::KeyListResult&)),
268 TQ_SLOT(slotKeyListResult(const GpgME::KeyListResult&)) );
269 connect( job, TQ_SIGNAL(nextKey(const GpgME::Key&)),
270 TQ_SLOT(slotNextKey(const GpgME::Key&)) );
271
272 const GpgME::Error err = job->start( fingerprints,
273 mKeyUsage & Kleo::KeySelectionDialog::SecretKeys &&
274 !( mKeyUsage & Kleo::KeySelectionDialog::PublicKeys ) );
275
276 if ( err )
277 showKeyListError( this, err );
278 else
279 ++mJobs;
280 }
281 }
282
283 if ( mSMIMEBackend ) {
284 KeyListJob * job = mSMIMEBackend->keyListJob( false ); // local, no sigs
285 if ( !job ) {
286 KMessageBox::error( this,
287 i18n("The S/MIME backend does not support listing keys. "
288 "Check your installation."),
289 i18n("Key Listing Failed") );
290 } else {
291 connect( job, TQ_SIGNAL(result(const GpgME::KeyListResult&)),
292 TQ_SLOT(slotKeyListResult(const GpgME::KeyListResult&)) );
293 connect( job, TQ_SIGNAL(nextKey(const GpgME::Key&)),
294 TQ_SLOT(slotNextKey(const GpgME::Key&)) );
295
296 const GpgME::Error err = job->start( fingerprints,
297 mKeyUsage & Kleo::KeySelectionDialog::SecretKeys &&
298 !( mKeyUsage & Kleo::KeySelectionDialog::PublicKeys ) );
299
300 if ( err )
301 showKeyListError( this, err );
302 else
303 ++mJobs;
304 }
305 }
306
307 if ( mJobs > 0 ) {
308 mEraseButton->setEnabled( false );
309 mDialogButton->setEnabled( false );
310 }
311}
312
313void Kleo::KeyRequester::slotNextKey( const GpgME::Key & key ) {
314 if ( !key.isNull() )
315 mTmpKeys.push_back( key );
316}
317
318void Kleo::KeyRequester::slotKeyListResult( const GpgME::KeyListResult & res ) {
319 if ( res.error() )
320 showKeyListError( this, res.error() );
321
322 if ( --mJobs <= 0 ) {
323 mEraseButton->setEnabled( true );
324 mDialogButton->setEnabled( true );
325
326 setKeys( mTmpKeys );
327 mTmpKeys.clear();
328 }
329}
330
331
332void Kleo::KeyRequester::slotDialogButtonClicked() {
333 KeySelectionDialog * dlg = mKeys.empty()
334 ? new KeySelectionDialog( mDialogCaption, mDialogMessage, mInitialQuery, mKeyUsage, mMulti, false, this )
335 : new KeySelectionDialog( mDialogCaption, mDialogCaption, mKeys, mKeyUsage, mMulti, false, this ) ;
336
337 if ( dlg->exec() == TQDialog::Accepted ) {
338 if ( mMulti )
339 setKeys( dlg->selectedKeys() );
340 else
341 setKey( dlg->selectedKey() );
342 emit changed();
343 }
344
345 delete dlg;
346}
347
348void Kleo::KeyRequester::slotEraseButtonClicked() {
349 if ( !mKeys.empty() )
350 emit changed();
351 mKeys.clear();
352 updateKeys();
353}
354
355void Kleo::KeyRequester::setDialogCaption( const TQString & caption ) {
356 mDialogCaption = caption;
357}
358
359void Kleo::KeyRequester::setDialogMessage( const TQString & msg ) {
360 mDialogMessage = msg;
361}
362
363bool Kleo::KeyRequester::isMultipleKeysEnabled() const {
364 return mMulti;
365}
366
367void Kleo::KeyRequester::setMultipleKeysEnabled( bool multi ) {
368 if ( multi == mMulti ) return;
369
370 if ( !multi && !mKeys.empty() )
371 mKeys.erase( mKeys.begin() + 1, mKeys.end() );
372
373 mMulti = multi;
374 updateKeys();
375}
376
377unsigned int Kleo::KeyRequester::allowedKeys() const {
378 return mKeyUsage;
379}
380
381void Kleo::KeyRequester::setAllowedKeys( unsigned int keyUsage ) {
382 mKeyUsage = keyUsage;
383 mOpenPGPBackend = 0;
384 mSMIMEBackend = 0;
385
386 if ( mKeyUsage & KeySelectionDialog::OpenPGPKeys )
387 mOpenPGPBackend = Kleo::CryptoBackendFactory::instance()->openpgp();
388 if ( mKeyUsage & KeySelectionDialog::SMIMEKeys )
389 mSMIMEBackend = Kleo::CryptoBackendFactory::instance()->smime();
390
391 if ( mOpenPGPBackend && !mSMIMEBackend ) {
392 mDialogCaption = i18n("OpenPGP Key Selection");
393 mDialogMessage = i18n("Please select an OpenPGP key to use.");
394 } else if ( !mOpenPGPBackend && mSMIMEBackend ) {
395 mDialogCaption = i18n("S/MIME Key Selection");
396 mDialogMessage = i18n("Please select an S/MIME key to use.");
397 } else {
398 mDialogCaption = i18n("Key Selection");
399 mDialogMessage = i18n("Please select an (OpenPGP or S/MIME) key to use.");
400 }
401}
402
403TQPushButton * Kleo::KeyRequester::dialogButton() {
404 return mDialogButton;
405}
406
407TQPushButton * Kleo::KeyRequester::eraseButton() {
408 return mEraseButton;
409}
410
411static inline unsigned int foo( bool openpgp, bool smime, bool trusted, bool valid ) {
412 unsigned int result = 0;
413 if ( openpgp )
414 result |= Kleo::KeySelectionDialog::OpenPGPKeys;
415 if ( smime )
416 result |= Kleo::KeySelectionDialog::SMIMEKeys;
417 if ( trusted )
418 result |= Kleo::KeySelectionDialog::TrustedKeys;
419 if ( valid )
420 result |= Kleo::KeySelectionDialog::ValidKeys;
421 return result;
422}
423
424static inline unsigned int encryptionKeyUsage( bool openpgp, bool smime, bool trusted, bool valid ) {
425 return foo( openpgp, smime, trusted, valid ) | Kleo::KeySelectionDialog::EncryptionKeys | Kleo::KeySelectionDialog::PublicKeys;
426}
427
428static inline unsigned int signingKeyUsage( bool openpgp, bool smime, bool trusted, bool valid ) {
429 return foo( openpgp, smime, trusted, valid ) | Kleo::KeySelectionDialog::SigningKeys | Kleo::KeySelectionDialog::SecretKeys;
430}
431
432Kleo::EncryptionKeyRequester::EncryptionKeyRequester( bool multi, unsigned int proto,
433 TQWidget * parent, const char * name,
434 bool onlyTrusted, bool onlyValid )
435 : KeyRequester( encryptionKeyUsage( proto & OpenPGP, proto & SMIME, onlyTrusted, onlyValid ), multi,
436 parent, name )
437{
438}
439
440Kleo::EncryptionKeyRequester::EncryptionKeyRequester( TQWidget * parent, const char * name )
441 : KeyRequester( 0, false, parent, name )
442{
443}
444
445Kleo::EncryptionKeyRequester::~EncryptionKeyRequester() {}
446
447
448void Kleo::EncryptionKeyRequester::setAllowedKeys( unsigned int proto, bool onlyTrusted, bool onlyValid )
449{
450 KeyRequester::setAllowedKeys( encryptionKeyUsage( proto & OpenPGP, proto & SMIME, onlyTrusted, onlyValid ) );
451}
452
453Kleo::SigningKeyRequester::SigningKeyRequester( bool multi, unsigned int proto,
454 TQWidget * parent, const char * name,
455 bool onlyTrusted, bool onlyValid )
456 : KeyRequester( signingKeyUsage( proto & OpenPGP, proto & SMIME, onlyTrusted, onlyValid ), multi,
457 parent, name )
458{
459}
460
461Kleo::SigningKeyRequester::SigningKeyRequester( TQWidget * parent, const char * name )
462 : KeyRequester( 0, false, parent, name )
463{
464}
465
466Kleo::SigningKeyRequester::~SigningKeyRequester() {}
467
468void Kleo::SigningKeyRequester::setAllowedKeys( unsigned int proto, bool onlyTrusted, bool onlyValid )
469{
470 KeyRequester::setAllowedKeys( signingKeyUsage( proto & OpenPGP, proto & SMIME, onlyTrusted, onlyValid ) );
471}
472
473void Kleo::KeyRequester::virtual_hook( int, void* ) {}
474void Kleo::EncryptionKeyRequester::virtual_hook( int id, void * data ) {
475 KeyRequester::virtual_hook( id, data );
476}
477void Kleo::SigningKeyRequester::virtual_hook( int id, void * data ) {
478 KeyRequester::virtual_hook( id, data );
479}
480
481#include "keyrequester.moc"
DN parser and reorderer.
Definition: dn.h:76
TQString prettyDN() const
Definition: dn.cpp:379
void setFingerprints(const TQStringList &fingerprints)
Set the keys by fingerprint.
void setKeys(const std::vector< GpgME::Key > &keys)
Preferred method to set a key for multi-KeyRequesters.
void setKey(const GpgME::Key &key)
Preferred method to set a key for non-multi-KeyRequesters.
void setFingerprint(const TQString &fingerprint)
Set the key by fingerprint.