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 
84 Kleo::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 
97 Kleo::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 
109 void 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 
142 Kleo::KeyRequester::~KeyRequester() {
143 
144 }
145 
146 const std::vector<GpgME::Key> & Kleo::KeyRequester::keys() const {
147  return mKeys;
148 }
149 
150 const GpgME::Key & Kleo::KeyRequester::key() const {
151  if ( mKeys.empty() )
152  return GpgME::Key::null;
153  else
154  return mKeys.front();
155 }
156 
157 void 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 
165 void Kleo::KeyRequester::setKey( const GpgME::Key & key ) {
166  mKeys.clear();
167  if ( !key.isNull() )
168  mKeys.push_back( key );
169  updateKeys();
170 }
171 
172 TQString Kleo::KeyRequester::fingerprint() const {
173  if ( mKeys.empty() )
174  return TQString();
175  else
176  return mKeys.front().primaryFingerprint();
177 }
178 
179 TQStringList 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 
188 void Kleo::KeyRequester::setFingerprint( const TQString & fingerprint ) {
189  startKeyListJob( fingerprint );
190 }
191 
192 void Kleo::KeyRequester::setFingerprints( const TQStringList & fingerprints ) {
193  startKeyListJob( fingerprints );
194 }
195 
196 void 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__
229 static 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 
240 void 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 
313 void Kleo::KeyRequester::slotNextKey( const GpgME::Key & key ) {
314  if ( !key.isNull() )
315  mTmpKeys.push_back( key );
316 }
317 
318 void 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 
332 void 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 
348 void Kleo::KeyRequester::slotEraseButtonClicked() {
349  if ( !mKeys.empty() )
350  emit changed();
351  mKeys.clear();
352  updateKeys();
353 }
354 
355 void Kleo::KeyRequester::setDialogCaption( const TQString & caption ) {
356  mDialogCaption = caption;
357 }
358 
359 void Kleo::KeyRequester::setDialogMessage( const TQString & msg ) {
360  mDialogMessage = msg;
361 }
362 
363 bool Kleo::KeyRequester::isMultipleKeysEnabled() const {
364  return mMulti;
365 }
366 
367 void 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 
377 unsigned int Kleo::KeyRequester::allowedKeys() const {
378  return mKeyUsage;
379 }
380 
381 void 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 
403 TQPushButton * Kleo::KeyRequester::dialogButton() {
404  return mDialogButton;
405 }
406 
407 TQPushButton * Kleo::KeyRequester::eraseButton() {
408  return mEraseButton;
409 }
410 
411 static 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 
424 static 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 
428 static 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 
432 Kleo::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 
440 Kleo::EncryptionKeyRequester::EncryptionKeyRequester( TQWidget * parent, const char * name )
441  : KeyRequester( 0, false, parent, name )
442 {
443 }
444 
445 Kleo::EncryptionKeyRequester::~EncryptionKeyRequester() {}
446 
447 
448 void Kleo::EncryptionKeyRequester::setAllowedKeys( unsigned int proto, bool onlyTrusted, bool onlyValid )
449 {
450  KeyRequester::setAllowedKeys( encryptionKeyUsage( proto & OpenPGP, proto & SMIME, onlyTrusted, onlyValid ) );
451 }
452 
453 Kleo::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 
461 Kleo::SigningKeyRequester::SigningKeyRequester( TQWidget * parent, const char * name )
462  : KeyRequester( 0, false, parent, name )
463 {
464 }
465 
466 Kleo::SigningKeyRequester::~SigningKeyRequester() {}
467 
468 void Kleo::SigningKeyRequester::setAllowedKeys( unsigned int proto, bool onlyTrusted, bool onlyValid )
469 {
470  KeyRequester::setAllowedKeys( signingKeyUsage( proto & OpenPGP, proto & SMIME, onlyTrusted, onlyValid ) );
471 }
472 
473 void Kleo::KeyRequester::virtual_hook( int, void* ) {}
474 void Kleo::EncryptionKeyRequester::virtual_hook( int id, void * data ) {
475  KeyRequester::virtual_hook( id, data );
476 }
477 void 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.