33 #include <config-kleopatra.h>
44 #include <kleo/stl_util.h>
45 #include <kleo/cryptobackend.h>
46 #include <kleo/cryptobackendfactory.h>
47 #include <kleo/multideletejob.h>
48 #include <kleo/deletejob.h>
50 #include <gpgme++/key.h>
53 #include <KMessageBox>
56 #include <QAbstractItemView>
58 #include <boost/bind.hpp>
64 using namespace boost;
65 using namespace GpgME;
67 using namespace Kleo::Dialogs;
70 friend class ::Kleo::DeleteCertificatesCommand;
76 void startDeleteJob( GpgME::Protocol protocol );
79 void pgpDeleteResult(
const GpgME::Error & );
80 void cmsDeleteResult(
const GpgME::Error & );
81 void showErrorsAndFinish();
83 bool canDelete( GpgME::Protocol proto )
const {
84 if (
const CryptoBackend::Protocol *
const cbp = CryptoBackendFactory::instance()->protocol( proto ) )
85 if ( DeleteJob *
const job = cbp->deleteJob() ) {
92 void ensureDialogCreated() {
96 applyWindowID( dialog );
97 dialog->setAttribute( Qt::WA_DeleteOnClose );
98 dialog->setWindowTitle( i18nc(
"@title:window",
"Delete Certificates") );
99 connect( dialog, SIGNAL(accepted()), q_func(), SLOT(slotDialogAccepted()) );
100 connect( dialog, SIGNAL(rejected()), q_func(), SLOT(slotDialogRejected()) );
102 void ensureDialogShown() {
107 void slotDialogAccepted();
108 void slotDialogRejected() {
113 QPointer<DeleteCertificatesDialog> dialog;
114 QPointer<MultiDeleteJob> cmsJob, pgpJob;
115 GpgME::Error cmsError, pgpError;
116 std::vector<Key> cmsKeys, pgpKeys;
119 DeleteCertificatesCommand::Private * DeleteCertificatesCommand::d_func() {
return static_cast<Private*
>(
d.get()); }
120 const DeleteCertificatesCommand::Private * DeleteCertificatesCommand::d_func()
const {
return static_cast<const Private*
>(
d.get()); }
131 DeleteCertificatesCommand::Private::~Private() {}
135 :
Command( new Private( this, p ) )
141 :
Command( v, new Private( this, p ) )
150 enum Action { Nothing = 0, Failure = 1, ClearCMS = 2, ClearPGP = 4 };
156 static const struct {
159 } deletionErrorCases[16] = {
163 { I18N_NOOP(
"Neither the OpenPGP nor the CMS "
164 "backends support certificate deletion.\n"
165 "Check your installation." ),
167 { I18N_NOOP(
"The OpenPGP backend does not support "
168 "certificate deletion.\n"
169 "Check your installation.\n"
170 "Only the selected CMS certificates "
171 "will be deleted." ),
174 { I18N_NOOP(
"The OpenPGP backend does not support "
175 "certificate deletion.\n"
176 "Check your installation." ),
178 { I18N_NOOP(
"The OpenPGP backend does not support "
179 "certificate deletion.\n"
180 "Check your installation." ),
184 { I18N_NOOP(
"The CMS backend does not support "
185 "certificate deletion.\n"
186 "Check your installation.\n"
187 "Only the selected OpenPGP certificates "
188 "will be deleted." ),
200 { I18N_NOOP(
"The CMS backend does not support "
201 "certificate deletion.\n"
202 "Check your installation." ),
213 { I18N_NOOP(
"The CMS backend does not support "
214 "certificate deletion.\n"
215 "Check your installation." ),
227 void DeleteCertificatesCommand::doStart() {
229 std::vector<Key> selected =
d->keys();
230 if ( selected.empty() ) {
235 kdtools::sort( selected, _detail::ByFingerprint<std::less>() );
241 kdtools::sort( toBeDeleted, _detail::ByFingerprint<std::less>() );
243 std::vector<Key> unselected;
244 unselected.reserve( toBeDeleted.size() );
245 std::set_difference( toBeDeleted.begin(), toBeDeleted.end(),
246 selected.begin(), selected.end(),
247 std::back_inserter( unselected ),
248 _detail::ByFingerprint<std::less>() );
250 d->ensureDialogCreated();
252 d->dialog->setSelectedKeys( selected );
253 d->dialog->setUnselectedKeys( unselected );
255 d->ensureDialogShown();
259 void DeleteCertificatesCommand::Private::slotDialogAccepted() {
260 std::vector<Key> keys = dialog->keys();
261 assert( !keys.empty() );
263 std::vector<Key>::iterator
264 pgpBegin = keys.begin(),
265 pgpEnd = std::stable_partition( pgpBegin, keys.end(),
266 boost::bind( &GpgME::Key::protocol, _1 ) !=
CMS ),
268 cmsEnd = keys.end() ;
270 std::vector<Key> openpgp( pgpBegin, pgpEnd );
271 std::vector<Key> cms( cmsBegin, cmsEnd );
273 const unsigned int errorCase =
274 openpgp.empty() << 3U | canDelete(
OpenPGP ) << 2U |
275 cms.empty() << 1U | canDelete(
CMS ) << 0U ;
277 if (
const unsigned int actions = deletionErrorCases[errorCase].actions ) {
278 information( i18n( deletionErrorCases[errorCase].text ),
280 ? i18n(
"Certificate Deletion Failed" )
281 : i18n(
"Certificate Deletion Problem" ) );
282 if ( actions & ClearCMS )
284 if ( actions & ClearPGP )
286 if ( actions & Failure ) {
292 assert( !openpgp.empty() || !cms.empty() );
294 pgpKeys.swap( openpgp );
297 if ( !pgpKeys.empty() )
299 if ( !cmsKeys.empty() )
302 if ( ( pgpKeys.empty() || pgpError.code() ) &&
303 ( cmsKeys.empty() || cmsError.code() ) )
304 showErrorsAndFinish();
307 void DeleteCertificatesCommand::Private::startDeleteJob( GpgME::Protocol protocol ) {
308 assert( protocol != GpgME::UnknownProtocol );
310 const std::vector<Key> & keys = protocol ==
CMS ? cmsKeys : pgpKeys ;
312 const CryptoBackend::Protocol *
const backend = CryptoBackendFactory::instance()->protocol( protocol );
315 std::auto_ptr<MultiDeleteJob> job(
new MultiDeleteJob( backend ) );
317 if ( protocol ==
CMS )
318 connect( job.get(), SIGNAL(result(GpgME::Error,GpgME::Key)),
319 q_func(), SLOT(cmsDeleteResult(GpgME::Error)) );
321 connect( job.get(), SIGNAL(result(GpgME::Error,GpgME::Key)),
322 q_func(), SLOT(pgpDeleteResult(GpgME::Error)) );
324 connect( job.get(), SIGNAL(progress(QString,
int,
int)),
325 q, SIGNAL(progress(QString,
int,
int)) );
327 if (
const Error err = job->start( keys,
true ) )
328 ( protocol ==
CMS ? cmsError : pgpError ) = err;
330 ( protocol ==
CMS ? cmsJob : pgpJob ) = job.release();
333 void DeleteCertificatesCommand::Private::showErrorsAndFinish() {
335 assert( !pgpJob ); assert( !cmsJob );
337 if ( pgpError || cmsError ) {
338 QString pgpErrorString;
340 pgpErrorString = i18n(
"OpenPGP backend: %1", QString::fromLocal8Bit( pgpError.asString() ) );
341 QString cmsErrorString;
343 cmsErrorString = i18n(
"CMS backend: %1", QString::fromLocal8Bit( cmsError.asString() ) );
345 const QString msg = i18n(
"<qt><p>An error occurred while trying to delete "
346 "the certificate:</p>"
347 "<p><b>%1</b></p></qt>",
348 pgpError ? cmsError ? pgpErrorString + QLatin1String(
"</br>") + cmsErrorString : pgpErrorString : cmsErrorString );
349 error( msg, i18n(
"Certificate Deletion Failed") );
351 std::vector<Key> keys = pgpKeys;
352 keys.insert( keys.end(), cmsKeys.begin(), cmsKeys.end() );
359 void DeleteCertificatesCommand::doCancel() {
363 void DeleteCertificatesCommand::Private::pgpDeleteResult(
const Error & err ) {
367 showErrorsAndFinish();
370 void DeleteCertificatesCommand::Private::cmsDeleteResult(
const Error & err ) {
374 showErrorsAndFinish();
377 void DeleteCertificatesCommand::Private::cancelJobs()
380 cmsJob->slotCancel();
382 pgpJob->slotCancel();
388 #include "moc_deletecertificatescommand.cpp"
DeleteCertificatesCommand(QAbstractItemView *view, KeyListController *parent)
kdtools::pimpl_ptr< Private > d
static boost::shared_ptr< const KeyCache > instance()
~DeleteCertificatesCommand()
static boost::shared_ptr< KeyCache > mutableInstance()