Page MenuHome GnuPG

No OneTemporary

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 4be1ae837..175927735 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,638 +1,638 @@
# SPDX-FileCopyrightText: none
# SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(icons)
add_subdirectory(mimetypes)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
if (NOT DISABLE_KWATCHGNUPG)
add_subdirectory(kwatchgnupg)
endif()
add_subdirectory(libkleopatraclient)
add_subdirectory(conf)
if(WIN32)
set(_kleopatra_extra_uiserver_SRCS uiserver/uiserver_win.cpp)
set(_kleopatra_extra_SRCS
selftest/registrycheck.cpp selftest/registrycheck.h
utils/gnupg-registry.c
utils/userinfo_win.cpp
utils/windowsprocessdevice.cpp utils/windowsprocessdevice.h
versioninfo.rc kleopatra.w32-manifest
)
else()
set(_kleopatra_extra_uiserver_SRCS uiserver/uiserver_unix.cpp)
set(_kleopatra_extra_SRCS)
endif()
set(_kleopatra_uiserver_SRCS
${_kleopatra_extra_uiserver_SRCS}
selftest/uiservercheck.cpp selftest/uiservercheck.h
uiserver/assuanserverconnection.cpp uiserver/assuanserverconnection.h
uiserver/createchecksumscommand.cpp uiserver/createchecksumscommand.h
uiserver/decryptverifycommandemailbase.cpp uiserver/decryptverifycommandemailbase.h
uiserver/decryptverifycommandfilesbase.cpp uiserver/decryptverifycommandfilesbase.h
uiserver/echocommand.cpp uiserver/echocommand.h
uiserver/encryptcommand.cpp uiserver/encryptcommand.h
uiserver/importfilescommand.cpp uiserver/importfilescommand.h
uiserver/prepencryptcommand.cpp uiserver/prepencryptcommand.h
uiserver/prepsigncommand.cpp uiserver/prepsigncommand.h
uiserver/selectcertificatecommand.cpp
uiserver/sessiondata.cpp uiserver/sessiondata.h
uiserver/signcommand.cpp uiserver/signcommand.h
uiserver/signencryptfilescommand.cpp
uiserver/uiserver.cpp
uiserver/verifychecksumscommand.cpp uiserver/verifychecksumscommand.h
)
set(_kleopatra_uiserver_extra_libs LibAssuan::LibAssuan LibGpgError::LibGpgError)
if(HAVE_GPG_ERR_SOURCE_KLEO)
add_definitions(-DGPG_ERR_SOURCE_DEFAULT=GPG_ERR_SOURCE_KLEO)
add_definitions(-DGPGMEPP_ERR_SOURCE_DEFAULT=GPG_ERR_SOURCE_KLEO)
else()
add_definitions(-DGPG_ERR_SOURCE_DEFAULT=GPG_ERR_SOURCE_USER_1)
add_definitions(-DGPGMEPP_ERR_SOURCE_DEFAULT=GPG_ERR_SOURCE_USER_1)
endif()
if(KPim6IdentityManagementCore_FOUND AND KPim6MailTransport_FOUND AND KPim6AkonadiMime_FOUND)
set(_kleopatra_mail_libs
KPim6::IdentityManagementCore # Export OpenPGP keys using WKS
KPim6::MailTransport
KPim6::AkonadiMime
)
add_definitions(-DMAILAKONADI_ENABLED)
endif()
ki18n_wrap_ui(_kleopatra_uiserver_SRCS crypto/gui/signingcertificateselectionwidget.ui)
set(_kleopatra_SRCS
${_kleopatra_extra_SRCS}
accessibility/accessiblelink.cpp
accessibility/accessiblelink_p.h
accessibility/accessiblerichtextlabel.cpp
accessibility/accessiblerichtextlabel_p.h
accessibility/accessiblevaluelabel.cpp
accessibility/accessiblevaluelabel_p.h
accessibility/accessiblewidgetfactory.cpp
accessibility/accessiblewidgetfactory.h
commands/addsubkeycommand.cpp
commands/addsubkeycommand.h
commands/adduseridcommand.cpp
commands/adduseridcommand.h
commands/authenticatepivcardapplicationcommand.cpp
commands/authenticatepivcardapplicationcommand.h
commands/cardcommand.cpp
commands/cardcommand.h
commands/certificatetopivcardcommand.cpp
commands/certificatetopivcardcommand.h
commands/certifycertificatecommand.cpp
commands/certifycertificatecommand.h
commands/certifygroupcommand.cpp
commands/certifygroupcommand.h
commands/changeexpirycommand.cpp
commands/changeexpirycommand.h
commands/changeownertrustcommand.cpp
commands/changeownertrustcommand.h
commands/changepassphrasecommand.cpp
commands/changepassphrasecommand.h
commands/changepincommand.cpp
commands/changepincommand.h
commands/changeroottrustcommand.cpp
commands/changeroottrustcommand.h
commands/checksumcreatefilescommand.cpp
commands/checksumcreatefilescommand.h
commands/checksumverifyfilescommand.cpp
commands/checksumverifyfilescommand.h
commands/clearcrlcachecommand.cpp
commands/clearcrlcachecommand.h
commands/command.cpp
commands/command.h
commands/createcsrforcardkeycommand.cpp
commands/createcsrforcardkeycommand.h
commands/creategroupcommand.cpp
commands/creategroupcommand.h
commands/createopenpgpkeyfromcardkeyscommand.cpp
commands/createopenpgpkeyfromcardkeyscommand.h
commands/decryptverifyclipboardcommand.cpp
commands/decryptverifyclipboardcommand.h
commands/decryptverifyfilescommand.cpp
commands/decryptverifyfilescommand.h
commands/deletecertificatescommand.cpp
commands/deletecertificatescommand.h
commands/detailscommand.cpp
commands/detailscommand.h
commands/dumpcertificatecommand.cpp
commands/dumpcertificatecommand.h
commands/dumpcrlcachecommand.cpp
commands/dumpcrlcachecommand.h
commands/encryptclipboardcommand.cpp
commands/encryptclipboardcommand.h
commands/exportcertificatecommand.cpp
commands/exportcertificatecommand.h
commands/exportgroupscommand.cpp
commands/exportgroupscommand.h
commands/exportopenpgpcertstoservercommand.cpp
commands/exportopenpgpcertstoservercommand.h
commands/exportopenpgpcerttoprovidercommand.cpp
commands/exportopenpgpcerttoprovidercommand.h
commands/exportpaperkeycommand.cpp
commands/exportpaperkeycommand.h
commands/exportsecretkeycommand.cpp
commands/exportsecretkeycommand.h
commands/exportsecretsubkeycommand.cpp
commands/exportsecretsubkeycommand.h
commands/genrevokecommand.cpp
commands/genrevokecommand.h
commands/gnupgprocesscommand.cpp
commands/gnupgprocesscommand.h
commands/importcertificatefromclipboardcommand.cpp
commands/importcertificatefromclipboardcommand.h
commands/importcertificatefromdatacommand.cpp
commands/importcertificatefromdatacommand.h
commands/importcertificatefromfilecommand.cpp
commands/importcertificatefromfilecommand.h
commands/importcertificatefromkeyservercommand.cpp
commands/importcertificatefromkeyservercommand.h
commands/importcertificatefrompivcardcommand.cpp
commands/importcertificatefrompivcardcommand.h
commands/importcertificatescommand.cpp
commands/importcertificatescommand.h
commands/importcrlcommand.cpp
commands/importcrlcommand.h
commands/importpaperkeycommand.cpp
commands/importpaperkeycommand.h
commands/keytocardcommand.cpp
commands/keytocardcommand.h
commands/lookupcertificatescommand.cpp
commands/lookupcertificatescommand.h
commands/newcertificatesigningrequestcommand.cpp
commands/newcertificatesigningrequestcommand.h
commands/newopenpgpcertificatecommand.cpp
commands/newopenpgpcertificatecommand.h
commands/openpgpgeneratecardkeycommand.cpp
commands/openpgpgeneratecardkeycommand.h
commands/pivgeneratecardkeycommand.cpp
commands/pivgeneratecardkeycommand.h
- commands/refreshcertificatecommand.cpp
- commands/refreshcertificatecommand.h
+ commands/refreshcertificatescommand.cpp
+ commands/refreshcertificatescommand.h
commands/refreshopenpgpcertscommand.cpp
commands/refreshopenpgpcertscommand.h
commands/refreshx509certscommand.cpp
commands/refreshx509certscommand.h
commands/reloadkeyscommand.cpp
commands/reloadkeyscommand.h
commands/revokecertificationcommand.cpp
commands/revokecertificationcommand.h
commands/revokekeycommand.cpp
commands/revokekeycommand.h
commands/revokeuseridcommand.cpp
commands/revokeuseridcommand.h
commands/selftestcommand.cpp
commands/selftestcommand.h
commands/setinitialpincommand.cpp
commands/setinitialpincommand.h
commands/setpivcardapplicationadministrationkeycommand.cpp
commands/setpivcardapplicationadministrationkeycommand.h
commands/setprimaryuseridcommand.cpp
commands/setprimaryuseridcommand.h
commands/signclipboardcommand.cpp
commands/signclipboardcommand.h
commands/signencryptfilescommand.cpp
commands/signencryptfilescommand.h
commands/signencryptfoldercommand.cpp
commands/signencryptfoldercommand.h
commands/viewemailfilescommand.cpp
commands/viewemailfilescommand.h
conf/configuredialog.cpp
conf/configuredialog.h
conf/groupsconfigdialog.cpp
conf/groupsconfigdialog.h
conf/groupsconfigwidget.cpp
conf/groupsconfigwidget.h
crypto/autodecryptverifyfilescontroller.cpp
crypto/autodecryptverifyfilescontroller.h
crypto/certificateresolver.cpp
crypto/certificateresolver.h
crypto/checksumsutils_p.cpp
crypto/checksumsutils_p.h
crypto/controller.cpp
crypto/controller.h
crypto/createchecksumscontroller.cpp
crypto/createchecksumscontroller.h
crypto/decryptverifyemailcontroller.cpp
crypto/decryptverifyemailcontroller.h
crypto/decryptverifyfilescontroller.cpp
crypto/decryptverifyfilescontroller.h
crypto/decryptverifytask.cpp
crypto/decryptverifytask.h
crypto/encryptemailcontroller.cpp
crypto/encryptemailcontroller.h
crypto/encryptemailtask.cpp
crypto/encryptemailtask.h
crypto/gui/certificatelineedit.cpp
crypto/gui/certificatelineedit.h
crypto/gui/certificateselectionline.cpp
crypto/gui/certificateselectionline.h
crypto/gui/decryptverifyfilesdialog.cpp
crypto/gui/decryptverifyfilesdialog.h
crypto/gui/decryptverifyfileswizard.cpp
crypto/gui/decryptverifyfileswizard.h
crypto/gui/decryptverifyoperationwidget.cpp
crypto/gui/decryptverifyoperationwidget.h
crypto/gui/encryptemailwizard.cpp
crypto/gui/encryptemailwizard.h
crypto/gui/newresultpage.cpp
crypto/gui/newresultpage.h
crypto/gui/objectspage.cpp
crypto/gui/objectspage.h
crypto/gui/resolverecipientspage.cpp
crypto/gui/resolverecipientspage.h
crypto/gui/resultitemwidget.cpp
crypto/gui/resultitemwidget.h
crypto/gui/resultlistwidget.cpp
crypto/gui/resultlistwidget.h
crypto/gui/resultpage.cpp
crypto/gui/resultpage.h
crypto/gui/signemailwizard.cpp
crypto/gui/signemailwizard.h
crypto/gui/signencryptemailconflictdialog.cpp
crypto/gui/signencryptemailconflictdialog.h
crypto/gui/signencryptfileswizard.cpp
crypto/gui/signencryptfileswizard.h
crypto/gui/signencryptwidget.cpp
crypto/gui/signencryptwidget.h
crypto/gui/signencryptwizard.cpp
crypto/gui/signencryptwizard.h
crypto/gui/signerresolvepage.cpp
crypto/gui/signerresolvepage.h
crypto/gui/signingcertificateselectiondialog.cpp
crypto/gui/signingcertificateselectiondialog.h
crypto/gui/signingcertificateselectionwidget.cpp
crypto/gui/signingcertificateselectionwidget.h
crypto/gui/unknownrecipientwidget.cpp
crypto/gui/unknownrecipientwidget.h
crypto/gui/verifychecksumsdialog.cpp
crypto/gui/verifychecksumsdialog.h
crypto/gui/wizard.cpp
crypto/gui/wizard.h
crypto/gui/wizardpage.cpp
crypto/gui/wizardpage.h
crypto/newsignencryptemailcontroller.cpp
crypto/newsignencryptemailcontroller.h
crypto/recipient.cpp
crypto/recipient.h
crypto/sender.cpp
crypto/sender.h
crypto/signemailcontroller.cpp
crypto/signemailcontroller.h
crypto/signemailtask.cpp
crypto/signemailtask.h
crypto/signencryptfilescontroller.cpp
crypto/signencryptfilescontroller.h
crypto/signencrypttask.cpp
crypto/signencrypttask.h
crypto/task.cpp
crypto/task.h
crypto/taskcollection.cpp
crypto/taskcollection.h
crypto/verifychecksumscontroller.cpp
crypto/verifychecksumscontroller.h
dialogs/addsubkeydialog.cpp
dialogs/addsubkeydialog.h
dialogs/adduseriddialog.cpp
dialogs/adduseriddialog.h
dialogs/animatedexpander.cpp
dialogs/animatedexpander.h
dialogs/cardinfotab.cpp
dialogs/cardinfotab.h
dialogs/certificatedetailsdialog.cpp
dialogs/certificatedetailsdialog.h
dialogs/certificatedetailsinputwidget.cpp
dialogs/certificatedetailsinputwidget.h
dialogs/certificatedetailswidget.cpp
dialogs/certificatedetailswidget.h
dialogs/certificatedumpwidget.cpp
dialogs/certificatedumpwidget.h
dialogs/certificateselectiondialog.cpp
dialogs/certificateselectiondialog.h
dialogs/certifycertificatedialog.cpp
dialogs/certifycertificatedialog.h
dialogs/certifywidget.cpp
dialogs/certifywidget.h
dialogs/createcsrforcardkeydialog.cpp
dialogs/createcsrforcardkeydialog.h
dialogs/deletecertificatesdialog.cpp
dialogs/deletecertificatesdialog.h
dialogs/editgroupdialog.cpp
dialogs/editgroupdialog.h
dialogs/expirydialog.cpp
dialogs/expirydialog.h
dialogs/exportdialog.cpp
dialogs/exportdialog.h
dialogs/gencardkeydialog.cpp
dialogs/gencardkeydialog.h
dialogs/groupdetailsdialog.cpp
dialogs/groupdetailsdialog.h
dialogs/lookupcertificatesdialog.cpp
dialogs/lookupcertificatesdialog.h
dialogs/nameandemailwidget.cpp
dialogs/nameandemailwidget.h
dialogs/newopenpgpcertificatedetailsdialog.cpp
dialogs/newopenpgpcertificatedetailsdialog.h
dialogs/pivcardapplicationadministrationkeyinputdialog.cpp
dialogs/pivcardapplicationadministrationkeyinputdialog.h
dialogs/revokekeydialog.cpp
dialogs/revokekeydialog.h
dialogs/selftestdialog.cpp
dialogs/selftestdialog.h
dialogs/setinitialpindialog.cpp
dialogs/setinitialpindialog.h
dialogs/subkeyswidget.cpp
dialogs/subkeyswidget.h
dialogs/trustchainwidget.cpp
dialogs/trustchainwidget.h
dialogs/updatenotification.cpp
dialogs/updatenotification.h
dialogs/useridswidget.cpp
dialogs/useridswidget.h
dialogs/weboftrustwidget.cpp
dialogs/weboftrustwidget.h
interfaces/anchorprovider.h
interfaces/focusfirstchild.h
newcertificatewizard/advancedsettingsdialog.cpp
newcertificatewizard/advancedsettingsdialog_p.h
newcertificatewizard/enterdetailspage.cpp
newcertificatewizard/enterdetailspage_p.h
newcertificatewizard/keyalgo.cpp
newcertificatewizard/keyalgo_p.h
newcertificatewizard/keycreationpage.cpp
newcertificatewizard/keycreationpage_p.h
newcertificatewizard/listwidget.cpp
newcertificatewizard/listwidget.h
newcertificatewizard/newcertificatewizard.cpp
newcertificatewizard/newcertificatewizard.h
newcertificatewizard/resultpage.cpp
newcertificatewizard/resultpage_p.h
newcertificatewizard/wizardpage.cpp
newcertificatewizard/wizardpage_p.h
selftest/compliancecheck.cpp
selftest/compliancecheck.h
selftest/enginecheck.cpp
selftest/enginecheck.h
selftest/gpgagentcheck.cpp
selftest/gpgagentcheck.h
selftest/gpgconfcheck.cpp
selftest/gpgconfcheck.h
selftest/libkleopatrarccheck.cpp
selftest/libkleopatrarccheck.h
selftest/selftest.cpp
selftest/selftest.h
smartcard/algorithminfo.h
smartcard/card.cpp
smartcard/card.h
smartcard/deviceinfowatcher.cpp
smartcard/deviceinfowatcher.h
smartcard/keypairinfo.cpp
smartcard/keypairinfo.h
smartcard/netkeycard.cpp
smartcard/netkeycard.h
smartcard/openpgpcard.cpp
smartcard/openpgpcard.h
smartcard/p15card.cpp
smartcard/p15card.h
smartcard/pivcard.cpp
smartcard/pivcard.h
smartcard/readerstatus.cpp
smartcard/readerstatus.h
smartcard/utils.cpp
smartcard/utils.h
utils/accessibility.cpp
utils/accessibility.h
utils/action_data.cpp
utils/action_data.h
utils/applicationstate.cpp
utils/applicationstate.h
utils/archivedefinition.cpp
utils/archivedefinition.h
utils/certificatepair.h
utils/clipboardmenu.cpp
utils/clipboardmenu.h
utils/debug-helpers.cpp
utils/debug-helpers.h
utils/dragqueen.cpp
utils/dragqueen.h
utils/email.cpp
utils/email.h
utils/emptypassphraseprovider.cpp
utils/emptypassphraseprovider.h
utils/expiration.cpp
utils/expiration.h
utils/filedialog.cpp
utils/filedialog.h
utils/gui-helper.cpp
utils/gui-helper.h
utils/headerview.cpp
utils/headerview.h
utils/input.cpp
utils/input.h
utils/iodevicelogger.cpp
utils/iodevicelogger.h
utils/kdpipeiodevice.cpp
utils/kdpipeiodevice.h
utils/keyexportdraghandler.cpp
utils/keyexportdraghandler.h
utils/keyparameters.cpp
utils/keyparameters.h
utils/kuniqueservice.cpp
utils/kuniqueservice.h
utils/log.cpp
utils/log.h
utils/memory-helpers.h
utils/migration.cpp
utils/migration.h
utils/multivalidator.cpp
utils/multivalidator.h
utils/output.cpp
utils/output.h
utils/overwritedialog.cpp
utils/overwritedialog.h
utils/path-helper.cpp
utils/path-helper.h
utils/scrollarea.cpp
utils/scrollarea.h
utils/systemtrayicon.cpp
utils/systemtrayicon.h
utils/tags.cpp
utils/tags.h
utils/types.cpp
utils/types.h
utils/userinfo.cpp
utils/userinfo.h
utils/validation.cpp
utils/validation.h
utils/writecertassuantransaction.cpp
utils/writecertassuantransaction.h
utils/wsastarter.cpp
utils/wsastarter.h
view/anchorcache.cpp
view/anchorcache_p.h
view/cardkeysview.cpp
view/cardkeysview.h
view/errorlabel.cpp
view/errorlabel.h
view/formtextinput.cpp
view/formtextinput.h
view/htmllabel.cpp
view/htmllabel.h
view/infofield.cpp
view/infofield.h
view/keycacheoverlay.cpp
view/keycacheoverlay.h
view/keylistcontroller.cpp
view/keylistcontroller.h
view/keytreeview.cpp
view/keytreeview.h
view/netkeywidget.cpp
view/netkeywidget.h
view/nullpinwidget.cpp
view/nullpinwidget.h
view/openpgpkeycardwidget.cpp
view/openpgpkeycardwidget.h
view/overlaywidget.cpp
view/overlaywidget.h
view/p15cardwidget.cpp
view/p15cardwidget.h
view/padwidget.cpp
view/padwidget.h
view/pgpcardwidget.cpp
view/pgpcardwidget.h
view/pivcardwidget.cpp
view/pivcardwidget.h
view/progressoverlay.cpp
view/progressoverlay.h
view/searchbar.cpp
view/searchbar.h
view/smartcardwidget.cpp
view/smartcardwidget.h
view/tabwidget.cpp
view/tabwidget.h
view/textoverlay.cpp
view/textoverlay.h
view/urllabel.cpp
view/urllabel.h
view/waitwidget.cpp
view/waitwidget.h
view/welcomewidget.cpp
view/welcomewidget.h
aboutdata.cpp
aboutdata.h
kleopatra.qrc
kleopatraapplication.cpp
kleopatraapplication.h
main.cpp
mainwindow.cpp
mainwindow.h
systrayicon.cpp
systrayicon.h
)
if(WIN32)
configure_file (versioninfo.rc.in versioninfo.rc)
set(_kleopatra_SRCS ${CMAKE_CURRENT_BINARY_DIR}/versioninfo.rc ${_kleopatra_SRCS})
configure_file (kleopatra.w32-manifest.in kleopatra.w32-manifest)
set(_kleopatra_SRCS ${CMAKE_CURRENT_BINARY_DIR}/kleopatra.w32-manifest ${_kleopatra_SRCS})
endif()
set (_kleopatra_SRCS conf/kleopageconfigdialog.cpp conf/kleopageconfigdialog.h ${_kleopatra_SRCS})
ecm_qt_declare_logging_category(_kleopatra_SRCS HEADER kleopatra_debug.h IDENTIFIER KLEOPATRA_LOG CATEGORY_NAME org.kde.pim.kleopatra
DESCRIPTION "kleopatra (kleopatra)"
OLD_CATEGORY_NAMES log_kleopatra
EXPORT KLEOPATRA
)
if(KLEO_MODEL_TEST)
add_definitions(-DKLEO_MODEL_TEST)
set(_kleopatra_SRCS ${_kleopatra_SRCS} models/modeltest.cpp)
endif()
ki18n_wrap_ui(_kleopatra_SRCS
dialogs/setinitialpindialog.ui
dialogs/trustchainwidget.ui
newcertificatewizard/listwidget.ui
)
kconfig_add_kcfg_files(_kleopatra_SRCS
kcfg/emailoperationspreferences.kcfgc
kcfg/fileoperationspreferences.kcfgc
kcfg/settings.kcfgc
kcfg/smimevalidationpreferences.kcfgc
kcfg/tagspreferences.kcfgc
kcfg/tooltippreferences.kcfgc
)
file(GLOB ICONS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/icons/*-apps-kleopatra.png")
ecm_add_app_icon(_kleopatra_SRCS ICONS ${ICONS_SRCS})
add_executable(kleopatra_bin ${_kleopatra_SRCS} ${_kleopatra_uiserver_SRCS})
# For the ConfigureDialog & KCMs
target_link_libraries(kleopatra_bin kcm_kleopatra_static)
#if (COMPILE_WITH_UNITY_CMAKE_SUPPORT)
# set_target_properties(kleopatra_bin PROPERTIES UNITY_BUILD ON)
#endif()
set_target_properties(kleopatra_bin PROPERTIES OUTPUT_NAME kleopatra)
if (WIN32)
set(_kleopatra_platform_libs "secur32")
endif ()
target_link_libraries(kleopatra_bin
Gpgmepp
KPim6::Libkleo
KPim6::Mime
KPim6::MimeTreeParserWidgets
KF6::Codecs
KF6::CoreAddons
KF6::Crash
KF6::I18n
KF6::IconThemes
KF6::ItemModels
KF6::KIOCore
KF6::KIOWidgets
KF6::WindowSystem
KF6::XmlGui
Qt::Network
Qt::PrintSupport # Printing secret keys
kleopatraclientcore
${_kleopatra_extra_libs}
${_kleopatra_mail_libs}
${_kleopatra_uiserver_extra_libs}
${_kleopatra_dbusaddons_libs}
${_kleopatra_platform_libs}
)
target_link_libraries(kleopatra_bin QGpgmeQt6)
install(TARGETS kleopatra_bin ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
install(
PROGRAMS data/org.kde.kleopatra.desktop data/kleopatra_import.desktop
DESTINATION ${KDE_INSTALL_APPDIR}
)
install(FILES data/org.kde.kleopatra.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR})
install(FILES data/kleopatra-mime.xml DESTINATION ${KDE_INSTALL_MIMEDIR})
install(
PROGRAMS data/kleopatra_signencryptfiles.desktop
data/kleopatra_signencryptfolders.desktop
data/kleopatra_decryptverifyfiles.desktop
data/kleopatra_decryptverifyfolders.desktop
DESTINATION ${KDE_INSTALL_DATADIR}/kio/servicemenus
)
diff --git a/src/commands/refreshcertificatecommand.cpp b/src/commands/refreshcertificatecommand.cpp
deleted file mode 100644
index 5c7c45251..000000000
--- a/src/commands/refreshcertificatecommand.cpp
+++ /dev/null
@@ -1,415 +0,0 @@
-/* -*- mode: c++; c-basic-offset:4 -*-
- commands/refreshcertificatecommand.cpp
-
- This file is part of Kleopatra, the KDE keymanager
- SPDX-FileCopyrightText: 2022 g10 Code GmbH
- SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
-
- SPDX-License-Identifier: GPL-2.0-or-later
-*/
-
-#include <config-kleopatra.h>
-
-#include "command_p.h"
-#include "refreshcertificatecommand.h"
-#include <settings.h>
-
-#include <Libkleo/Formatting>
-#include <Libkleo/GnuPG>
-
-#include <KLocalizedString>
-#include <KMessageBox>
-
-#include <QGpgME/Protocol>
-#include <QGpgME/ReceiveKeysJob>
-#include <QGpgME/RefreshKeysJob>
-#if QGPGME_SUPPORTS_WKD_REFRESH_JOB
-#include <QGpgME/WKDRefreshJob>
-#endif
-
-#include <gpgme++/importresult.h>
-
-#include "kleopatra_debug.h"
-
-using namespace Kleo;
-using namespace GpgME;
-
-class RefreshCertificateCommand::Private : public Command::Private
-{
- friend class ::RefreshCertificateCommand;
- RefreshCertificateCommand *q_func() const
- {
- return static_cast<RefreshCertificateCommand *>(q);
- }
-
-public:
- explicit Private(RefreshCertificateCommand *qq);
- ~Private() override;
-
- void start();
- void cancel();
-
- std::unique_ptr<QGpgME::ReceiveKeysJob> startReceiveKeysJob();
- std::unique_ptr<QGpgME::RefreshKeysJob> startSMIMEJob();
-#if QGPGME_SUPPORTS_WKD_REFRESH_JOB
- std::unique_ptr<QGpgME::WKDRefreshJob> startWKDRefreshJob();
-#endif
- void onReceiveKeysJobResult(const ImportResult &result);
- void onWKDRefreshJobResult(const ImportResult &result);
- void onSMIMEJobResult(const Error &err);
- void showOpenPGPResult();
- void showError(const Error &err);
-
-private:
- Key key;
- QPointer<QGpgME::Job> job;
- ImportResult receiveKeysResult;
- ImportResult wkdRefreshResult;
-};
-
-RefreshCertificateCommand::Private *RefreshCertificateCommand::d_func()
-{
- return static_cast<Private *>(d.get());
-}
-const RefreshCertificateCommand::Private *RefreshCertificateCommand::d_func() const
-{
- return static_cast<const Private *>(d.get());
-}
-
-#define d d_func()
-#define q q_func()
-
-RefreshCertificateCommand::Private::Private(RefreshCertificateCommand *qq)
- : Command::Private{qq}
-{
-}
-
-RefreshCertificateCommand::Private::~Private() = default;
-
-namespace
-{
-Key getKey(const std::vector<Key> &keys)
-{
- if (keys.size() != 1) {
- qCWarning(KLEOPATRA_LOG) << "Expected exactly one key, but got" << keys.size();
- return {};
- }
- const Key key = keys.front();
- if (key.protocol() == GpgME::UnknownProtocol) {
- qCWarning(KLEOPATRA_LOG) << "Key has unknown protocol";
- return {};
- }
- return key;
-}
-}
-
-void RefreshCertificateCommand::Private::start()
-{
- key = getKey(keys());
- if (key.isNull()) {
- finished();
- return;
- }
-
- std::unique_ptr<QGpgME::Job> refreshJob;
- switch (key.protocol()) {
- case GpgME::OpenPGP: {
- if (haveKeyserverConfigured()) {
- refreshJob = startReceiveKeysJob();
- } else {
- QMetaObject::invokeMethod(
- q,
- [this]() {
- // use GPG_ERR_USER_1 to signal skipped key server lookup
- onReceiveKeysJobResult(ImportResult{Error::fromCode(GPG_ERR_USER_1)});
- },
- Qt::QueuedConnection);
- return;
- }
- break;
- }
- case GpgME::CMS:
- refreshJob = startSMIMEJob();
- break;
- default:; // cannot happen ;-)
- }
- if (!refreshJob) {
- finished();
- return;
- }
- job = refreshJob.release();
-}
-
-void RefreshCertificateCommand::Private::cancel()
-{
- if (job) {
- job->slotCancel();
- }
- job.clear();
-}
-
-std::unique_ptr<QGpgME::ReceiveKeysJob> RefreshCertificateCommand::Private::startReceiveKeysJob()
-{
- std::unique_ptr<QGpgME::ReceiveKeysJob> refreshJob{QGpgME::openpgp()->receiveKeysJob()};
- Q_ASSERT(refreshJob);
-
- connect(refreshJob.get(), &QGpgME::ReceiveKeysJob::result, q, [this](const GpgME::ImportResult &result) {
- onReceiveKeysJobResult(result);
- });
- connect(refreshJob.get(), &QGpgME::Job::jobProgress, q, &Command::progress);
-
- const GpgME::Error err = refreshJob->start({QString::fromLatin1(key.primaryFingerprint())});
- if (err) {
- showError(err);
- return {};
- }
- Q_EMIT q->info(i18nc("@info:status", "Updating key..."));
-
- return refreshJob;
-}
-
-std::unique_ptr<QGpgME::RefreshKeysJob> RefreshCertificateCommand::Private::startSMIMEJob()
-{
- std::unique_ptr<QGpgME::RefreshKeysJob> refreshJob{QGpgME::smime()->refreshKeysJob()};
- Q_ASSERT(refreshJob);
-
- connect(refreshJob.get(), &QGpgME::RefreshKeysJob::result, q, [this](const GpgME::Error &err) {
- onSMIMEJobResult(err);
- });
- connect(refreshJob.get(), &QGpgME::Job::jobProgress, q, &Command::progress);
-
- const GpgME::Error err = refreshJob->start({key});
- if (err) {
- showError(err);
- return {};
- }
- Q_EMIT q->info(i18nc("@info:status", "Updating certificate..."));
-
- return refreshJob;
-}
-
-#if QGPGME_SUPPORTS_WKD_REFRESH_JOB
-std::unique_ptr<QGpgME::WKDRefreshJob> RefreshCertificateCommand::Private::startWKDRefreshJob()
-{
- if (!Settings{}.queryWKDsForAllUserIDs()) {
- // check if key is eligible for WKD refresh, i.e. if any user ID has WKD as origin
- const auto userIds = key.userIDs();
- const auto eligibleForWKDRefresh = std::any_of(userIds.begin(), userIds.end(), [](const auto &userId) {
- return !userId.isRevoked() && !userId.addrSpec().empty() && userId.origin() == Key::OriginWKD;
- });
- if (!eligibleForWKDRefresh) {
- wkdRefreshResult = ImportResult{Error::fromCode(GPG_ERR_USER_1)};
- return {};
- }
- }
-
- std::unique_ptr<QGpgME::WKDRefreshJob> refreshJob{QGpgME::openpgp()->wkdRefreshJob()};
- Q_ASSERT(refreshJob);
-
- connect(refreshJob.get(), &QGpgME::WKDRefreshJob::result, q, [this](const GpgME::ImportResult &result) {
- onWKDRefreshJobResult(result);
- });
- connect(refreshJob.get(), &QGpgME::Job::jobProgress, q, &Command::progress);
-
- Error err;
- if (Settings{}.queryWKDsForAllUserIDs()) {
- err = refreshJob->start(key.userIDs());
- } else {
- err = refreshJob->start({key});
- }
- if (err) {
- wkdRefreshResult = ImportResult{err};
- return {};
- }
- Q_EMIT q->info(i18nc("@info:status", "Updating key..."));
-
- return refreshJob;
-}
-#endif
-
-namespace
-{
-static auto informationOnChanges(const ImportResult &result)
-{
- QString text;
-
- // if additional keys have been retrieved via WKD, then most of the below
- // details are just a guess and may concern the additional keys instead of
- // the refresh keys; this could only be clarified by a thorough comparison of
- // unrefreshed and refreshed key
-
- if (result.numUnchanged() == result.numConsidered()) {
- // if numUnchanged < numConsidered, then it is not clear whether the refreshed key
- // hasn't changed or whether another key retrieved via WKD hasn't changed
- text = i18n("The key hasn't changed.");
- } else if (result.newRevocations() > 0) {
- // it is possible that a revoked key has been newly imported via WKD,
- // but it is much more likely that the refreshed key was revoked
- text = i18n("The key has been revoked.");
- } else {
- // it doesn't make much sense to list below details if the key has been revoked
- text = i18n("The key has been updated.");
-
- QStringList details;
- if (result.newUserIDs() > 0) {
- details.push_back(i18n("New user IDs: %1", result.newUserIDs()));
- }
- if (result.newSubkeys() > 0) {
- details.push_back(i18n("New subkeys: %1", result.newSubkeys()));
- }
- if (result.newSignatures() > 0) {
- details.push_back(i18n("New signatures: %1", result.newSignatures()));
- }
- if (!details.empty()) {
- text += QLatin1StringView{"<br><br>"} + details.join(QLatin1String{"<br>"});
- }
- }
-
- text = QLatin1StringView{"<p>"} + text + QLatin1String{"</p>"};
- if (result.numImported() > 0) {
- text += QLatin1StringView{"<p>"}
- + i18np("Additionally, one new key has been retrieved.", "Additionally, %1 new keys have been retrieved.", result.numImported())
- + QLatin1StringView{"</p>"};
- }
-
- return text;
-}
-
-}
-
-void RefreshCertificateCommand::Private::onReceiveKeysJobResult(const ImportResult &result)
-{
- receiveKeysResult = result;
-
- if (result.error().isCanceled()) {
- finished();
- return;
- }
-
-#if QGPGME_SUPPORTS_WKD_REFRESH_JOB
- std::unique_ptr<QGpgME::Job> refreshJob = startWKDRefreshJob();
- if (!refreshJob) {
- showOpenPGPResult();
- return;
- }
- job = refreshJob.release();
-#else
- if (receiveKeysResult.error()) {
- if (receiveKeysResult.error().code() == GPG_ERR_USER_1) {
- information(i18nc("@info", "The update was skipped because no keyserver is configured."), i18nc("@title:window", "Update Skipped"));
- } else {
- showError(receiveKeysResult.error());
- }
- } else {
- information(informationOnChanges(receiveKeysResult), i18nc("@title:window", "Key Updated"));
- }
-
- finished();
-#endif
-}
-
-void RefreshCertificateCommand::Private::onWKDRefreshJobResult(const ImportResult &result)
-{
- wkdRefreshResult = result;
-
- showOpenPGPResult();
-}
-
-void RefreshCertificateCommand::Private::onSMIMEJobResult(const Error &err)
-{
- if (err) {
- showError(err);
- finished();
- return;
- }
-
- if (!err.isCanceled()) {
- information(i18nc("@info", "The certificate has been updated."), i18nc("@title:window", "Certificate Updated"));
- }
- finished();
-}
-
-void RefreshCertificateCommand::Private::showOpenPGPResult()
-{
- if (wkdRefreshResult.error().code() == GPG_ERR_USER_1 || wkdRefreshResult.error().isCanceled()) {
- if (receiveKeysResult.error()) {
- if (receiveKeysResult.error().code() == GPG_ERR_USER_1) {
- information(i18nc("@info", "The update was skipped because no keyserver is configured."), i18nc("@title:window", "Update Skipped"));
- } else {
- showError(receiveKeysResult.error());
- }
- } else {
- information(informationOnChanges(receiveKeysResult), i18nc("@title:window", "Key Updated"));
- }
- finished();
- return;
- }
-
- if (receiveKeysResult.error() && (receiveKeysResult.error().code() != GPG_ERR_USER_1) && wkdRefreshResult.error()) {
- error(xi18nc("@info",
- "<para>Updating the certificate from a keyserver, an LDAP server, or Active Directory failed:</para>"
- "<para><message>%1</message></para>"
- "<para>Updating the certificate via Web Key Directory failed:</para>"
- "<para><message>%2</message></para>",
- Formatting::errorAsString(receiveKeysResult.error()),
- Formatting::errorAsString(wkdRefreshResult.error())),
- i18nc("@title:window", "Update Failed"));
- finished();
- return;
- }
-
- QString text;
- text +=
- QLatin1StringView{"<p><strong>"} + i18nc("@info", "Result of update from keyserver, LDAP server, or Active Directory") + QLatin1String{"</strong></p>"};
- if (receiveKeysResult.error()) {
- if (receiveKeysResult.error().code() == GPG_ERR_USER_1) {
- text += xi18nc("@info", "<para>The update was skipped because no keyserver is configured.</para>");
- } else {
- text += xi18nc("@info", "<para>The update failed: <message>%1</message></para>", Formatting::errorAsString(receiveKeysResult.error()));
- }
- } else {
- text += informationOnChanges(receiveKeysResult);
- }
-
- text += QLatin1StringView{"<p><strong>"} + i18nc("@info", "Result of update via Web Key Directory") + QLatin1String{"</strong></p>"};
- if (wkdRefreshResult.error()) {
- text += xi18nc("@info", "<para>The update failed: <message>%1</message></para>", Formatting::errorAsString(wkdRefreshResult.error()));
- } else {
- text += informationOnChanges(wkdRefreshResult);
- }
-
- information(text, i18nc("@title:window", "Key Updated"));
-
- finished();
-}
-
-void RefreshCertificateCommand::Private::showError(const Error &err)
-{
- error(xi18nc("@info",
- "<para>An error occurred while updating the certificate:</para>"
- "<para><message>%1</message></para>",
- Formatting::errorAsString(err)),
- i18nc("@title:window", "Update Failed"));
-}
-
-RefreshCertificateCommand::RefreshCertificateCommand(const GpgME::Key &key)
- : Command{key, new Private{this}}
-{
-}
-
-RefreshCertificateCommand::~RefreshCertificateCommand() = default;
-
-void RefreshCertificateCommand::doStart()
-{
- d->start();
-}
-
-void RefreshCertificateCommand::doCancel()
-{
- d->cancel();
-}
-
-#undef d
-#undef q
-
-#include "moc_refreshcertificatecommand.cpp"
diff --git a/src/commands/refreshcertificatescommand.cpp b/src/commands/refreshcertificatescommand.cpp
new file mode 100644
index 000000000..062cc2c38
--- /dev/null
+++ b/src/commands/refreshcertificatescommand.cpp
@@ -0,0 +1,434 @@
+/* -*- mode: c++; c-basic-offset:4 -*-
+ commands/refreshcertificatecommand.cpp
+
+ This file is part of Kleopatra, the KDE keymanager
+ SPDX-FileCopyrightText: 2022 g10 Code GmbH
+ SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
+
+ SPDX-License-Identifier: GPL-2.0-or-later
+*/
+
+#include <config-kleopatra.h>
+
+#include "command_p.h"
+#include "refreshcertificatescommand.h"
+#include <settings.h>
+
+#include <Libkleo/Formatting>
+#include <Libkleo/GnuPG>
+#include <Libkleo/KeyHelpers>
+
+#include <KLocalizedString>
+#include <KMessageBox>
+
+#include <QGpgME/Protocol>
+#include <QGpgME/ReceiveKeysJob>
+#include <QGpgME/RefreshKeysJob>
+#if QGPGME_SUPPORTS_WKD_REFRESH_JOB
+#include <QGpgME/WKDRefreshJob>
+#endif
+
+#include <gpgme++/importresult.h>
+
+#include "kleopatra_debug.h"
+
+using namespace Kleo;
+using namespace GpgME;
+
+class RefreshCertificatesCommand::Private : public Command::Private
+{
+ friend class ::RefreshCertificatesCommand;
+ RefreshCertificatesCommand *q_func() const
+ {
+ return static_cast<RefreshCertificatesCommand *>(q);
+ }
+
+public:
+ explicit Private(RefreshCertificatesCommand *qq);
+ explicit Private(RefreshCertificatesCommand *qq, KeyListController *c);
+ ~Private() override;
+
+ void start();
+ void cancel();
+
+ std::unique_ptr<QGpgME::ReceiveKeysJob> startKeyserverJob();
+ std::unique_ptr<QGpgME::RefreshKeysJob> startSMIMEJob();
+#if QGPGME_SUPPORTS_WKD_REFRESH_JOB
+ std::unique_ptr<QGpgME::WKDRefreshJob> startWKDRefreshJob();
+#endif
+
+ void onKeyserverJobResult(const ImportResult &result);
+ void onWKDRefreshJobResult(const ImportResult &result);
+ void onSMIMEJobResult(const Error &err);
+
+ void checkFinished();
+
+private:
+ QPointer<QGpgME::Job> pgpJob;
+ QPointer<QGpgME::Job> smimeJob;
+ QPointer<QGpgME::Job> wkdJob;
+
+ std::vector<Key> pgpKeys;
+ std::vector<Key> smimeKeys;
+ std::vector<Key> wkdKeys;
+
+ ImportResult keyserverResult;
+ ImportResult wkdRefreshResult;
+ std::optional<Error> smimeError;
+};
+
+RefreshCertificatesCommand::Private *RefreshCertificatesCommand::d_func()
+{
+ return static_cast<Private *>(d.get());
+}
+const RefreshCertificatesCommand::Private *RefreshCertificatesCommand::d_func() const
+{
+ return static_cast<const Private *>(d.get());
+}
+
+#define d d_func()
+#define q q_func()
+
+RefreshCertificatesCommand::Private::Private(RefreshCertificatesCommand *qq)
+ : Command::Private{qq}
+{
+}
+
+RefreshCertificatesCommand::Private::Private(RefreshCertificatesCommand *qq, KeyListController *c)
+ : Command::Private{qq, c}
+{
+}
+
+RefreshCertificatesCommand::Private::~Private() = default;
+
+void RefreshCertificatesCommand::Private::start()
+{
+ if (std::ranges::any_of(keys(), [](const auto &key) {
+ return key.protocol() == GpgME::UnknownProtocol;
+ })) {
+ qCWarning(KLEOPATRA_LOG) << "Key has unknown protocol";
+ finished();
+ return;
+ }
+
+ std::unique_ptr<QGpgME::Job> pgpRefreshJob;
+ std::unique_ptr<QGpgME::Job> smimeRefreshJob;
+ std::unique_ptr<QGpgME::Job> wkdRefreshJob;
+
+ auto keysByProtocol = Kleo::partitionKeysByProtocol(keys());
+
+ pgpKeys = keysByProtocol.openpgp;
+ smimeKeys = keysByProtocol.cms;
+
+ if (!smimeKeys.empty()) {
+ smimeRefreshJob = startSMIMEJob();
+ }
+
+ if (!pgpKeys.empty()) {
+ if (haveKeyserverConfigured()) {
+ pgpRefreshJob = startKeyserverJob();
+ } else {
+ keyserverResult = ImportResult{Error::fromCode(GPG_ERR_USER_1)};
+ }
+#if QGPGME_SUPPORTS_WKD_REFRESH_JOB
+ wkdRefreshJob = startWKDRefreshJob();
+#endif
+ }
+
+ if (!pgpRefreshJob && !smimeRefreshJob && !wkdRefreshJob) {
+ finished();
+ return;
+ }
+ pgpJob = pgpRefreshJob.release();
+ smimeJob = smimeRefreshJob.release();
+ wkdJob = wkdRefreshJob.release();
+}
+
+void RefreshCertificatesCommand::Private::cancel()
+{
+ if (pgpJob) {
+ pgpJob->slotCancel();
+ }
+
+ if (smimeJob) {
+ smimeJob->slotCancel();
+ }
+
+ if (wkdJob) {
+ wkdJob->slotCancel();
+ }
+
+ pgpJob.clear();
+ smimeJob.clear();
+ wkdJob.clear();
+
+ smimeError = Error::fromCode(GPG_ERR_CANCELED);
+}
+
+std::unique_ptr<QGpgME::ReceiveKeysJob> RefreshCertificatesCommand::Private::startKeyserverJob()
+{
+ std::unique_ptr<QGpgME::ReceiveKeysJob> refreshJob{QGpgME::openpgp()->receiveKeysJob()};
+ Q_ASSERT(refreshJob);
+
+ connect(refreshJob.get(), &QGpgME::ReceiveKeysJob::result, q, [this](const GpgME::ImportResult &result) {
+ onKeyserverJobResult(result);
+ });
+ connect(refreshJob.get(), &QGpgME::Job::jobProgress, q, &Command::progress);
+
+ refreshJob->start(Kleo::getFingerprints(pgpKeys));
+
+ Q_EMIT q->info(i18nc("@info:status", "Updating key..."));
+
+ return refreshJob;
+}
+
+std::unique_ptr<QGpgME::RefreshKeysJob> RefreshCertificatesCommand::Private::startSMIMEJob()
+{
+ std::unique_ptr<QGpgME::RefreshKeysJob> refreshJob{QGpgME::smime()->refreshKeysJob()};
+ Q_ASSERT(refreshJob);
+
+ connect(refreshJob.get(), &QGpgME::RefreshKeysJob::result, q, [this](const GpgME::Error &err) {
+ onSMIMEJobResult(err);
+ });
+ connect(refreshJob.get(), &QGpgME::Job::jobProgress, q, &Command::progress);
+
+ refreshJob->start(smimeKeys);
+
+ Q_EMIT q->info(i18nc("@info:status", "Updating certificate..."));
+
+ return refreshJob;
+}
+
+#if QGPGME_SUPPORTS_WKD_REFRESH_JOB
+std::unique_ptr<QGpgME::WKDRefreshJob> RefreshCertificatesCommand::Private::startWKDRefreshJob()
+{
+ for (const auto &key : pgpKeys) {
+ const auto userIds = key.userIDs();
+ if (std::any_of(userIds.begin(), userIds.end(), [](const auto &userId) {
+ return !userId.isRevoked() && !userId.addrSpec().empty() && userId.origin() == Key::OriginWKD;
+ })) {
+ wkdKeys.push_back(key);
+ }
+ }
+
+ std::unique_ptr<QGpgME::WKDRefreshJob> refreshJob{QGpgME::openpgp()->wkdRefreshJob()};
+ Q_ASSERT(refreshJob);
+
+ connect(refreshJob.get(), &QGpgME::WKDRefreshJob::result, q, [this](const GpgME::ImportResult &result) {
+ onWKDRefreshJobResult(result);
+ });
+ connect(refreshJob.get(), &QGpgME::Job::jobProgress, q, &Command::progress);
+ Error err;
+
+ if (!Settings{}.queryWKDsForAllUserIDs()) {
+ // check if key is eligible for WKD refresh, i.e. if any user ID has WKD as origin
+ if (wkdKeys.empty()) {
+ wkdRefreshResult = ImportResult{Error::fromCode(GPG_ERR_USER_1)};
+ QMetaObject::invokeMethod(
+ q,
+ [this]() {
+ checkFinished();
+ },
+ Qt::QueuedConnection);
+ return {};
+ }
+ err = refreshJob->start(wkdKeys);
+ } else {
+ std::vector<UserID> userIds;
+ wkdKeys = pgpKeys;
+ for (const auto &key : pgpKeys) {
+ const auto newUserIds = key.userIDs();
+ userIds.insert(userIds.end(), newUserIds.begin(), newUserIds.end());
+ }
+ err = refreshJob->start(userIds);
+ }
+
+ Q_EMIT q->info(i18nc("@info:status", "Updating key..."));
+
+ return refreshJob;
+}
+#endif
+
+namespace
+{
+static auto informationOnChanges(const ImportResult &result)
+{
+ QString text;
+
+ // if additional keys have been retrieved via WKD, then most of the below
+ // details are just a guess and may concern the additional keys instead of
+ // the refresh keys; this could only be clarified by a thorough comparison of
+ // unrefreshed and refreshed key
+
+ if (result.numUnchanged() == result.numConsidered()) {
+ // if numUnchanged < numConsidered, then it is not clear whether the refreshed key
+ // hasn't changed or whether another key retrieved via WKD hasn't changed
+ text = i18n("The certificate has not changed.");
+ } else if (result.newRevocations() > 0) {
+ // it is possible that a revoked key has been newly imported via WKD,
+ // but it is much more likely that the refreshed key was revoked
+ text = i18n("The certificate has been revoked.");
+ } else {
+ // it doesn't make much sense to list below details if the key has been revoked
+ text = i18n("The certificate has been updated.");
+
+ QStringList details;
+ if (result.newUserIDs() > 0) {
+ details.push_back(i18n("New user IDs: %1", result.newUserIDs()));
+ }
+ if (result.newSubkeys() > 0) {
+ details.push_back(i18n("New subkeys: %1", result.newSubkeys()));
+ }
+ if (result.newSignatures() > 0) {
+ details.push_back(i18n("New signatures: %1", result.newSignatures()));
+ }
+ if (!details.empty()) {
+ text += QLatin1StringView{"<br><br>"} + details.join(QLatin1String{"<br>"});
+ }
+ }
+
+ text = QLatin1StringView{"<p>"} + text + QLatin1String{"</p>"};
+ if (result.numImported() > 0) {
+ text += QLatin1StringView{"<p>"}
+ + i18np("Additionally, one new key has been retrieved.", "Additionally, %1 new keys have been retrieved.", result.numImported())
+ + QLatin1StringView{"</p>"};
+ }
+
+ return text;
+}
+
+}
+
+void RefreshCertificatesCommand::Private::onKeyserverJobResult(const ImportResult &result)
+{
+ keyserverResult = result;
+
+ if (result.error().isCanceled()) {
+ pgpJob.clear();
+ finished();
+ return;
+ }
+
+ pgpJob.clear();
+ checkFinished();
+}
+
+void RefreshCertificatesCommand::Private::onWKDRefreshJobResult(const ImportResult &result)
+{
+ wkdRefreshResult = result;
+
+ if (result.error().isCanceled()) {
+ pgpJob.clear();
+ finished();
+ return;
+ }
+
+ wkdJob.clear();
+ checkFinished();
+}
+
+void RefreshCertificatesCommand::Private::onSMIMEJobResult(const Error &error)
+{
+ smimeError = error;
+
+ if (error.isCanceled()) {
+ smimeJob.clear();
+ finished();
+ return;
+ }
+
+ smimeJob.clear();
+ checkFinished();
+}
+
+RefreshCertificatesCommand::RefreshCertificatesCommand(QAbstractItemView *v, KeyListController *p)
+ : Command(v, new Private(this, p))
+{
+}
+
+RefreshCertificatesCommand::RefreshCertificatesCommand(const Key &key)
+ : Command(key, new Private(this))
+{
+}
+
+RefreshCertificatesCommand::~RefreshCertificatesCommand() = default;
+
+void RefreshCertificatesCommand::doStart()
+{
+ d->start();
+}
+
+void RefreshCertificatesCommand::doCancel()
+{
+ d->cancel();
+}
+
+void RefreshCertificatesCommand::Private::checkFinished()
+{
+ if (smimeJob || pgpJob || wkdJob) {
+ return;
+ }
+
+ if (smimeError && smimeError->code() == GPG_ERR_CANCELED) {
+ finished();
+ return;
+ }
+
+ const auto pgpSkipped = keyserverResult.error().code() == GPG_ERR_USER_1;
+ const auto pgpKeyNotFound = keyserverResult.error().code() == GPG_ERR_NO_DATA;
+ const auto wkdSkipped = wkdRefreshResult.error().code() == GPG_ERR_USER_1;
+
+ const auto hasSmimeError = smimeError && *smimeError;
+ const auto hasPgpError = !keyserverResult.isNull() && keyserverResult.error() && !pgpSkipped && !pgpKeyNotFound;
+ const auto hasWkdError = !wkdRefreshResult.isNull() && wkdRefreshResult.error() && !wkdSkipped;
+
+ bool success = false;
+ QString text;
+
+ if (!pgpKeys.empty()) {
+ text += QLatin1StringView{"<p><strong>"} + i18nc("@info", "Result of OpenPGP certificate update from keyserver, LDAP server, or Active Directory")
+ + QLatin1String{"</strong></p>"};
+ if (hasPgpError) {
+ text += xi18nc("@info", "<para>Update failed:</para><para><message>%1</message></para>", Formatting::errorAsString(keyserverResult.error()));
+ } else if (pgpSkipped) {
+ text += xi18nc("@info", "<para>Update skipped because no OpenPGP keyserver is configured.</para>");
+ } else if (pgpKeyNotFound && pgpKeys.size() == 1) {
+ text += xi18nc("@info", "<para>The certificate was not found.</para>");
+ } else if (pgpKeys.size() > 1) {
+ success = true;
+ text += xi18ncp("@info", "<para>The certificate was updated.</para>", "<para>The certificates were updated.</para>", pgpKeys.size());
+ } else if (pgpKeys.size() == 1) {
+ success = true;
+ text += informationOnChanges(keyserverResult);
+ }
+ }
+
+ if (!wkdKeys.empty() && !wkdSkipped) {
+ text += QLatin1StringView{"<p><strong>"} + i18nc("@info", "Result of update from Web Key Directory") + QLatin1String{"</strong></p>"};
+ if (hasWkdError) {
+ text += xi18nc("@info", "<para>Update failed:</para><para><message>%1</message></para>", Formatting::errorAsString(wkdRefreshResult.error()));
+ } else {
+ success = true;
+ text += xi18ncp("@info", "<para>The certificate was updated.</para>", "<para>The certificates were updated.</para>", pgpKeys.size());
+ }
+ }
+
+ if (!smimeKeys.empty()) {
+ text += QLatin1StringView{"<p><strong>"} + i18nc("@info", "Result of S/MIME certificate update") + QLatin1String{"</strong></p>"};
+ if (hasSmimeError) {
+ text += xi18nc("@info", "<para>Update failed:</para><para><message>%1</message></para>", Formatting::errorAsString(*smimeError));
+ } else {
+ success = true;
+ text += xi18ncp("@info", "<para>The certificate was updated.</para>", "<para>The certificates were updated.</para>", smimeKeys.size());
+ }
+ }
+
+ information(text,
+ success ? i18ncp("@title:window", "Certificate Updated", "Certificates Updated", keys().size()) : i18nc("@title:window", "Update Failed"));
+ finished();
+}
+
+#undef d
+#undef q
+
+#include "moc_refreshcertificatescommand.cpp"
diff --git a/src/commands/refreshcertificatecommand.h b/src/commands/refreshcertificatescommand.h
similarity index 56%
rename from src/commands/refreshcertificatecommand.h
rename to src/commands/refreshcertificatescommand.h
index 33c70eeeb..bfeef1be6 100644
--- a/src/commands/refreshcertificatecommand.h
+++ b/src/commands/refreshcertificatescommand.h
@@ -1,33 +1,39 @@
/* -*- mode: c++; c-basic-offset:4 -*-
- commands/refreshcertificatecommand.h
+ commands/refreshcertificatescommand.h
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2022 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "command.h"
namespace Kleo
{
-class RefreshCertificateCommand : public Command
+class RefreshCertificatesCommand : public Command
{
Q_OBJECT
public:
- explicit RefreshCertificateCommand(const GpgME::Key &key);
- ~RefreshCertificateCommand() override;
+ explicit RefreshCertificatesCommand(QAbstractItemView *view, KeyListController *parent);
+ explicit RefreshCertificatesCommand(const GpgME::Key &key);
+ ~RefreshCertificatesCommand() override;
+
+ /* reimp */ static Restrictions restrictions()
+ {
+ return NeedSelection;
+ }
private:
void doStart() override;
void doCancel() override;
private:
class Private;
inline Private *d_func();
inline const Private *d_func() const;
};
}
diff --git a/src/dialogs/certificatedetailsdialog.cpp b/src/dialogs/certificatedetailsdialog.cpp
index 34a45c2dc..b141569c5 100644
--- a/src/dialogs/certificatedetailsdialog.cpp
+++ b/src/dialogs/certificatedetailsdialog.cpp
@@ -1,194 +1,194 @@
/* SPDX-FileCopyrightText: 2016 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2017 Intevation GmbH
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "certificatedetailsdialog.h"
#include "certificatedetailswidget.h"
#include "commands/changepassphrasecommand.h"
#include "commands/dumpcertificatecommand.h"
#include "commands/genrevokecommand.h"
-#include "commands/refreshcertificatecommand.h"
+#include "commands/refreshcertificatescommand.h"
#include "exportdialog.h"
#include <Libkleo/KeyHelpers>
#include <KConfigGroup>
#include <KLocalizedString>
#include <KSharedConfig>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QVBoxLayout>
#include <gpgme++/key.h>
using namespace Kleo;
class CertificateDetailsDialog::Private
{
public:
Private(CertificateDetailsDialog *qq)
: q(qq)
{
}
QPushButton *changePassphraseBtn = nullptr;
QPushButton *genRevokeBtn = nullptr;
QPushButton *exportBtn = nullptr;
QPushButton *refreshBtn = nullptr;
void refreshCertificate();
void exportClicked();
void genRevokeCert();
void changePassphrase();
void showMoreDetails();
private:
CertificateDetailsDialog *q;
};
CertificateDetailsDialog::CertificateDetailsDialog(QWidget *parent)
: QDialog(parent)
, d(new Private(this))
{
auto l = new QVBoxLayout(this);
auto w = new CertificateDetailsWidget{this};
w->layout()->setContentsMargins(0, 0, 0, 0);
l->addWidget(w);
auto bbox = new QDialogButtonBox(this);
d->refreshBtn = new QPushButton{i18nc("@action:button", "Update"), parent};
bbox->addButton(d->refreshBtn, QDialogButtonBox::ActionRole);
d->exportBtn = new QPushButton(i18nc("@action:button", "Export"), parent);
bbox->addButton(d->exportBtn, QDialogButtonBox::ActionRole);
d->genRevokeBtn = new QPushButton(i18nc("@action:button", "Generate Revocation Certificate"), parent);
d->genRevokeBtn->setToolTip(u"<html>"
% i18n("A revocation certificate is a file that serves as a \"kill switch\" to publicly "
"declare that a key shall not anymore be used. It is not possible "
"to retract such a revocation certificate once it has been published.")
% u"</html>");
bbox->addButton(d->genRevokeBtn, QDialogButtonBox::ActionRole);
d->changePassphraseBtn = new QPushButton(i18nc("@action:button", "Change Passphrase"), parent);
bbox->addButton(d->changePassphraseBtn, QDialogButtonBox::ActionRole);
auto closeBtn = bbox->addButton(QDialogButtonBox::Close);
connect(closeBtn, &QPushButton::pressed, this, &QDialog::accept);
l->addWidget(bbox);
connect(d->exportBtn, &QPushButton::clicked, this, [this]() {
d->exportClicked();
});
connect(d->refreshBtn, &QPushButton::clicked, this, [this]() {
d->refreshCertificate();
});
connect(d->genRevokeBtn, &QPushButton::clicked, this, [this]() {
d->genRevokeCert();
});
connect(d->changePassphraseBtn, &QPushButton::clicked, this, [this]() {
d->changePassphrase();
});
readConfig();
}
CertificateDetailsDialog::~CertificateDetailsDialog()
{
writeConfig();
}
void CertificateDetailsDialog::readConfig()
{
KConfigGroup dialog(KSharedConfig::openStateConfig(), QStringLiteral("CertificateDetailsDialog"));
const QSize size = dialog.readEntry("Size", QSize(730, 280));
if (size.isValid()) {
resize(size);
}
}
void CertificateDetailsDialog::writeConfig()
{
KConfigGroup dialog(KSharedConfig::openStateConfig(), QStringLiteral("CertificateDetailsDialog"));
dialog.writeEntry("Size", size());
dialog.sync();
}
namespace
{
QString title(const GpgME::Key &key)
{
switch (key.protocol()) {
case GpgME::OpenPGP:
return i18nc("@title:window", "OpenPGP Certificate");
case GpgME::CMS:
return i18nc("@title:window", "S/MIME Certificate");
default:
return {};
}
}
}
void CertificateDetailsDialog::setKey(const GpgME::Key &key)
{
setWindowTitle(title(key));
findChild<CertificateDetailsWidget *>()->setKey(key);
d->exportBtn->setVisible(!isRemoteKey(key));
d->refreshBtn->setVisible(!isRemoteKey(key));
if (key.protocol() == GpgME::Protocol::CMS) {
d->refreshBtn->setToolTip(i18nc("@info:tooltip", "Update the CRLs and do a full validation check of the certificate."));
} else {
d->refreshBtn->setToolTip(i18nc("@info:tooltip", "Update the key from external sources."));
}
d->genRevokeBtn->setVisible(key.protocol() == GpgME::Protocol::OpenPGP && key.hasSecret());
d->genRevokeBtn->setEnabled(canBeUsedForSecretKeyOperations(key));
d->changePassphraseBtn->setVisible(isSecretKeyStoredInKeyRing(key));
}
GpgME::Key CertificateDetailsDialog::key() const
{
return findChild<CertificateDetailsWidget *>()->key();
}
void CertificateDetailsDialog::Private::exportClicked()
{
QScopedPointer<ExportDialog> dlg(new ExportDialog(q));
dlg->setKey(q->key());
dlg->exec();
}
void CertificateDetailsDialog::Private::refreshCertificate()
{
- auto cmd = new Kleo::RefreshCertificateCommand(q->key());
- QObject::connect(cmd, &Kleo::RefreshCertificateCommand::finished, q, [this]() {
+ auto cmd = new Kleo::RefreshCertificatesCommand(q->key());
+ QObject::connect(cmd, &Kleo::RefreshCertificatesCommand::finished, q, [this]() {
refreshBtn->setEnabled(true);
});
refreshBtn->setEnabled(false);
cmd->start();
}
void CertificateDetailsDialog::Private::genRevokeCert()
{
auto cmd = new Kleo::Commands::GenRevokeCommand(q->key());
QObject::connect(cmd, &Kleo::Commands::GenRevokeCommand::finished, q, [this]() {
genRevokeBtn->setEnabled(true);
});
genRevokeBtn->setEnabled(false);
cmd->start();
}
void CertificateDetailsDialog::Private::changePassphrase()
{
auto cmd = new Kleo::Commands::ChangePassphraseCommand(q->key());
QObject::connect(cmd, &Kleo::Commands::ChangePassphraseCommand::finished, q, [this]() {
changePassphraseBtn->setEnabled(true);
});
changePassphraseBtn->setEnabled(false);
cmd->start();
}
#include "moc_certificatedetailsdialog.cpp"
diff --git a/src/kleopatra.rc b/src/kleopatra.rc
index e85bea7a9..bc8facc76 100644
--- a/src/kleopatra.rc
+++ b/src/kleopatra.rc
@@ -1,158 +1,162 @@
<!DOCTYPE gui >
<gui name="kleopatra" version="515" >
<MenuBar>
<Menu name="file">
<text>&amp;File</text>
<Action name="file_new_certificate"/>
<Action name="file_new_certificate_signing_request"/>
<Separator/>
<Action name="file_lookup_certificates"/>
<Action name="file_import_certificates"/>
<Separator/>
<Action name="file_export_certificates"/>
<Action name="file_export_secret_keys"/>
<Action name="file_export_paper_key"/>
<Action name="file_export_certificates_to_server"/>
<Action name="file_export_certificate_to_provider"/>
<Separator/>
<Action name="file_decrypt_verify_files"/>
<Action name="file_sign_encrypt_files"/>
<Action name="file_sign_encrypt_folder"/>
<Separator/>
<Action name="file_checksum_create_files"/>
<Action name="file_checksum_verify_files"/>
<Separator/>
<Action name="quit" />
</Menu>
<Menu name="view">
<text>&amp;View</text>
<Action name="view_redisplay"/>
<Separator/>
<Action name="view_stop_operations"/>
<Action name="view_certificate_details"/>
<Separator/>
<Action name="window_view_hierarchical"/>
<Separator/>
<Action name="window_expand_all"/>
<Action name="window_collapse_all"/>
<Separator/>
<Action name="view_certificate_overview"/>
<Action name="pad_view"/>
<Action name="manage_smartcard"/>
</Menu>
<Menu name="certMenu">
<text>&amp;Certificates</text>
+ <Action name="certificates_refresh"/>
+ <Separator/>
<Action name="certificates_change_owner_trust"/>
<Action name="certificates_trust_root"/>
<Action name="certificates_distrust_root"/>
<Separator/>
<Action name="certificates_certify_certificate"/>
<Action name="certificates_revoke_certification"/>
<Separator/>
<Action name="certificates_change_expiry"/>
<Action name="certificates_change_passphrase"/>
<Action name="certificates_add_userid"/>
<Separator/>
<Action name="certificates_revoke"/>
<Action name="certificates_delete"/>
<Separator/>
<Action name="certificates_create_group"/>
</Menu>
<Menu name="tools">
<text>&amp;Tools</text>
<Action name="tools_start_kwatchgnupg"/>
<Separator/>
<Action name="tools_refresh_x509_certificates"/>
<Action name="tools_refresh_openpgp_certificates"/>
<Separator/>
<Action name="clipboard_menu"/>
<Separator/>
<Action name="crl_import_crl"/>
<Separator/>
<Action name="crl_clear_crl_cache"/>
<Action name="crl_dump_crl_cache"/>
<Separator/>
<Action name="tools_restart_backend"/>
</Menu>
<Menu name="settings">
<text>&amp;Settings</text>
<Action name="settings_self_test"/>
<Action name="configure_groups" append="configure_merge"/>
</Menu>
<Menu name="window" append="settings_merge">
<text>&amp;Window</text>
<Action name="window_rename_tab"/>
<Separator/>
<Action name="window_new_tab"/>
<Action name="window_duplicate_tab"/>
<Action name="window_close_tab"/>
<Separator/>
<Action name="window_move_tab_left"/>
<Action name="window_move_tab_right"/>
</Menu>
<Menu name="help">
<text>&amp;Help</text>
<Action name="help_doc_quickguide"/>
<Action name="help_doc_symenc"/>
<Action name="help_doc_groups"/>
<Action name="help_doc_gpgol"/>
<Menu name="help_more">
<text>&amp;More documentation</text>
<Action name="help_doc_cert_management"/>
<Action name="help_doc_smartcard"/>
<Action name="help_doc_gnupg"/>
</Menu>
<Separator/>
<Action name="help_doc_compendium"/>
<Action name="help_doc_approval_manual"/>
<Action name="help_doc_vsa10573"/>
<Action name="help_doc_vsa10584"/>
<Separator/>
<Action name="help_check_updates"/>
</Menu>
</MenuBar>
<ToolBar fullWidth="false" name="mainToolBar" iconText="TextUnderIcon">
<text>Main Toolbar</text>
<Action name="file_sign_encrypt_files"/>
<Action name="file_decrypt_verify_files"/>
<Separator/>
<Action name="file_import_certificates"/>
<Action name="file_export_certificates"/>
<Action name="certificates_certify_certificate"/>
<Action name="file_lookup_certificates"/>
<Separator/>
<Action name="view_certificate_overview"/>
<Action name="pad_view"/>
<Action name="manage_smartcard"/>
<Separator/>
<Action name="configure_groups_toolbar"/>
</ToolBar>
<Menu name="listview_popup">
<text>&amp;Certificates</text>
+ <Action name="certificates_refresh"/>
+ <Separator/>
<Action name="certificates_certify_certificate"/>
<Action name="certificates_revoke_certification"/>
<Action name="certificates_trust_root"/>
<Action name="certificates_distrust_root"/>
<Action name="certificates_change_owner_trust"/>
<Separator/>
<Action name="certificates_change_expiry"/>
<Action name="certificates_change_passphrase"/>
<Action name="certificates_add_userid"/>
<Separator/>
<Action name="certificates_revoke"/>
<Action name="certificates_delete"/>
<Separator/>
<Action name="certificates_create_group"/>
<Separator/>
<Action name="file_export_certificates"/>
<Action name="file_export_secret_keys"/>
<Action name="file_export_paper_key"/>
<Action name="file_export_certificates_to_server"/>
<Action name="file_export_certificate_to_provider"/>
<Separator/>
<Action name="view_certificate_details"/>
</Menu>
</gui>
diff --git a/src/view/keylistcontroller.cpp b/src/view/keylistcontroller.cpp
index 8f38d181a..cc686cdcc 100644
--- a/src/view/keylistcontroller.cpp
+++ b/src/view/keylistcontroller.cpp
@@ -1,1021 +1,1033 @@
/* -*- mode: c++; c-basic-offset:4 -*-
view/keylistcontroller.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2022 Felix Tiede
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-kleopatra.h>
#include "keylistcontroller.h"
#include "tabwidget.h"
#include <smartcard/readerstatus.h>
#include <utils/action_data.h>
#include "commands/exportcertificatecommand.h"
#include "commands/exportopenpgpcertstoservercommand.h"
#include "kleopatra_debug.h"
#include "tooltippreferences.h"
#include <settings.h>
#ifdef MAILAKONADI_ENABLED
#include "commands/exportopenpgpcerttoprovidercommand.h"
#endif // MAILAKONADI_ENABLED
#include "commands/adduseridcommand.h"
#include "commands/certifycertificatecommand.h"
#include "commands/changeexpirycommand.h"
#include "commands/changeownertrustcommand.h"
#include "commands/changepassphrasecommand.h"
#include "commands/changeroottrustcommand.h"
#include "commands/checksumcreatefilescommand.h"
#include "commands/checksumverifyfilescommand.h"
#include "commands/clearcrlcachecommand.h"
#include "commands/creategroupcommand.h"
#include "commands/decryptverifyfilescommand.h"
#include "commands/deletecertificatescommand.h"
#include "commands/detailscommand.h"
#include "commands/dumpcertificatecommand.h"
#include "commands/dumpcrlcachecommand.h"
#include "commands/exportpaperkeycommand.h"
#include "commands/exportsecretkeycommand.h"
#include "commands/importcertificatefromfilecommand.h"
#include "commands/importcrlcommand.h"
#include "commands/lookupcertificatescommand.h"
#include "commands/newcertificatesigningrequestcommand.h"
#include "commands/newopenpgpcertificatecommand.h"
+#include "commands/refreshcertificatescommand.h"
#include "commands/refreshopenpgpcertscommand.h"
#include "commands/refreshx509certscommand.h"
#include "commands/reloadkeyscommand.h"
#include "commands/revokecertificationcommand.h"
#include "commands/revokekeycommand.h"
#include "commands/signencryptfilescommand.h"
#include "commands/signencryptfoldercommand.h"
#include <Libkleo/Algorithm>
#include <Libkleo/Formatting>
#include <Libkleo/KeyCache>
#include <Libkleo/KeyListModel>
#include <gpgme++/key.h>
#include <KActionCollection>
#include <KLocalizedString>
#include <QAbstractItemView>
#include <QAction>
#include <QItemSelectionModel>
#include <QPointer>
#include <algorithm>
#include <iterator>
using namespace Kleo;
using namespace Kleo::Commands;
using namespace Kleo::SmartCard;
using namespace GpgME;
namespace ranges = std::ranges;
class KeyListController::Private
{
friend class ::Kleo::KeyListController;
KeyListController *const q;
public:
explicit Private(KeyListController *qq);
~Private();
void connectView(QAbstractItemView *view);
void connectCommand(Command *cmd);
void connectTabWidget();
void disconnectTabWidget();
void addCommand(Command *cmd)
{
connectCommand(cmd);
commands.insert(ranges::lower_bound(commands, cmd), cmd);
}
void addView(QAbstractItemView *view)
{
connectView(view);
views.insert(ranges::lower_bound(views, view), view);
}
void removeView(QAbstractItemView *view)
{
view->disconnect(q);
view->selectionModel()->disconnect(q);
std::erase(views, view);
}
public:
void slotDestroyed(QObject *o)
{
qCDebug(KLEOPATRA_LOG) << (void *)o;
std::erase(views, o);
std::erase(commands, o);
}
void slotDoubleClicked(const QModelIndex &idx);
void slotActivated(const QModelIndex &idx);
void slotSelectionChanged(const QItemSelection &old, const QItemSelection &new_);
void slotContextMenu(const QPoint &pos);
void slotCommandFinished();
void slotActionTriggered(QAction *action);
void slotCurrentViewChanged(QAbstractItemView *view)
{
if (view && !ranges::binary_search(views, view)) {
qCDebug(KLEOPATRA_LOG) << "you need to register view" << view << "before trying to set it as the current view!";
addView(view);
}
currentView = view;
q->enableDisableActions(view ? view->selectionModel() : nullptr);
}
private:
int toolTipOptions() const;
private:
static Command::Restrictions calculateRestrictionsMask(const QItemSelectionModel *sm);
private:
struct action_item {
QPointer<QAction> action;
Command::Restrictions restrictions;
Command *(*createCommand)(QAbstractItemView *, KeyListController *);
};
std::vector<action_item> actions;
std::vector<QAbstractItemView *> views;
std::vector<Command *> commands;
QPointer<QWidget> parentWidget;
QPointer<TabWidget> tabWidget;
QPointer<QAbstractItemView> currentView;
QPointer<AbstractKeyListModel> flatModel, hierarchicalModel;
std::vector<QMetaObject::Connection> m_connections;
};
KeyListController::Private::Private(KeyListController *qq)
: q(qq)
, actions()
, views()
, commands()
, parentWidget()
, tabWidget()
, flatModel()
, hierarchicalModel()
{
}
KeyListController::Private::~Private()
{
}
KeyListController::KeyListController(QObject *p)
: QObject(p)
, d(new Private(this))
{
}
KeyListController::~KeyListController()
{
}
void KeyListController::addView(QAbstractItemView *view)
{
if (!view || ranges::binary_search(d->views, view)) {
return;
}
d->addView(view);
}
void KeyListController::removeView(QAbstractItemView *view)
{
if (!view || !ranges::binary_search(d->views, view)) {
return;
}
d->removeView(view);
}
void KeyListController::setCurrentView(QAbstractItemView *view)
{
d->slotCurrentViewChanged(view);
}
std::vector<QAbstractItemView *> KeyListController::views() const
{
return d->views;
}
void KeyListController::setFlatModel(AbstractKeyListModel *model)
{
if (model == d->flatModel) {
return;
}
d->flatModel = model;
if (model) {
model->setToolTipOptions(d->toolTipOptions());
}
}
void KeyListController::setHierarchicalModel(AbstractKeyListModel *model)
{
if (model == d->hierarchicalModel) {
return;
}
d->hierarchicalModel = model;
if (model) {
model->setToolTipOptions(d->toolTipOptions());
}
}
void KeyListController::setTabWidget(TabWidget *tabWidget)
{
if (tabWidget == d->tabWidget) {
return;
}
d->disconnectTabWidget();
d->tabWidget = tabWidget;
d->connectTabWidget();
d->slotCurrentViewChanged(tabWidget ? tabWidget->currentView() : nullptr);
}
void KeyListController::setParentWidget(QWidget *parent)
{
d->parentWidget = parent;
}
QWidget *KeyListController::parentWidget() const
{
return d->parentWidget;
}
void KeyListController::Private::connectTabWidget()
{
if (!tabWidget) {
return;
}
const auto views = tabWidget->views();
ranges::for_each(views, [this](QAbstractItemView *view) {
addView(view);
});
m_connections.reserve(3);
m_connections.push_back(connect(tabWidget, &TabWidget::viewAdded, q, &KeyListController::addView));
m_connections.push_back(connect(tabWidget, &TabWidget::viewAboutToBeRemoved, q, &KeyListController::removeView));
m_connections.push_back(connect(tabWidget, &TabWidget::currentViewChanged, q, [this](QAbstractItemView *view) {
slotCurrentViewChanged(view);
}));
}
void KeyListController::Private::disconnectTabWidget()
{
if (!tabWidget) {
return;
}
for (const auto &connection : m_connections) {
disconnect(connection);
}
m_connections.clear();
const auto views = tabWidget->views();
ranges::for_each(views, [this](QAbstractItemView *view) {
removeView(view);
});
}
AbstractKeyListModel *KeyListController::flatModel() const
{
return d->flatModel;
}
AbstractKeyListModel *KeyListController::hierarchicalModel() const
{
return d->hierarchicalModel;
}
QAbstractItemView *KeyListController::currentView() const
{
return d->currentView;
}
TabWidget *KeyListController::tabWidget() const
{
return d->tabWidget;
}
void KeyListController::createActions(KActionCollection *coll)
{
const std::vector<action_data> common_and_openpgp_action_data = {
// File menu
{
"file_new_certificate",
i18n("New OpenPGP Key Pair..."),
i18n("Create a new OpenPGP certificate"),
"view-certificate-add",
nullptr,
nullptr,
QStringLiteral("Ctrl+N"),
},
{
"file_export_certificates",
i18n("Export..."),
i18n("Export the selected certificate (public key) to a file"),
"view-certificate-export",
nullptr,
nullptr,
QStringLiteral("Ctrl+E"),
},
{
"file_export_certificates_to_server",
i18n("Publish on Server..."),
i18n("Publish the selected certificate (public key) on a public keyserver"),
"view-certificate-export-server",
nullptr,
nullptr,
QStringLiteral("Ctrl+Shift+E"),
},
#ifdef MAILAKONADI_ENABLED
{
"file_export_certificate_to_provider",
i18n("Publish at Mail Provider..."),
i18n("Publish the selected certificate (public key) at mail provider's Web Key Directory if offered"),
"view-certificate-export",
nullptr,
nullptr,
QString(),
},
#endif // MAILAKONADI_ENABLED
{
"file_export_secret_keys",
i18n("Backup Secret Keys..."),
QString(),
"view-certificate-export-secret",
nullptr,
nullptr,
QString(),
},
{
"file_export_paper_key",
i18n("Print Secret Key..."),
QString(),
"document-print",
nullptr,
nullptr,
QString(),
},
{
"file_lookup_certificates",
i18n("Lookup on Server..."),
i18n("Search for certificates online using a public keyserver"),
"edit-find",
nullptr,
nullptr,
QStringLiteral("Shift+Ctrl+I"),
},
{
"file_import_certificates",
i18n("Import..."),
i18n("Import a certificate from a file"),
"view-certificate-import",
nullptr,
nullptr,
QStringLiteral("Ctrl+I"),
},
{
"file_decrypt_verify_files",
i18n("Decrypt/Verify..."),
i18n("Decrypt and/or verify files"),
"document-edit-decrypt-verify",
nullptr,
nullptr,
QString(),
},
{
"file_sign_encrypt_files",
i18n("Sign/Encrypt..."),
i18n("Encrypt and/or sign files"),
"document-edit-sign-encrypt",
nullptr,
nullptr,
QString(),
},
{
"file_sign_encrypt_folder",
i18n("Sign/Encrypt Folder..."),
i18n("Encrypt and/or sign folders"),
"folder-edit-sign-encrypt-symbolic",
nullptr,
nullptr,
QString(),
},
{
"file_checksum_create_files",
i18n("Create Checksum Files..."),
QString(),
nullptr /*"document-checksum-create"*/,
nullptr,
nullptr,
QString(),
},
{
"file_checksum_verify_files",
i18n("Verify Checksum Files..."),
QString(),
nullptr /*"document-checksum-verify"*/,
nullptr,
nullptr,
QString(),
},
// View menu
{
"view_redisplay",
i18n("Redisplay"),
QString(),
"view-refresh",
nullptr,
nullptr,
QStringLiteral("F5"),
},
{
"view_stop_operations",
i18n("Stop Operation"),
QString(),
"process-stop",
this,
[this](bool) {
cancelCommands();
},
QStringLiteral("Escape"),
RegularQAction,
Disabled,
},
{
"view_certificate_details",
i18n("Details"),
QString(),
"dialog-information",
nullptr,
nullptr,
QString(),
},
// Certificate menu
{
"certificates_revoke",
i18n("Revoke Certificate..."),
i18n("Revoke the selected OpenPGP certificate"),
"view-certificate-revoke",
nullptr,
nullptr,
{},
},
{
"certificates_delete",
i18n("Delete"),
i18n("Delete selected certificates"),
"edit-delete",
nullptr,
nullptr,
QStringLiteral("Delete"),
},
+ {
+ "certificates_refresh",
+ i18n("Update Certificates"),
+ i18n("Update selected certificates"),
+ "view-refresh",
+ nullptr,
+ nullptr,
+ QString(),
+ },
{
"certificates_certify_certificate",
i18n("Certify..."),
i18n("Certify the validity of the selected certificate"),
"view-certificate-sign",
nullptr,
nullptr,
QString(),
},
{
"certificates_revoke_certification",
i18n("Revoke Certification..."),
i18n("Revoke the certification of the selected certificate"),
"view-certificate-revoke",
nullptr,
nullptr,
QString(),
},
{
"certificates_change_expiry",
i18n("Change End of Validity Period..."),
QString(),
nullptr,
nullptr,
nullptr,
QString(),
},
{
"certificates_change_owner_trust",
i18nc("@action:inmenu", "Change Certification Power..."),
i18nc("@info:tooltip", "Grant or revoke the certification power of the selected certificate"),
nullptr,
nullptr,
nullptr,
QString(),
},
{
"certificates_change_passphrase",
i18n("Change Passphrase..."),
QString(),
nullptr,
nullptr,
nullptr,
QString(),
},
{
"certificates_add_userid",
i18n("Add User ID..."),
QString(),
nullptr,
nullptr,
nullptr,
QString(),
},
{
"certificates_create_group",
i18nc("@action:inmenu", "Create Group..."),
i18nc("@info:tooltip", "Create a group from the selected certificates"),
"resource-group-new",
nullptr,
nullptr,
QString(),
},
// Tools menu
{
"tools_refresh_openpgp_certificates",
i18n("Refresh OpenPGP Certificates"),
QString(),
"view-refresh",
nullptr,
nullptr,
QString(),
},
// Window menu
// (come from TabWidget)
// Help menu
// (come from MainWindow)
};
static const action_data cms_create_csr_action_data = {
"file_new_certificate_signing_request",
i18n("New S/MIME Certification Request..."),
i18n("Create a new S/MIME certificate signing request (CSR)"),
"view-certificate-add",
nullptr,
nullptr,
{},
};
static const std::vector<action_data> cms_action_data = {
// Certificate menu
{
"certificates_trust_root",
i18n("Trust Root Certificate"),
QString(),
nullptr,
nullptr,
nullptr,
QString(),
},
{
"certificates_distrust_root",
i18n("Distrust Root Certificate"),
QString(),
nullptr,
nullptr,
nullptr,
QString(),
},
{
"certificates_dump_certificate",
i18n("Technical Details"),
QString(),
nullptr,
nullptr,
nullptr,
QString(),
},
// Tools menu
{
"tools_refresh_x509_certificates",
i18n("Refresh S/MIME Certificates"),
QString(),
"view-refresh",
nullptr,
nullptr,
QString(),
},
{
"crl_clear_crl_cache",
i18n("Clear CRL Cache"),
QString(),
nullptr,
nullptr,
nullptr,
QString(),
},
{
"crl_dump_crl_cache",
i18n("Dump CRL Cache"),
QString(),
nullptr,
nullptr,
nullptr,
QString(),
},
{
"crl_import_crl",
i18n("Import CRL From File..."),
QString(),
nullptr,
nullptr,
nullptr,
QString(),
},
};
std::vector<action_data> action_data = common_and_openpgp_action_data;
if (const Kleo::Settings settings{}; settings.cmsEnabled()) {
if (settings.cmsCertificateCreationAllowed()) {
action_data.push_back(cms_create_csr_action_data);
}
action_data.reserve(action_data.size() + cms_action_data.size());
ranges::copy(cms_action_data, std::back_inserter(action_data));
}
make_actions_from_data(action_data, coll);
if (QAction *action = coll->action(QStringLiteral("view_stop_operations"))) {
connect(this, &KeyListController::commandsExecuting, action, &QAction::setEnabled);
}
// ### somehow make this better...
registerActionForCommand<NewOpenPGPCertificateCommand>(coll->action(QStringLiteral("file_new_certificate")));
registerActionForCommand<NewCertificateSigningRequestCommand>(coll->action(QStringLiteral("file_new_certificate_signing_request")));
//---
registerActionForCommand<LookupCertificatesCommand>(coll->action(QStringLiteral("file_lookup_certificates")));
registerActionForCommand<ImportCertificateFromFileCommand>(coll->action(QStringLiteral("file_import_certificates")));
//---
registerActionForCommand<ExportCertificateCommand>(coll->action(QStringLiteral("file_export_certificates")));
registerActionForCommand<ExportSecretKeyCommand>(coll->action(QStringLiteral("file_export_secret_keys")));
registerActionForCommand<ExportPaperKeyCommand>(coll->action(QStringLiteral("file_export_paper_key")));
registerActionForCommand<ExportOpenPGPCertsToServerCommand>(coll->action(QStringLiteral("file_export_certificates_to_server")));
#ifdef MAILAKONADI_ENABLED
registerActionForCommand<ExportOpenPGPCertToProviderCommand>(coll->action(QStringLiteral("file_export_certificate_to_provider")));
#endif // MAILAKONADI_ENABLED
//---
registerActionForCommand<DecryptVerifyFilesCommand>(coll->action(QStringLiteral("file_decrypt_verify_files")));
registerActionForCommand<SignEncryptFilesCommand>(coll->action(QStringLiteral("file_sign_encrypt_files")));
registerActionForCommand<SignEncryptFolderCommand>(coll->action(QStringLiteral("file_sign_encrypt_folder")));
//---
registerActionForCommand<ChecksumCreateFilesCommand>(coll->action(QStringLiteral("file_checksum_create_files")));
registerActionForCommand<ChecksumVerifyFilesCommand>(coll->action(QStringLiteral("file_checksum_verify_files")));
registerActionForCommand<ReloadKeysCommand>(coll->action(QStringLiteral("view_redisplay")));
// coll->action( "view_stop_operations" ) <-- already dealt with in make_actions_from_data()
registerActionForCommand<DetailsCommand>(coll->action(QStringLiteral("view_certificate_details")));
registerActionForCommand<ChangeOwnerTrustCommand>(coll->action(QStringLiteral("certificates_change_owner_trust")));
registerActionForCommand<TrustRootCommand>(coll->action(QStringLiteral("certificates_trust_root")));
registerActionForCommand<DistrustRootCommand>(coll->action(QStringLiteral("certificates_distrust_root")));
//---
registerActionForCommand<CertifyCertificateCommand>(coll->action(QStringLiteral("certificates_certify_certificate")));
if (RevokeCertificationCommand::isSupported()) {
registerActionForCommand<RevokeCertificationCommand>(coll->action(QStringLiteral("certificates_revoke_certification")));
}
//---
registerActionForCommand<ChangeExpiryCommand>(coll->action(QStringLiteral("certificates_change_expiry")));
registerActionForCommand<ChangePassphraseCommand>(coll->action(QStringLiteral("certificates_change_passphrase")));
registerActionForCommand<AddUserIDCommand>(coll->action(QStringLiteral("certificates_add_userid")));
registerActionForCommand<CreateGroupCommand>(coll->action(QStringLiteral("certificates_create_group")));
//---
registerActionForCommand<RevokeKeyCommand>(coll->action(QStringLiteral("certificates_revoke")));
registerActionForCommand<DeleteCertificatesCommand>(coll->action(QStringLiteral("certificates_delete")));
//---
+ registerActionForCommand<RefreshCertificatesCommand>(coll->action(QStringLiteral("certificates_refresh")));
+ //---
registerActionForCommand<DumpCertificateCommand>(coll->action(QStringLiteral("certificates_dump_certificate")));
registerActionForCommand<RefreshX509CertsCommand>(coll->action(QStringLiteral("tools_refresh_x509_certificates")));
registerActionForCommand<RefreshOpenPGPCertsCommand>(coll->action(QStringLiteral("tools_refresh_openpgp_certificates")));
//---
registerActionForCommand<ImportCrlCommand>(coll->action(QStringLiteral("crl_import_crl")));
//---
registerActionForCommand<ClearCrlCacheCommand>(coll->action(QStringLiteral("crl_clear_crl_cache")));
registerActionForCommand<DumpCrlCacheCommand>(coll->action(QStringLiteral("crl_dump_crl_cache")));
enableDisableActions(nullptr);
}
void KeyListController::registerAction(QAction *action, Command::Restrictions restrictions, Command *(*create)(QAbstractItemView *, KeyListController *))
{
if (!action) {
return;
}
Q_ASSERT(!action->isCheckable()); // can be added later, for now, disallow
const Private::action_item ai = {action, restrictions, create};
connect(action, &QAction::triggered, this, [this, action]() {
d->slotActionTriggered(action);
});
d->actions.push_back(ai);
}
void KeyListController::registerCommand(Command *cmd)
{
if (!cmd || ranges::binary_search(d->commands, cmd)) {
return;
}
d->addCommand(cmd);
qCDebug(KLEOPATRA_LOG) << (void *)cmd;
if (d->commands.size() == 1) {
Q_EMIT commandsExecuting(true);
}
}
bool KeyListController::hasRunningCommands() const
{
return !d->commands.empty();
}
bool KeyListController::shutdownWarningRequired() const
{
return ranges::any_of(d->commands, std::mem_fn(&Command::warnWhenRunningAtShutdown));
}
// slot
void KeyListController::cancelCommands()
{
ranges::for_each(d->commands, std::mem_fn(&Command::cancel));
}
void KeyListController::Private::connectView(QAbstractItemView *view)
{
connect(view, &QObject::destroyed, q, [this](QObject *obj) {
slotDestroyed(obj);
});
connect(view, &QAbstractItemView::doubleClicked, q, [this](const QModelIndex &index) {
slotDoubleClicked(index);
});
connect(view, &QAbstractItemView::activated, q, [this](const QModelIndex &index) {
slotActivated(index);
});
connect(view->selectionModel(), &QItemSelectionModel::selectionChanged, q, [this](const QItemSelection &oldSel, const QItemSelection &newSel) {
slotSelectionChanged(oldSel, newSel);
});
view->setContextMenuPolicy(Qt::CustomContextMenu);
connect(view, &QWidget::customContextMenuRequested, q, [this](const QPoint &pos) {
slotContextMenu(pos);
});
}
void KeyListController::Private::connectCommand(Command *cmd)
{
if (!cmd) {
return;
}
connect(cmd, &QObject::destroyed, q, [this](QObject *obj) {
slotDestroyed(obj);
});
connect(cmd, &Command::finished, q, [this] {
slotCommandFinished();
});
// connect( cmd, SIGNAL(canceled()), q, SLOT(slotCommandCanceled()) );
connect(cmd, &Command::progress, q, &KeyListController::progress);
}
void KeyListController::Private::slotDoubleClicked(const QModelIndex &idx)
{
QAbstractItemView *const view = qobject_cast<QAbstractItemView *>(q->sender());
if (!view || !ranges::binary_search(views, view)) {
return;
}
if (const auto *const keyListModel = dynamic_cast<KeyListModelInterface *>(view->model())) {
DetailsCommand *const c = new DetailsCommand{keyListModel->key(idx)};
c->setParentWidget(parentWidget ? parentWidget : view);
c->start();
}
}
void KeyListController::Private::slotActivated(const QModelIndex &idx)
{
Q_UNUSED(idx)
QAbstractItemView *const view = qobject_cast<QAbstractItemView *>(q->sender());
if (!view || !ranges::binary_search(views, view)) {
return;
}
}
void KeyListController::Private::slotSelectionChanged(const QItemSelection &old, const QItemSelection &new_)
{
Q_UNUSED(old)
Q_UNUSED(new_)
const QItemSelectionModel *const sm = qobject_cast<QItemSelectionModel *>(q->sender());
if (!sm) {
return;
}
q->enableDisableActions(sm);
}
void KeyListController::Private::slotContextMenu(const QPoint &p)
{
QAbstractItemView *const view = qobject_cast<QAbstractItemView *>(q->sender());
if (view && ranges::binary_search(views, view)) {
Q_EMIT q->contextMenuRequested(view, view->viewport()->mapToGlobal(p));
} else {
qCDebug(KLEOPATRA_LOG) << "sender is not a QAbstractItemView*!";
}
}
void KeyListController::Private::slotCommandFinished()
{
Command *const cmd = qobject_cast<Command *>(q->sender());
if (!cmd || !ranges::binary_search(commands, cmd)) {
return;
}
qCDebug(KLEOPATRA_LOG) << (void *)cmd;
if (commands.size() == 1) {
Q_EMIT q->commandsExecuting(false);
}
}
void KeyListController::enableDisableActions(const QItemSelectionModel *sm) const
{
const Command::Restrictions restrictionsMask = d->calculateRestrictionsMask(sm);
for (const Private::action_item &ai : std::as_const(d->actions))
if (ai.action) {
ai.action->setEnabled(ai.restrictions == (ai.restrictions & restrictionsMask));
}
}
static bool all_secret_are_not_owner_trust_ultimate(const std::vector<Key> &keys)
{
for (const Key &key : keys)
if (key.hasSecret() && key.ownerTrust() == Key::Ultimate) {
return false;
}
return true;
}
Command::Restrictions find_root_restrictions(const std::vector<Key> &keys)
{
bool trusted = false, untrusted = false;
for (const Key &key : keys)
if (key.isRoot())
if (key.userID(0).validity() == UserID::Ultimate) {
trusted = true;
} else {
untrusted = true;
}
else {
return Command::NoRestriction;
}
if (trusted)
if (untrusted) {
return Command::NoRestriction;
} else {
return Command::MustBeTrustedRoot;
}
else if (untrusted) {
return Command::MustBeUntrustedRoot;
} else {
return Command::NoRestriction;
}
}
static bool secretSubkeyDataAvailable(const Subkey &subkey)
{
return subkey.isSecret() && !subkey.isCardKey();
};
Command::Restrictions KeyListController::Private::calculateRestrictionsMask(const QItemSelectionModel *sm)
{
if (!sm) {
return Command::NoRestriction;
}
const KeyListModelInterface *const m = dynamic_cast<const KeyListModelInterface *>(sm->model());
if (!m) {
return Command::NoRestriction;
}
const std::vector<Key> keys = m->keys(sm->selectedRows());
if (keys.empty()) {
return Command::NoRestriction;
}
Command::Restrictions result = Command::NeedSelection;
if (keys.size() == 1) {
result |= Command::OnlyOneKey;
}
// we need to check the primary subkey because Key::hasSecret() is also true if just the secret key stub of an offline key is available
const auto primaryKeyCanBeUsedForSecretKeyOperations = [](const auto &k) {
return k.subkey(0).isSecret();
};
if (ranges::all_of(keys, primaryKeyCanBeUsedForSecretKeyOperations)) {
result |= Command::NeedSecretKey;
}
if (ranges::all_of(keys, [](const auto &k) {
return ranges::any_of(k.subkeys(), &secretSubkeyDataAvailable);
})) {
result |= Command::NeedSecretSubkeyData;
}
if ((result & Command::NeedSecretSubkeyData) && ranges::all_of(keys, [](const auto &k) {
return secretSubkeyDataAvailable(k.subkey(0));
})) {
result |= Command::NeedSecretPrimaryKeyData;
}
if (ranges::all_of(keys, [](const Key &key) {
return key.protocol() == OpenPGP;
})) {
result |= Command::MustBeOpenPGP;
} else if (ranges::all_of(keys, [](const Key &key) {
return key.protocol() == CMS;
})) {
result |= Command::MustBeCMS;
}
if (ranges::all_of(keys, [](const auto &key) {
return !key.isBad();
})) {
result |= Command::MustBeValid;
}
if (all_secret_are_not_owner_trust_ultimate(keys)) {
result |= Command::MayOnlyBeSecretKeyIfOwnerTrustIsNotYetUltimate;
}
result |= find_root_restrictions(keys);
if (const ReaderStatus *rs = ReaderStatus::instance()) {
if (!rs->firstCardWithNullPin().empty()) {
result |= Command::AnyCardHasNullPin;
}
}
return result;
}
void KeyListController::Private::slotActionTriggered(QAction *sender)
{
const auto it = ranges::find_if(actions, [sender](const action_item &item) {
return item.action == sender;
});
if (it != actions.end())
if (Command *const c = it->createCommand(this->currentView, q)) {
if (parentWidget) {
c->setParentWidget(parentWidget);
}
c->start();
} else
qCDebug(KLEOPATRA_LOG) << "createCommand() == NULL for action(?) \"" << qPrintable(sender->objectName()) << "\"";
else {
qCDebug(KLEOPATRA_LOG) << "I don't know anything about action(?) \"%s\"", qPrintable(sender->objectName());
}
}
int KeyListController::Private::toolTipOptions() const
{
using namespace Kleo::Formatting;
static const int validityFlags = Validity | Issuer | ExpiryDates | CertificateUsage;
static const int ownerFlags = Subject | UserIDs | OwnerTrust;
static const int detailsFlags = StorageLocation | CertificateType | SerialNumber | Fingerprint;
const TooltipPreferences prefs;
int flags = KeyID;
flags |= prefs.showValidity() ? validityFlags : 0;
flags |= prefs.showOwnerInformation() ? ownerFlags : 0;
flags |= prefs.showCertificateDetails() ? detailsFlags : 0;
return flags;
}
void KeyListController::updateConfig()
{
const int opts = d->toolTipOptions();
if (d->flatModel) {
d->flatModel->setToolTipOptions(opts);
}
if (d->hierarchicalModel) {
d->hierarchicalModel->setToolTipOptions(opts);
}
}
#include "moc_keylistcontroller.cpp"

File Metadata

Mime Type
text/x-diff
Expires
Sat, Jan 24, 11:13 PM (10 h, 5 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
cf/a2/9fd9b8cb0846f1111fa384a6d895

Event Timeline