Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F34212035
deletecertificatescommand.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
12 KB
Subscribers
None
deletecertificatescommand.cpp
View Options
/*
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include
<config-kleopatra.h>
#include
"deletecertificatescommand.h"
#include
"command_p.h"
#include
<dialogs/deletecertificatesdialog.h>
#include
<Libkleo/Formatting>
#include
<Libkleo/KeyCache>
#include
<Libkleo/Predicates>
#include
<Libkleo/Stl_Util>
#include
<QGpgME/DeleteJob>
#include
<QGpgME/MultiDeleteJob>
#include
<QGpgME/Protocol>
#include
<qgpgme/qgpgme_version.h>
#include
<gpgme++/key.h>
#include
<KLocalizedString>
#include
<QAbstractItemView>
#include
<QPointer>
#include
<KLazyLocalizedString>
#include
<algorithm>
#include
<vector>
using
namespace
GpgME
;
using
namespace
Kleo
;
using
namespace
Kleo
::
Dialogs
;
using
namespace
QGpgME
;
class
DeleteCertificatesCommand
::
Private
:
public
Command
::
Private
{
friend
class
::
Kleo
::
DeleteCertificatesCommand
;
DeleteCertificatesCommand
*
q_func
()
const
{
return
static_cast
<
DeleteCertificatesCommand
*>
(
q
);
}
public
:
explicit
Private
(
DeleteCertificatesCommand
*
qq
,
KeyListController
*
c
);
~
Private
()
override
;
void
startDeleteJob
(
GpgME
::
Protocol
protocol
);
void
cancelJobs
();
void
pgpDeleteResult
(
const
GpgME
::
Error
&
);
void
cmsDeleteResult
(
const
GpgME
::
Error
&
);
void
showErrorsAndFinish
();
bool
canDelete
(
GpgME
::
Protocol
proto
)
const
{
if
(
const
auto
cbp
=
(
proto
==
GpgME
::
OpenPGP
?
QGpgME
::
openpgp
()
:
QGpgME
::
smime
()))
if
(
DeleteJob
*
const
job
=
cbp
->
deleteJob
())
{
job
->
slotCancel
();
return
true
;
}
return
false
;
}
void
ensureDialogCreated
()
{
if
(
dialog
)
{
return
;
}
dialog
=
new
DeleteCertificatesDialog
;
applyWindowID
(
dialog
);
dialog
->
setAttribute
(
Qt
::
WA_DeleteOnClose
);
dialog
->
setWindowTitle
(
i18nc
(
"@title:window"
,
"Delete Certificates"
));
connect
(
dialog
,
&
QDialog
::
accepted
,
q_func
(),
[
this
]()
{
slotDialogAccepted
();
});
connect
(
dialog
,
&
QDialog
::
rejected
,
q_func
(),
[
this
]()
{
slotDialogRejected
();
});
}
void
ensureDialogShown
()
{
if
(
dialog
)
{
dialog
->
show
();
}
}
void
slotDialogAccepted
();
void
slotDialogRejected
()
{
canceled
();
}
private
:
QPointer
<
DeleteCertificatesDialog
>
dialog
;
QPointer
<
MultiDeleteJob
>
cmsJob
,
pgpJob
;
GpgME
::
Error
cmsError
,
pgpError
;
std
::
vector
<
Key
>
cmsKeys
,
pgpKeys
;
std
::
shared_ptr
<
KeyCacheAutoRefreshSuspension
>
keyCacheAutoRefreshSuspension
;
};
DeleteCertificatesCommand
::
Private
*
DeleteCertificatesCommand
::
d_func
()
{
return
static_cast
<
Private
*>
(
d
.
get
());
}
const
DeleteCertificatesCommand
::
Private
*
DeleteCertificatesCommand
::
d_func
()
const
{
return
static_cast
<
const
Private
*>
(
d
.
get
());
}
#define d d_func()
#define q q_func()
DeleteCertificatesCommand
::
Private
::
Private
(
DeleteCertificatesCommand
*
qq
,
KeyListController
*
c
)
:
Command
::
Private
(
qq
,
c
)
{
}
DeleteCertificatesCommand
::
Private
::~
Private
()
{
}
DeleteCertificatesCommand
::
DeleteCertificatesCommand
(
KeyListController
*
p
)
:
Command
(
new
Private
(
this
,
p
))
{
}
DeleteCertificatesCommand
::
DeleteCertificatesCommand
(
QAbstractItemView
*
v
,
KeyListController
*
p
)
:
Command
(
v
,
new
Private
(
this
,
p
))
{
}
DeleteCertificatesCommand
::~
DeleteCertificatesCommand
()
{
}
namespace
{
enum
Action
{
Nothing
=
0
,
Failure
=
1
,
ClearCMS
=
2
,
ClearPGP
=
4
};
// const unsigned int errorCase =
// openpgp.empty() << 3U | d->canDelete( OpenPGP ) << 2U |
// cms.empty() << 1U | d->canDelete( CMS ) << 0U ;
static
const
struct
{
const
KLazyLocalizedString
text
;
Action
actions
;
}
deletionErrorCases
[
16
]
=
{
// if havePGP
// if cantPGP
// if haveCMS
{
kli18n
(
"Neither the OpenPGP nor the CMS "
"backends support certificate deletion.
\n
"
"Check your installation."
),
Failure
},
// cantCMS
{
kli18n
(
"The OpenPGP backend does not support "
"certificate deletion.
\n
"
"Check your installation.
\n
"
"Only the selected CMS certificates "
"will be deleted."
),
ClearPGP
},
// canCMS
// if !haveCMS
{
kli18n
(
"The OpenPGP backend does not support "
"certificate deletion.
\n
"
"Check your installation."
),
Failure
},
{
kli18n
(
"The OpenPGP backend does not support "
"certificate deletion.
\n
"
"Check your installation."
),
Failure
},
// if canPGP
// if haveCMS
{
kli18n
(
"The CMS backend does not support "
"certificate deletion.
\n
"
"Check your installation.
\n
"
"Only the selected OpenPGP certificates "
"will be deleted."
),
ClearCMS
},
// cantCMS
{
KLazyLocalizedString
(),
Nothing
},
// canCMS
// if !haveCMS
{
KLazyLocalizedString
(),
Nothing
},
// cantCMS
{
KLazyLocalizedString
(),
Nothing
},
// canCMS
// if !havePGP
// if cantPGP
// if haveCMS
{
kli18n
(
"The CMS backend does not support "
"certificate deletion.
\n
"
"Check your installation."
),
Failure
},
// cantCMS
{
KLazyLocalizedString
(),
Nothing
},
// canCMS
// if !haveCMS
{
KLazyLocalizedString
(),
Nothing
},
// cantCMS
{
KLazyLocalizedString
(),
Nothing
},
// canCMS
// if canPGP
// if haveCMS
{
kli18n
(
"The CMS backend does not support "
"certificate deletion.
\n
"
"Check your installation."
),
Failure
},
// cantCMS
{
KLazyLocalizedString
(),
Nothing
},
// canCMS
// if !haveCMS
{
KLazyLocalizedString
(),
Nothing
},
// cantCMS
{
KLazyLocalizedString
(),
Nothing
},
// canCMS
};
}
// anon namespace
void
DeleteCertificatesCommand
::
doStart
()
{
std
::
vector
<
Key
>
selected
=
d
->
keys
();
if
(
selected
.
empty
())
{
d
->
finished
();
return
;
}
std
::
sort
(
selected
.
begin
(),
selected
.
end
(),
_detail
::
ByFingerprint
<
std
::
less
>
());
// Calculate the closure of the selected keys (those that need to
// be deleted with them, though not selected themselves):
std
::
vector
<
Key
>
toBeDeleted
=
KeyCache
::
instance
()
->
findSubjects
(
selected
);
std
::
sort
(
toBeDeleted
.
begin
(),
toBeDeleted
.
end
(),
_detail
::
ByFingerprint
<
std
::
less
>
());
std
::
vector
<
Key
>
unselected
;
unselected
.
reserve
(
toBeDeleted
.
size
());
std
::
set_difference
(
toBeDeleted
.
begin
(),
toBeDeleted
.
end
(),
selected
.
begin
(),
selected
.
end
(),
std
::
back_inserter
(
unselected
),
_detail
::
ByFingerprint
<
std
::
less
>
());
d
->
ensureDialogCreated
();
d
->
dialog
->
setSelectedKeys
(
selected
);
d
->
dialog
->
setUnselectedKeys
(
unselected
);
d
->
ensureDialogShown
();
}
void
DeleteCertificatesCommand
::
Private
::
slotDialogAccepted
()
{
std
::
vector
<
Key
>
keys
=
dialog
->
keys
();
Q_ASSERT
(
!
keys
.
empty
());
auto
pgpBegin
=
keys
.
begin
();
auto
pgpEnd
=
std
::
stable_partition
(
pgpBegin
,
keys
.
end
(),
[](
const
GpgME
::
Key
&
key
)
{
return
key
.
protocol
()
!=
GpgME
::
CMS
;
});
auto
cmsBegin
=
pgpEnd
;
auto
cmsEnd
=
keys
.
end
();
std
::
vector
<
Key
>
openpgp
(
pgpBegin
,
pgpEnd
);
std
::
vector
<
Key
>
cms
(
cmsBegin
,
cmsEnd
);
const
unsigned
int
errorCase
=
//
openpgp
.
empty
()
<<
3U
//
|
canDelete
(
OpenPGP
)
<<
2U
//
|
cms
.
empty
()
<<
1U
//
|
canDelete
(
CMS
)
<<
0U
;
if
(
const
unsigned
int
actions
=
deletionErrorCases
[
errorCase
].
actions
)
{
information
(
KLocalizedString
(
deletionErrorCases
[
errorCase
].
text
).
toString
(),
(
actions
&
Failure
)
?
i18n
(
"Certificate Deletion Failed"
)
:
i18n
(
"Certificate Deletion Problem"
));
if
(
actions
&
ClearCMS
)
{
cms
.
clear
();
}
if
(
actions
&
ClearPGP
)
{
openpgp
.
clear
();
}
if
(
actions
&
Failure
)
{
canceled
();
return
;
}
}
Q_ASSERT
(
!
openpgp
.
empty
()
||
!
cms
.
empty
());
pgpKeys
.
swap
(
openpgp
);
cmsKeys
.
swap
(
cms
);
keyCacheAutoRefreshSuspension
=
KeyCache
::
mutableInstance
()
->
suspendAutoRefresh
();
if
(
!
pgpKeys
.
empty
())
{
startDeleteJob
(
GpgME
::
OpenPGP
);
}
if
(
!
cmsKeys
.
empty
())
{
startDeleteJob
(
GpgME
::
CMS
);
}
if
((
pgpKeys
.
empty
()
||
pgpError
.
code
())
&&
(
cmsKeys
.
empty
()
||
cmsError
.
code
()))
{
showErrorsAndFinish
();
}
}
void
DeleteCertificatesCommand
::
Private
::
startDeleteJob
(
GpgME
::
Protocol
protocol
)
{
Q_ASSERT
(
protocol
!=
GpgME
::
UnknownProtocol
);
const
std
::
vector
<
Key
>
&
keys
=
protocol
==
CMS
?
cmsKeys
:
pgpKeys
;
const
auto
backend
=
(
protocol
==
GpgME
::
OpenPGP
)
?
QGpgME
::
openpgp
()
:
QGpgME
::
smime
();
Q_ASSERT
(
backend
);
std
::
unique_ptr
<
MultiDeleteJob
>
job
(
new
MultiDeleteJob
(
backend
));
connect
(
job
.
get
(),
&
QGpgME
::
MultiDeleteJob
::
result
,
q_func
(),
[
this
,
protocol
](
const
GpgME
::
Error
&
result
)
{
if
(
protocol
==
CMS
)
{
cmsDeleteResult
(
result
);
}
else
{
pgpDeleteResult
(
result
);
}
});
connect
(
job
.
get
(),
&
QGpgME
::
Job
::
jobProgress
,
q
,
&
Command
::
progress
);
#if QGPGME_VERSION >= QT_VERSION_CHECK(2, 0, 1)
if
(
const
Error
err
=
job
->
start
(
keys
,
GpgME
::
Context
::
DeletionFlags
::
DeleteAllowSecret
|
GpgME
::
Context
::
DeletionFlags
::
DeleteForce
))
{
#else
if
(
const
Error
err
=
job
->
start
(
keys
,
true
/* allowSecretKeyDeletion */
))
{
#endif
(
protocol
==
CMS
?
cmsError
:
pgpError
)
=
err
;
}
else
{
(
protocol
==
CMS
?
cmsJob
:
pgpJob
)
=
job
.
release
();
}
}
void
DeleteCertificatesCommand
::
Private
::
showErrorsAndFinish
()
{
Q_ASSERT
(
!
pgpJob
);
Q_ASSERT
(
!
cmsJob
);
// on success, we know which keys were removed
#if QGPGME_VERSION >= QT_VERSION_CHECK(2, 0, 0)
if
(
!
pgpKeys
.
empty
()
&&
pgpError
.
isSuccess
())
{
#else
if
(
!
pgpKeys
.
empty
()
&&
!
pgpError
&&
!
pgpError
.
isCanceled
())
{
#endif
KeyCache
::
mutableInstance
()
->
remove
(
pgpKeys
);
}
#if QGPGME_VERSION >= QT_VERSION_CHECK(2, 0, 0)
if
(
!
cmsKeys
.
empty
()
&&
cmsError
.
isSuccess
())
{
#else
if
(
!
cmsKeys
.
empty
()
&&
!
cmsError
&&
!
cmsError
.
isCanceled
())
{
#endif
KeyCache
::
mutableInstance
()
->
remove
(
cmsKeys
);
}
// force a keylisting in any case because the deleted keys might have certified other keys
const
GpgME
::
Protocol
protocolToUpdate
=
(
!
pgpKeys
.
empty
()
//
?
(
!
cmsKeys
.
empty
()
//
?
GpgME
::
Protocol
::
UnknownProtocol
:
GpgME
::
Protocol
::
OpenPGP
)
:
GpgME
::
Protocol
::
CMS
);
KeyCache
::
mutableInstance
()
->
reload
(
protocolToUpdate
,
KeyCache
::
ForceReload
);
if
(
pgpError
||
cmsError
)
{
QString
pgpErrorString
;
if
(
pgpError
)
{
pgpErrorString
=
i18n
(
"OpenPGP backend: %1"
,
Formatting
::
errorAsString
(
pgpError
));
}
QString
cmsErrorString
;
if
(
cmsError
)
{
cmsErrorString
=
i18n
(
"CMS backend: %1"
,
Formatting
::
errorAsString
(
cmsError
));
}
const
QString
msg
=
i18n
(
"<qt><p>An error occurred while trying to delete "
"the certificate:</p>"
"<p><b>%1</b></p></qt>"
,
pgpError
?
cmsError
?
pgpErrorString
+
QLatin1StringView
(
"</br>"
)
+
cmsErrorString
:
pgpErrorString
:
cmsErrorString
);
error
(
msg
,
i18n
(
"Certificate Deletion Failed"
));
}
finished
();
}
void
DeleteCertificatesCommand
::
doCancel
()
{
d
->
cancelJobs
();
}
void
DeleteCertificatesCommand
::
Private
::
pgpDeleteResult
(
const
Error
&
err
)
{
pgpError
=
err
;
pgpJob
=
nullptr
;
if
(
!
cmsJob
)
{
showErrorsAndFinish
();
}
}
void
DeleteCertificatesCommand
::
Private
::
cmsDeleteResult
(
const
Error
&
err
)
{
cmsError
=
err
;
cmsJob
=
nullptr
;
if
(
!
pgpJob
)
{
showErrorsAndFinish
();
}
}
void
DeleteCertificatesCommand
::
Private
::
cancelJobs
()
{
if
(
cmsJob
)
{
cmsJob
->
slotCancel
();
}
if
(
pgpJob
)
{
pgpJob
->
slotCancel
();
}
}
#undef d
#undef q
#include
"moc_deletecertificatescommand.cpp"
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Fri, Dec 19, 3:27 AM (11 h, 33 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
2b/8f/95e4378df09518f2eaba8a0d35dc
Attached To
rKLEOPATRA Kleopatra
Event Timeline
Log In to Comment