keyrequester.cpp
00001 /* -*- c++ -*- 00002 keyrequester.cpp 00003 00004 This file is part of libkleopatra, the KDE keymanagement library 00005 Copyright (c) 2004 Klarälvdalens Datakonsult AB 00006 00007 Libkleopatra is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU General Public License as 00009 published by the Free Software Foundation; either version 2 of the 00010 License, or (at your option) any later version. 00011 00012 Libkleopatra is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program; if not, write to the Free Software 00019 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 00021 In addition, as a special exception, the copyright holders give 00022 permission to link the code of this program with any edition of 00023 the TQt library by Trolltech AS, Norway (or with modified versions 00024 of TQt that use the same license as TQt), and distribute linked 00025 combinations including the two. You must obey the GNU General 00026 Public License in all respects for all of the code used other than 00027 TQt. If you modify this file, you may extend this exception to 00028 your version of the file, but you are not obligated to do so. If 00029 you do not wish to do so, delete this exception statement from 00030 your version. 00031 00032 00033 Based on kpgpui.cpp 00034 Copyright (C) 2001,2002 the KPGP authors 00035 See file libtdenetwork/AUTHORS.kpgp for details 00036 00037 This file is part of KPGP, the KDE PGP/GnuPG support library. 00038 00039 KPGP is free software; you can redistribute it and/or modify 00040 it under the terms of the GNU General Public License as published by 00041 the Free Software Foundation; either version 2 of the License, or 00042 (at your option) any later version. 00043 00044 You should have received a copy of the GNU General Public License 00045 along with this program; if not, write to the Free Software Foundation, 00046 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 00047 */ 00048 00049 #ifdef HAVE_CONFIG_H 00050 #include <config.h> 00051 #endif 00052 00053 #include "keyrequester.h" 00054 00055 #include "keyselectiondialog.h" 00056 00057 #include <kleo/keylistjob.h> 00058 #include <kleo/dn.h> 00059 #include <kleo/cryptobackendfactory.h> 00060 00061 // gpgme++ 00062 #include <gpgmepp/key.h> 00063 #include <gpgmepp/keylistresult.h> 00064 00065 // KDE 00066 #include <tdelocale.h> 00067 #include <kiconloader.h> 00068 #include <kdialog.h> 00069 #include <kdebug.h> 00070 #include <tdemessagebox.h> 00071 #include <kpushbutton.h> 00072 00073 // TQt 00074 #include <tqapplication.h> 00075 #include <tqlayout.h> 00076 #include <tqtooltip.h> 00077 #include <tqstring.h> 00078 #include <tqstringlist.h> 00079 #include <tqlabel.h> 00080 #include <tqregexp.h> 00081 00082 #include <assert.h> 00083 00084 Kleo::KeyRequester::KeyRequester( unsigned int allowedKeys, bool multipleKeys, 00085 TQWidget * parent, const char * name ) 00086 : TQWidget( parent, name ), 00087 mOpenPGPBackend( 0 ), 00088 mSMIMEBackend( 0 ), 00089 mMulti( multipleKeys ), 00090 mKeyUsage( allowedKeys ), 00091 mJobs( 0 ), 00092 d( 0 ) 00093 { 00094 init(); 00095 } 00096 00097 Kleo::KeyRequester::KeyRequester( TQWidget * parent, const char * name ) 00098 : TQWidget( parent, name ), 00099 mOpenPGPBackend( 0 ), 00100 mSMIMEBackend( 0 ), 00101 mMulti( false ), 00102 mKeyUsage( 0 ), 00103 mJobs( 0 ), 00104 d( 0 ) 00105 { 00106 init(); 00107 } 00108 00109 void Kleo::KeyRequester::init() 00110 { 00111 TQHBoxLayout * hlay = new TQHBoxLayout( this, 0, KDialog::spacingHint() ); 00112 00113 // the label where the key id is to be displayed: 00114 mLabel = new TQLabel( this ); 00115 mLabel->setFrameStyle( TQFrame::Panel | TQFrame::Sunken ); 00116 00117 // the button to unset any key: 00118 mEraseButton = new KPushButton( this ); 00119 mEraseButton->setAutoDefault( false ); 00120 mEraseButton->setSizePolicy( TQSizePolicy( TQSizePolicy::Minimum, 00121 TQSizePolicy::Minimum ) ); 00122 mEraseButton->setIconSet( SmallIconSet( TQApplication::reverseLayout() ? "locationbar_erase" : "clear_left" ) ); 00123 TQToolTip::add( mEraseButton, i18n("Clear") ); 00124 00125 // the button to call the KeySelectionDialog: 00126 mDialogButton = new TQPushButton( i18n("Change..."), this ); 00127 mDialogButton->setAutoDefault( false ); 00128 00129 hlay->addWidget( mLabel, 1 ); 00130 hlay->addWidget( mEraseButton ); 00131 hlay->addWidget( mDialogButton ); 00132 00133 connect( mEraseButton, TQT_SIGNAL(clicked()), TQT_SLOT(slotEraseButtonClicked()) ); 00134 connect( mDialogButton, TQT_SIGNAL(clicked()), TQT_SLOT(slotDialogButtonClicked()) ); 00135 00136 setSizePolicy( TQSizePolicy( TQSizePolicy::MinimumExpanding, 00137 TQSizePolicy::Fixed ) ); 00138 00139 setAllowedKeys( mKeyUsage ); 00140 } 00141 00142 Kleo::KeyRequester::~KeyRequester() { 00143 00144 } 00145 00146 const std::vector<GpgME::Key> & Kleo::KeyRequester::keys() const { 00147 return mKeys; 00148 } 00149 00150 const GpgME::Key & Kleo::KeyRequester::key() const { 00151 if ( mKeys.empty() ) 00152 return GpgME::Key::null; 00153 else 00154 return mKeys.front(); 00155 } 00156 00157 void Kleo::KeyRequester::setKeys( const std::vector<GpgME::Key> & keys ) { 00158 mKeys.clear(); 00159 for ( std::vector<GpgME::Key>::const_iterator it = keys.begin() ; it != keys.end() ; ++it ) 00160 if ( !it->isNull() ) 00161 mKeys.push_back( *it ); 00162 updateKeys(); 00163 } 00164 00165 void Kleo::KeyRequester::setKey( const GpgME::Key & key ) { 00166 mKeys.clear(); 00167 if ( !key.isNull() ) 00168 mKeys.push_back( key ); 00169 updateKeys(); 00170 } 00171 00172 TQString Kleo::KeyRequester::fingerprint() const { 00173 if ( mKeys.empty() ) 00174 return TQString(); 00175 else 00176 return mKeys.front().primaryFingerprint(); 00177 } 00178 00179 TQStringList Kleo::KeyRequester::fingerprints() const { 00180 TQStringList result; 00181 for ( std::vector<GpgME::Key>::const_iterator it = mKeys.begin() ; it != mKeys.end() ; ++it ) 00182 if ( !it->isNull() ) 00183 if ( const char * fpr = it->primaryFingerprint() ) 00184 result.push_back( fpr ); 00185 return result; 00186 } 00187 00188 void Kleo::KeyRequester::setFingerprint( const TQString & fingerprint ) { 00189 startKeyListJob( fingerprint ); 00190 } 00191 00192 void Kleo::KeyRequester::setFingerprints( const TQStringList & fingerprints ) { 00193 startKeyListJob( fingerprints ); 00194 } 00195 00196 void Kleo::KeyRequester::updateKeys() { 00197 if ( mKeys.empty() ) { 00198 mLabel->clear(); 00199 return; 00200 } 00201 if ( mKeys.size() > 1 ) 00202 setMultipleKeysEnabled( true ); 00203 00204 TQStringList labelTexts; 00205 TQString toolTipText; 00206 for ( std::vector<GpgME::Key>::const_iterator it = mKeys.begin() ; it != mKeys.end() ; ++it ) { 00207 if ( it->isNull() ) 00208 continue; 00209 const TQString fpr = it->primaryFingerprint(); 00210 labelTexts.push_back( fpr.right(8) ); 00211 toolTipText += fpr.right(8) + ": "; 00212 if ( const char * uid = it->userID(0).id() ) 00213 if ( it->protocol() == GpgME::Context::OpenPGP ) 00214 toolTipText += TQString::fromUtf8( uid ); 00215 else 00216 toolTipText += Kleo::DN( uid ).prettyDN(); 00217 else 00218 toolTipText += i18n("<unknown>"); 00219 toolTipText += '\n'; 00220 } 00221 00222 mLabel->setText( labelTexts.join(", ") ); 00223 TQToolTip::remove( mLabel ); 00224 TQToolTip::add( mLabel, toolTipText ); 00225 } 00226 00227 #ifndef __KLEO_UI_SHOW_KEY_LIST_ERROR_H__ 00228 #define __KLEO_UI_SHOW_KEY_LIST_ERROR_H__ 00229 static void showKeyListError( TQWidget * parent, const GpgME::Error & err ) { 00230 assert( err ); 00231 const TQString msg = i18n( "<qt><p>An error occurred while fetching " 00232 "the keys from the backend:</p>" 00233 "<p><b>%1</b></p></qt>" ) 00234 .arg( TQString::fromLocal8Bit( err.asString() ) ); 00235 00236 KMessageBox::error( parent, msg, i18n( "Key Listing Failed" ) ); 00237 } 00238 #endif // __KLEO_UI_SHOW_KEY_LIST_ERROR_H__ 00239 00240 void Kleo::KeyRequester::startKeyListJob( const TQStringList & fingerprints ) { 00241 if ( !mSMIMEBackend && !mOpenPGPBackend ) 00242 return; 00243 00244 mTmpKeys.clear(); 00245 mJobs = 0; 00246 00247 unsigned int count = 0; 00248 for ( TQStringList::const_iterator it = fingerprints.begin() ; it != fingerprints.end() ; ++it ) 00249 if ( !(*it).stripWhiteSpace().isEmpty() ) 00250 ++count; 00251 00252 if ( !count ) { 00253 // don't fall into the trap that an empty pattern means 00254 // "return all keys" :) 00255 setKey( GpgME::Key::null ); 00256 return; 00257 } 00258 00259 if ( mOpenPGPBackend ) { 00260 KeyListJob * job = mOpenPGPBackend->keyListJob( false ); // local, no sigs 00261 if ( !job ) { 00262 KMessageBox::error( this, 00263 i18n("The OpenPGP backend does not support listing keys. " 00264 "Check your installation."), 00265 i18n("Key Listing Failed") ); 00266 } else { 00267 connect( job, TQT_SIGNAL(result(const GpgME::KeyListResult&)), 00268 TQT_SLOT(slotKeyListResult(const GpgME::KeyListResult&)) ); 00269 connect( job, TQT_SIGNAL(nextKey(const GpgME::Key&)), 00270 TQT_SLOT(slotNextKey(const GpgME::Key&)) ); 00271 00272 const GpgME::Error err = job->start( fingerprints, 00273 mKeyUsage & Kleo::KeySelectionDialog::SecretKeys && 00274 !( mKeyUsage & Kleo::KeySelectionDialog::PublicKeys ) ); 00275 00276 if ( err ) 00277 showKeyListError( this, err ); 00278 else 00279 ++mJobs; 00280 } 00281 } 00282 00283 if ( mSMIMEBackend ) { 00284 KeyListJob * job = mSMIMEBackend->keyListJob( false ); // local, no sigs 00285 if ( !job ) { 00286 KMessageBox::error( this, 00287 i18n("The S/MIME backend does not support listing keys. " 00288 "Check your installation."), 00289 i18n("Key Listing Failed") ); 00290 } else { 00291 connect( job, TQT_SIGNAL(result(const GpgME::KeyListResult&)), 00292 TQT_SLOT(slotKeyListResult(const GpgME::KeyListResult&)) ); 00293 connect( job, TQT_SIGNAL(nextKey(const GpgME::Key&)), 00294 TQT_SLOT(slotNextKey(const GpgME::Key&)) ); 00295 00296 const GpgME::Error err = job->start( fingerprints, 00297 mKeyUsage & Kleo::KeySelectionDialog::SecretKeys && 00298 !( mKeyUsage & Kleo::KeySelectionDialog::PublicKeys ) ); 00299 00300 if ( err ) 00301 showKeyListError( this, err ); 00302 else 00303 ++mJobs; 00304 } 00305 } 00306 00307 if ( mJobs > 0 ) { 00308 mEraseButton->setEnabled( false ); 00309 mDialogButton->setEnabled( false ); 00310 } 00311 } 00312 00313 void Kleo::KeyRequester::slotNextKey( const GpgME::Key & key ) { 00314 if ( !key.isNull() ) 00315 mTmpKeys.push_back( key ); 00316 } 00317 00318 void Kleo::KeyRequester::slotKeyListResult( const GpgME::KeyListResult & res ) { 00319 if ( res.error() ) 00320 showKeyListError( this, res.error() ); 00321 00322 if ( --mJobs <= 0 ) { 00323 mEraseButton->setEnabled( true ); 00324 mDialogButton->setEnabled( true ); 00325 00326 setKeys( mTmpKeys ); 00327 mTmpKeys.clear(); 00328 } 00329 } 00330 00331 00332 void Kleo::KeyRequester::slotDialogButtonClicked() { 00333 KeySelectionDialog * dlg = mKeys.empty() 00334 ? new KeySelectionDialog( mDialogCaption, mDialogMessage, mInitialQuery, mKeyUsage, mMulti, false, this ) 00335 : new KeySelectionDialog( mDialogCaption, mDialogCaption, mKeys, mKeyUsage, mMulti, false, this ) ; 00336 00337 if ( dlg->exec() == TQDialog::Accepted ) { 00338 if ( mMulti ) 00339 setKeys( dlg->selectedKeys() ); 00340 else 00341 setKey( dlg->selectedKey() ); 00342 emit changed(); 00343 } 00344 00345 delete dlg; 00346 } 00347 00348 void Kleo::KeyRequester::slotEraseButtonClicked() { 00349 if ( !mKeys.empty() ) 00350 emit changed(); 00351 mKeys.clear(); 00352 updateKeys(); 00353 } 00354 00355 void Kleo::KeyRequester::setDialogCaption( const TQString & caption ) { 00356 mDialogCaption = caption; 00357 } 00358 00359 void Kleo::KeyRequester::setDialogMessage( const TQString & msg ) { 00360 mDialogMessage = msg; 00361 } 00362 00363 bool Kleo::KeyRequester::isMultipleKeysEnabled() const { 00364 return mMulti; 00365 } 00366 00367 void Kleo::KeyRequester::setMultipleKeysEnabled( bool multi ) { 00368 if ( multi == mMulti ) return; 00369 00370 if ( !multi && !mKeys.empty() ) 00371 mKeys.erase( mKeys.begin() + 1, mKeys.end() ); 00372 00373 mMulti = multi; 00374 updateKeys(); 00375 } 00376 00377 unsigned int Kleo::KeyRequester::allowedKeys() const { 00378 return mKeyUsage; 00379 } 00380 00381 void Kleo::KeyRequester::setAllowedKeys( unsigned int keyUsage ) { 00382 mKeyUsage = keyUsage; 00383 mOpenPGPBackend = 0; 00384 mSMIMEBackend = 0; 00385 00386 if ( mKeyUsage & KeySelectionDialog::OpenPGPKeys ) 00387 mOpenPGPBackend = Kleo::CryptoBackendFactory::instance()->openpgp(); 00388 if ( mKeyUsage & KeySelectionDialog::SMIMEKeys ) 00389 mSMIMEBackend = Kleo::CryptoBackendFactory::instance()->smime(); 00390 00391 if ( mOpenPGPBackend && !mSMIMEBackend ) { 00392 mDialogCaption = i18n("OpenPGP Key Selection"); 00393 mDialogMessage = i18n("Please select an OpenPGP key to use."); 00394 } else if ( !mOpenPGPBackend && mSMIMEBackend ) { 00395 mDialogCaption = i18n("S/MIME Key Selection"); 00396 mDialogMessage = i18n("Please select an S/MIME key to use."); 00397 } else { 00398 mDialogCaption = i18n("Key Selection"); 00399 mDialogMessage = i18n("Please select an (OpenPGP or S/MIME) key to use."); 00400 } 00401 } 00402 00403 TQPushButton * Kleo::KeyRequester::dialogButton() { 00404 return mDialogButton; 00405 } 00406 00407 TQPushButton * Kleo::KeyRequester::eraseButton() { 00408 return mEraseButton; 00409 } 00410 00411 static inline unsigned int foo( bool openpgp, bool smime, bool trusted, bool valid ) { 00412 unsigned int result = 0; 00413 if ( openpgp ) 00414 result |= Kleo::KeySelectionDialog::OpenPGPKeys; 00415 if ( smime ) 00416 result |= Kleo::KeySelectionDialog::SMIMEKeys; 00417 if ( trusted ) 00418 result |= Kleo::KeySelectionDialog::TrustedKeys; 00419 if ( valid ) 00420 result |= Kleo::KeySelectionDialog::ValidKeys; 00421 return result; 00422 } 00423 00424 static inline unsigned int encryptionKeyUsage( bool openpgp, bool smime, bool trusted, bool valid ) { 00425 return foo( openpgp, smime, trusted, valid ) | Kleo::KeySelectionDialog::EncryptionKeys | Kleo::KeySelectionDialog::PublicKeys; 00426 } 00427 00428 static inline unsigned int signingKeyUsage( bool openpgp, bool smime, bool trusted, bool valid ) { 00429 return foo( openpgp, smime, trusted, valid ) | Kleo::KeySelectionDialog::SigningKeys | Kleo::KeySelectionDialog::SecretKeys; 00430 } 00431 00432 Kleo::EncryptionKeyRequester::EncryptionKeyRequester( bool multi, unsigned int proto, 00433 TQWidget * parent, const char * name, 00434 bool onlyTrusted, bool onlyValid ) 00435 : KeyRequester( encryptionKeyUsage( proto & OpenPGP, proto & SMIME, onlyTrusted, onlyValid ), multi, 00436 parent, name ) 00437 { 00438 } 00439 00440 Kleo::EncryptionKeyRequester::EncryptionKeyRequester( TQWidget * parent, const char * name ) 00441 : KeyRequester( 0, false, parent, name ) 00442 { 00443 } 00444 00445 Kleo::EncryptionKeyRequester::~EncryptionKeyRequester() {} 00446 00447 00448 void Kleo::EncryptionKeyRequester::setAllowedKeys( unsigned int proto, bool onlyTrusted, bool onlyValid ) 00449 { 00450 KeyRequester::setAllowedKeys( encryptionKeyUsage( proto & OpenPGP, proto & SMIME, onlyTrusted, onlyValid ) ); 00451 } 00452 00453 Kleo::SigningKeyRequester::SigningKeyRequester( bool multi, unsigned int proto, 00454 TQWidget * parent, const char * name, 00455 bool onlyTrusted, bool onlyValid ) 00456 : KeyRequester( signingKeyUsage( proto & OpenPGP, proto & SMIME, onlyTrusted, onlyValid ), multi, 00457 parent, name ) 00458 { 00459 } 00460 00461 Kleo::SigningKeyRequester::SigningKeyRequester( TQWidget * parent, const char * name ) 00462 : KeyRequester( 0, false, parent, name ) 00463 { 00464 } 00465 00466 Kleo::SigningKeyRequester::~SigningKeyRequester() {} 00467 00468 void Kleo::SigningKeyRequester::setAllowedKeys( unsigned int proto, bool onlyTrusted, bool onlyValid ) 00469 { 00470 KeyRequester::setAllowedKeys( signingKeyUsage( proto & OpenPGP, proto & SMIME, onlyTrusted, onlyValid ) ); 00471 } 00472 00473 void Kleo::KeyRequester::virtual_hook( int, void* ) {} 00474 void Kleo::EncryptionKeyRequester::virtual_hook( int id, void * data ) { 00475 KeyRequester::virtual_hook( id, data ); 00476 } 00477 void Kleo::SigningKeyRequester::virtual_hook( int id, void * data ) { 00478 KeyRequester::virtual_hook( id, data ); 00479 } 00480 00481 #include "keyrequester.moc"