Better wording
[kdepim.git] / kleopatra / dialogs / certificatedetailsdialog.cpp
blob33628105e76effefda128b3a39b72096708821a4
1 /* -*- mode: c++; c-basic-offset:4 -*-
2 dialogs/certificatedetailsdialog.cpp
4 This file is part of Kleopatra, the KDE keymanager
5 Copyright (c) 2008 Klarälvdalens Datakonsult AB
7 Kleopatra is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 Kleopatra 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.
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
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 Qt library by Trolltech AS, Norway (or with modified versions
24 of Qt that use the same license as Qt), 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 Qt. 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.
33 #include <config-kleopatra.h>
35 #include "certificatedetailsdialog.h"
37 #include "ui_certificatedetailsdialog.h"
39 #include <models/useridlistmodel.h>
40 #include <models/subkeylistmodel.h>
41 #include <models/keycache.h>
43 #include <commands/changepassphrasecommand.h>
44 #include <commands/changeownertrustcommand.h>
45 #include <commands/changeexpirycommand.h>
46 #include <commands/adduseridcommand.h>
47 #include <commands/certifycertificatecommand.h>
48 #include <commands/dumpcertificatecommand.h>
50 #include <utils/formatting.h>
51 #include <utils/gnupg-helper.h>
53 #include <kleo/cryptobackendfactory.h>
54 #include <kleo/cryptobackend.h>
55 #include <kleo/keylistjob.h>
56 #include <kleo/dn.h>
58 #include <gpgme++/key.h>
59 #include <gpgme++/keylistresult.h>
61 #include <KDebug>
62 #include <KMessageBox>
63 #include <KLocalizedString>
64 #include <KGlobalSettings>
66 #include <QPointer>
67 #include <QHeaderView>
69 #include <boost/mem_fn.hpp>
71 #include <algorithm>
72 #include <cassert>
74 using namespace Kleo;
75 using namespace Kleo::Dialogs;
76 using namespace Kleo::Commands;
77 using namespace GpgME;
78 using namespace boost;
80 static bool own( const std::vector<UserID::Signature> & sigs ) {
81 const shared_ptr<const KeyCache> kc = KeyCache::instance();
82 Q_FOREACH( const UserID::Signature & sig, sigs ) {
83 const Key signer = kc->findByKeyIDOrFingerprint( sig.signerKeyID() );
84 if ( signer.isNull() || !signer.hasSecret() )
85 return false;
87 return !sigs.empty();
90 class CertificateDetailsDialog::Private {
91 friend class ::Kleo::Dialogs::CertificateDetailsDialog;
92 CertificateDetailsDialog * const q;
93 public:
94 explicit Private( CertificateDetailsDialog * qq )
95 : q( qq ),
96 key(),
97 certificationsModel(),
98 subkeysModel(),
99 ui( q )
101 ui.certificationsTV->setModel( &certificationsModel );
102 connect( ui.certificationsTV->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
103 q, SLOT(slotCertificationSelectionChanged()) );
105 ui.subkeyTV->setModel( &subkeysModel );
106 // no selection (yet)
108 connect( KeyCache::instance().get(), SIGNAL(keysMayHaveChanged()),
109 q, SLOT(slotKeysMayHaveChanged()) );
112 private:
113 void startCommandImplementation( const QPointer<Command> & ptr, const char * slot ) {
114 connect( ptr, SIGNAL(finished()), q, slot );
115 ptr->start();
116 enableDisableWidgets();
118 template <typename T, typename A>
119 void startCommand( QPointer<Command> & ptr, const A & arg, const char * slot ) {
120 if ( ptr )
121 return;
122 ptr = new T( arg );
123 startCommandImplementation( ptr, slot );
125 template <typename T>
126 void startCommand( QPointer<Command> & ptr, const char * slot ) {
127 startCommand<T>( ptr, this->key, slot );
129 void commandFinished( QPointer<Command> & ptr ) {
130 ptr = 0;
131 enableDisableWidgets();
134 void slotChangePassphraseClicked() {
135 startCommand<ChangePassphraseCommand>( changePassphraseCommand, SLOT(slotChangePassphraseCommandFinished()) );
137 void slotChangePassphraseCommandFinished() {
138 commandFinished( changePassphraseCommand );
141 void slotChangeTrustLevelClicked() {
142 startCommand<ChangeOwnerTrustCommand>( changeOwnerTrustCommand, SLOT(slotChangeOwnerTrustCommandFinished()) );
144 void slotChangeOwnerTrustCommandFinished() {
145 commandFinished( changeOwnerTrustCommand );
148 void slotChangeExpiryDateClicked() {
149 startCommand<ChangeExpiryCommand>( changeExpiryDateCommand, SLOT(slotChangeExpiryDateCommandFinished()) );
151 void slotChangeExpiryDateCommandFinished() {
152 commandFinished( changeExpiryDateCommand );
155 void slotAddUserIDClicked() {
156 startCommand<AddUserIDCommand>( addUserIDCommand, SLOT(slotAddUserIDCommandFinished()) );
158 void slotAddUserIDCommandFinished() {
159 commandFinished( addUserIDCommand );
162 void slotCertifyUserIDClicked() {
163 const std::vector<UserID> uids = selectedUserIDs();
164 if ( uids.empty() )
165 return;
166 startCommand<CertifyCertificateCommand>( signCertificateCommand, uids, SLOT(slotSignCertificateCommandFinished()) );
168 void slotSignCertificateCommandFinished() {
169 commandFinished( signCertificateCommand );
172 void slotRevokeCertificateClicked() {
176 void slotRevokeUserIDClicked() {
180 void slotRevokeCertificationClicked() {
184 void slotShowCertificationsClicked() {
185 startSignatureListing();
186 enableDisableWidgets();
189 void startSignatureListing() {
190 if ( keyListJob )
191 return;
192 const CryptoBackend::Protocol * const protocol = CryptoBackendFactory::instance()->protocol( key.protocol() );
193 if ( !protocol )
194 return;
195 KeyListJob * const job = protocol->keyListJob( /*remote*/false, /*includeSigs*/true, /*validate*/true );
196 if ( !job )
197 return;
198 connect( job, SIGNAL(result(GpgME::KeyListResult)),
199 q, SLOT(slotSignatureListingDone(GpgME::KeyListResult)) );
200 connect( job, SIGNAL(nextKey(GpgME::Key)),
201 q, SLOT(slotSignatureListingNextKey(GpgME::Key)) );
202 if ( const Error err = job->start( QStringList( QString::fromLatin1( key.primaryFingerprint() ) ) ) )
203 showSignatureListingErrorDialog( err );
204 else
205 keyListJob = job;
207 void slotSignatureListingNextKey( const Key & key ) {
208 // don't lose the secret flags ...
209 Key merged = key;
210 merged.mergeWith( this->key );
211 q->setKey( merged );
213 // fixup the tree view
214 ui.certificationsTV->expandAll();
215 ui.certificationsTV->header()->resizeSections( QHeaderView::ResizeToContents );
217 void slotSignatureListingDone( const KeyListResult & result ) {
218 if ( result.error().isCanceled() )
220 else if ( result.error() )
221 showSignatureListingErrorDialog( result.error() );
222 else {
223 ; // nothing to do
225 keyListJob = 0;
226 enableDisableWidgets();
228 void showSignatureListingErrorDialog( const Error & err ) {
229 KMessageBox::information( q, i18nc("@info",
230 "<para>An error occurred while loading the certifications: "
231 "<message>%1</message></para>",
232 QString::fromLocal8Bit( err.asString() ) ),
233 i18nc("@title","Certifications Loading Failed") );
236 void slotCertificationSelectionChanged() {
237 enableDisableWidgets();
240 void slotKeysMayHaveChanged() {
241 if ( const char * const fpr = key.primaryFingerprint() )
242 if ( !(key.keyListMode() & Extern) )
243 q->setKey( KeyCache::instance()->findByFingerprint( fpr ) );
246 void slotDumpCertificate() {
248 if ( dumpCertificateCommand )
249 return;
251 if ( key.protocol() != CMS ) {
252 ui.dumpLTW->clear();
253 return;
256 ui.dumpLTW->setLines( QStringList( i18n("Please wait while generating the dump...") ) );
258 dumpCertificateCommand = new DumpCertificateCommand( key );
259 dumpCertificateCommand->setUseDialog( false );
260 QPointer<Command> cmd = dumpCertificateCommand.data();
261 startCommandImplementation( cmd, SLOT(slotDumpCertificateCommandFinished()) );
264 void slotDumpCertificateCommandFinished() {
265 ui.dumpLTW->setLines( dumpCertificateCommand->output() );
268 private:
269 void updateWidgetVisibility() {
270 const bool x509 = key.protocol() == CMS;
271 const bool pgp = key.protocol() == OpenPGP;
272 const bool secret = key.hasSecret();
273 const bool sigs = (key.keyListMode() & Signatures);
274 const bool ultimateTrust = key.ownerTrust() == Key::Ultimate;
275 const bool external = (key.keyListMode() & Extern);
277 // Overview Tab
278 ui.overviewActionsGB->setVisible( !external );
279 ui.changePassphrasePB->setVisible( secret );
280 ui.changeTrustLevelPB->setVisible( pgp && ( !secret || !ultimateTrust ) );
281 ui.changeExpiryDatePB->setVisible( pgp && secret );
283 // Certifications Tab
284 ui.userIDsActionsGB->setVisible( !external && pgp );
285 ui.certificationsActionGB->setVisible( !external && pgp );
286 ui.addUserIDPB->setVisible( secret );
287 ui.expandAllCertificationsPB->setVisible( pgp && sigs );
288 ui.collapseAllCertificationsPB->setVisible( pgp && sigs );
289 ui.showCertificationsPB->setVisible( !external && pgp && !sigs );
291 // Technical Details Tab
292 ui.tabWidget->setTabEnabled( ui.tabWidget->indexOf( ui.detailsTab ), pgp );
294 // Chain tab
295 ui.tabWidget->setTabEnabled( ui.tabWidget->indexOf( ui.chainTab ), x509 );
297 // Dump tab
298 ui.tabWidget->setTabEnabled( ui.tabWidget->indexOf( ui.dumpTab ), x509 );
300 // not implemented:
301 ui.revokeCertificatePB->hide();
302 ui.revokeUserIDPB->hide();
303 ui.certificationsActionGB->hide();
306 QModelIndexList selectedCertificationsIndexes() const {
307 return ui.certificationsTV->selectionModel()->selectedRows();
310 std::vector<UserID> selectedUserIDs() const {
311 const QModelIndexList mil = selectedCertificationsIndexes();
312 std::vector<UserID> uids = certificationsModel.userIDs( mil, true );
313 uids.erase( std::remove_if( uids.begin(), uids.end(), mem_fn( &UserID::isNull ) ), uids.end() );
314 return uids;
317 std::vector<UserID::Signature> selectedSignatures() const {
318 const QModelIndexList mil = selectedCertificationsIndexes();
319 std::vector<UserID::Signature> sigs = certificationsModel.signatures( mil );
320 sigs.erase( std::remove_if( sigs.begin(), sigs.end(), mem_fn( &UserID::Signature::isNull ) ), sigs.end() );
321 return sigs;
324 void enableDisableWidgets() {
325 // Overview Tab
326 ui.changePassphrasePB->setEnabled( !changePassphraseCommand );
327 ui.changeTrustLevelPB->setEnabled( !changeOwnerTrustCommand );
328 ui.changeExpiryDatePB->setEnabled( !changeExpiryDateCommand );
330 // Certifications Tab
331 ui.addUserIDPB->setEnabled( !addUserIDCommand );
332 ui.showCertificationsPB->setEnabled( !keyListJob );
333 ui.showCertificationsPB->setText( keyListJob
334 ? i18n("(please wait while certifications are being loaded)")
335 : i18n("Load Certifications (may take a while)") );
337 const std::vector<UserID> uids = selectedUserIDs();
338 const std::vector<UserID::Signature> sigs = selectedSignatures();
340 ui.certifyUserIDPB->setEnabled( !uids.empty() && sigs.empty() && !signCertificateCommand );
341 ui.revokeUserIDPB->setEnabled( !uids.empty() && sigs.empty() );
342 ui.revokeCertificationPB->setEnabled( uids.empty() && !sigs.empty() && own( sigs ) );
345 void updateLabel() {
346 ui.overviewLB->setText( Formatting::formatOverview( key ) );
349 void updateChainTab() {
350 ui.chainTW->clear();
352 if ( key.protocol() != CMS )
353 return;
355 QTreeWidgetItem * last = 0;
356 const std::vector<Key> chain = KeyCache::instance()->findIssuers( key, KeyCache::RecursiveSearch|KeyCache::IncludeSubject );
357 if ( chain.empty() )
358 return;
359 if ( !chain.back().isRoot() ) {
360 last = new QTreeWidgetItem( ui.chainTW );
361 last->setText( 0, i18n("Issuer Certificate Not Found (%1)",
362 DN( chain.back().issuerName() ).prettyDN() ) );
363 //last->setSelectable( false );
364 const QBrush & fg = ui.chainTW->palette().brush( QPalette::Disabled, QPalette::WindowText );
365 last->setForeground( 0, fg );
367 for ( std::vector<Key>::const_reverse_iterator it = chain.rbegin(), end = chain.rend() ; it != end ; ++it ) {
368 last = last ? new QTreeWidgetItem( last ) : new QTreeWidgetItem( ui.chainTW ) ;
369 last->setText( 0, DN( it->userID(0).id() ).prettyDN() );
370 //last->setSelectable( true );
372 ui.chainTW->expandAll();
375 void propagateKey() {
376 certificationsModel.setKey( key );
377 const QModelIndexList uidIndexes = certificationsModel.indexes( key.userIDs() );
378 Q_FOREACH( const QModelIndex & idx, uidIndexes )
379 ui.certificationsTV->setFirstColumnSpanned( idx.row(), idx.parent(), true );
381 subkeysModel.setKey( key );
382 ui.subkeyTV->header()->resizeSections( QHeaderView::ResizeToContents );
384 updateChainTab();
385 slotDumpCertificate();
389 private:
390 Key key;
391 UserIDListModel certificationsModel;
392 SubkeyListModel subkeysModel;
394 QPointer<Command> changePassphraseCommand;
395 QPointer<Command> changeOwnerTrustCommand;
396 QPointer<Command> changeExpiryDateCommand;
398 QPointer<Command> addUserIDCommand;
399 QPointer<Command> signCertificateCommand;
401 QPointer<DumpCertificateCommand> dumpCertificateCommand;
403 QPointer<KeyListJob> keyListJob;
405 struct UI : public Ui_CertificateDetailsDialog {
406 explicit UI( Dialogs::CertificateDetailsDialog * qq )
407 : Ui_CertificateDetailsDialog()
409 setupUi( qq->mainWidget() );
410 qq->setButtons( KDialog::Help | KDialog::Close );
411 qq->setHelp(QString(), "kleopatra");
412 chainTW->header()->setResizeMode( 0, QHeaderView::Stretch );
414 dumpLTW->setFont( KGlobalSettings::fixedFont() );
415 dumpLTW->setMinimumVisibleLines( 15 );
416 dumpLTW->setMinimumVisibleColumns( 40 );
418 subkeyHLine->setTitle( i18nc("@title","Subkeys") );
420 } ui;
423 CertificateDetailsDialog::CertificateDetailsDialog( QWidget * p, Qt::WindowFlags f )
424 : KDialog( p, f ), d( new Private( this ) )
429 CertificateDetailsDialog::~CertificateDetailsDialog() {}
432 void CertificateDetailsDialog::setKey( const Key & key ) {
433 d->key = key;
434 d->updateWidgetVisibility();
435 d->updateLabel();
436 d->propagateKey();
437 d->enableDisableWidgets();
440 Key CertificateDetailsDialog::key() const {
441 return d->key;
445 #include "moc_certificatedetailsdialog.cpp"