Page MenuHome GnuPG

No OneTemporary

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 91c79bc2f..922890d52 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,654 +1,656 @@
# 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/winapi-helpers.cpp utils/winapi-helpers.h
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/addadskcommand.cpp
commands/addadskcommand.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/certificatetocardcommand.cpp
commands/certificatetocardcommand.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/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/copytosmartcarddialog.cpp
dialogs/copytosmartcarddialog.h
dialogs/debugdialog.cpp
dialogs/debugdialog.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/revokerswidget.cpp
dialogs/revokerswidget.h
dialogs/selftestdialog.cpp
dialogs/selftestdialog.h
dialogs/setinitialpindialog.cpp
dialogs/setinitialpindialog.h
+ dialogs/smartcardwindow.cpp
+ dialogs/smartcardwindow.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
kleopatra_options.h
)
if(WIN32)
configure_file (versioninfo.rc.in versioninfo.rc)
configure_file (kleopatra.w32-manifest.in kleopatra.w32-manifest)
set(_kleopatra_SRCS
${CMAKE_CURRENT_BINARY_DIR}/kleopatra.w32-manifest
${CMAKE_CURRENT_BINARY_DIR}/versioninfo.rc
conf/kmessageboxdontaskagainstorage.cpp
conf/kmessageboxdontaskagainstorage.h
${_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
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/dialogs/smartcardwindow.cpp b/src/dialogs/smartcardwindow.cpp
new file mode 100644
index 000000000..7d385c833
--- /dev/null
+++ b/src/dialogs/smartcardwindow.cpp
@@ -0,0 +1,88 @@
+/* dialogs/smartcardwindow.cpp
+
+ This file is part of Kleopatra, the KDE keymanager
+ SPDX-FileCopyrightText: 2024 g10 Code GmbH
+ SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
+
+ SPDX-License-Identifier: GPL-2.0-or-later
+*/
+
+#include "smartcardwindow.h"
+
+#include <kleopatraapplication.h>
+#include <mainwindow.h>
+
+#include <smartcard/readerstatus.h>
+#include <view/smartcardwidget.h>
+
+#include <KConfigGroup>
+#include <KLocalizedString>
+#include <KSharedConfig>
+#include <KStandardAction>
+
+#include <QVBoxLayout>
+
+using namespace Kleo;
+using namespace Kleo::SmartCard;
+
+class SmartCardWindow::Private
+{
+ friend class ::SmartCardWindow;
+ SmartCardWindow *const q;
+
+public:
+ Private(SmartCardWindow *qq)
+ : q(qq)
+ {
+ }
+
+private:
+ void saveLayout();
+ void restoreLayout(const QSize &defaultSize = {});
+
+private:
+ SmartCardWidget *smartCardWidget = nullptr;
+};
+
+void SmartCardWindow::Private::saveLayout()
+{
+ KConfigGroup configGroup(KSharedConfig::openStateConfig(), QLatin1StringView("SmartCardWindow"));
+ configGroup.writeEntry("Size", q->size());
+ configGroup.sync();
+}
+
+void SmartCardWindow::Private::restoreLayout(const QSize &defaultSize)
+{
+ const KConfigGroup configGroup(KSharedConfig::openStateConfig(), QLatin1StringView("SmartCardWindow"));
+ const QSize size = configGroup.readEntry("Size", defaultSize);
+ if (size.isValid()) {
+ q->resize(size);
+ }
+}
+
+SmartCardWindow::SmartCardWindow(QWidget *parent)
+ : QMainWindow(parent)
+ , d(new Private(this))
+{
+ setWindowTitle(i18nc("@title:window", "Manage Smart Cards"));
+
+ d->smartCardWidget = new SmartCardWidget{this};
+ d->smartCardWidget->setContentsMargins({});
+ setCentralWidget(d->smartCardWidget);
+
+ addAction(KStandardAction::close(this, &SmartCardWindow::close, this));
+
+ // use size of main window as default size
+ const auto mainWindow = KleopatraApplication::instance()->mainWindow();
+ d->restoreLayout(mainWindow ? mainWindow->size() : QSize{1024, 500});
+
+ // load currently inserted cards
+ d->smartCardWidget->showCards(ReaderStatus::instance()->getCards());
+}
+
+SmartCardWindow::~SmartCardWindow()
+{
+ d->saveLayout();
+}
+
+#include "moc_smartcardwindow.cpp"
diff --git a/src/dialogs/smartcardwindow.h b/src/dialogs/smartcardwindow.h
new file mode 100644
index 000000000..87ce7c722
--- /dev/null
+++ b/src/dialogs/smartcardwindow.h
@@ -0,0 +1,26 @@
+/*
+ dialogs/smartcardwindow.h
+
+ This file is part of Kleopatra, the KDE keymanager
+ SPDX-FileCopyrightText: 2024 g10 Code GmbH
+ SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
+
+ SPDX-License-Identifier: GPL-2.0-or-later
+*/
+#pragma once
+
+#include <QMainWindow>
+
+#include <memory>
+
+class SmartCardWindow : public QMainWindow
+{
+ Q_OBJECT
+public:
+ explicit SmartCardWindow(QWidget *parent = nullptr);
+ ~SmartCardWindow() override;
+
+private:
+ class Private;
+ const std::unique_ptr<Private> d;
+};
diff --git a/src/kleopatraapplication.cpp b/src/kleopatraapplication.cpp
index 36fd5ecb6..1cc01a589 100644
--- a/src/kleopatraapplication.cpp
+++ b/src/kleopatraapplication.cpp
@@ -1,887 +1,899 @@
/*
kleopatraapplication.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2016 Bundesamt für Sicherheit in der Informationstechnik
SPDX-FileContributor: Intevation GmbH
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-kleopatra.h>
#include "kleopatraapplication.h"
#include "kleopatra_options.h"
#include "mainwindow.h"
#include "settings.h"
#include "smimevalidationpreferences.h"
#include "systrayicon.h"
#include <conf/configuredialog.h>
#include <conf/groupsconfigdialog.h>
+#include <dialogs/smartcardwindow.h>
#include <smartcard/readerstatus.h>
#include <Libkleo/GnuPG>
#include <utils/kdpipeiodevice.h>
#include <utils/log.h>
#include <utils/userinfo.h>
#include <gpgme++/key.h>
#include <Libkleo/Classify>
#include <Libkleo/Dn>
#include <Libkleo/FileSystemWatcher>
#include <Libkleo/KeyCache>
#include <Libkleo/KeyFilterManager>
#include <Libkleo/KeyGroupConfig>
#include <Libkleo/SystemInfo>
#include <uiserver/uiserver.h>
#include "commands/checksumcreatefilescommand.h"
#include "commands/checksumverifyfilescommand.h"
#include "commands/decryptverifyfilescommand.h"
#include "commands/detailscommand.h"
#include "commands/importcertificatefromfilecommand.h"
#include "commands/lookupcertificatescommand.h"
#include "commands/newcertificatesigningrequestcommand.h"
#include "commands/newopenpgpcertificatecommand.h"
#include "commands/signencryptfilescommand.h"
#include "dialogs/updatenotification.h"
#ifdef Q_OS_WIN
#include <utils/winapi-helpers.h>
#endif
#include "kleopatra_debug.h"
#include <KColorSchemeManager>
#include <KIconLoader>
#include <KLocalizedString>
#include <KMessageBox>
#include <KWindowSystem>
#include <QDesktopServices>
#include <QDir>
#include <QFile>
#include <QFocusFrame>
#if QT_CONFIG(graphicseffect)
#include <QGraphicsEffect>
#endif
#include <QPointer>
#include <QSettings>
#include <QStyleOption>
#include <QStylePainter>
#include <KSharedConfig>
#include <memory>
#ifdef Q_OS_WIN
#include <QtPlatformHeaders/QWindowsWindowFunctions>
#include <windows.h>
#endif
using namespace Kleo;
using namespace Kleo::Commands;
static void add_resources()
{
KIconLoader::global()->addAppDir(QStringLiteral("libkleopatra"));
KIconLoader::global()->addAppDir(QStringLiteral("kwatchgnupg"));
}
static QList<QByteArray> default_logging_options()
{
QList<QByteArray> result;
result.push_back("io");
return result;
}
namespace
{
class FocusFrame : public QFocusFrame
{
Q_OBJECT
public:
using QFocusFrame::QFocusFrame;
protected:
void paintEvent(QPaintEvent *event) override;
};
static QRect effectiveWidgetRect(const QWidget *w)
{
// based on QWidgetPrivate::effectiveRectFor
#if QT_CONFIG(graphicseffect)
if (auto graphicsEffect = w->graphicsEffect(); graphicsEffect && graphicsEffect->isEnabled())
return graphicsEffect->boundingRectFor(w->rect()).toAlignedRect();
#endif // QT_CONFIG(graphicseffect)
return w->rect();
}
static QRect clipRect(const QWidget *w)
{
// based on QWidgetPrivate::clipRect
if (!w->isVisible()) {
return QRect();
}
QRect r = effectiveWidgetRect(w);
int ox = 0;
int oy = 0;
while (w && w->isVisible() && !w->isWindow() && w->parentWidget()) {
ox -= w->x();
oy -= w->y();
w = w->parentWidget();
r &= QRect(ox, oy, w->width(), w->height());
}
return r;
}
void FocusFrame::paintEvent(QPaintEvent *)
{
if (!widget()) {
return;
}
QStylePainter p(this);
QStyleOptionFocusRect option;
initStyleOption(&option);
const int vmargin = style()->pixelMetric(QStyle::PM_FocusFrameVMargin, &option);
const int hmargin = style()->pixelMetric(QStyle::PM_FocusFrameHMargin, &option);
const QRect rect = clipRect(widget()).adjusted(0, 0, hmargin * 2, vmargin * 2);
p.setClipRect(rect);
p.drawPrimitive(QStyle::PE_FrameFocusRect, option);
}
}
class KleopatraApplication::Private
{
friend class ::KleopatraApplication;
KleopatraApplication *const q;
public:
explicit Private(KleopatraApplication *qq)
: q(qq)
, ignoreNewInstance(true)
, firstNewInstance(true)
#ifndef QT_NO_SYSTEMTRAYICON
, sysTray(nullptr)
#endif
{
}
~Private()
{
#ifndef QT_NO_SYSTEMTRAYICON
delete sysTray;
#endif
}
void setUpSysTrayIcon()
{
#ifndef QT_NO_SYSTEMTRAYICON
Q_ASSERT(readerStatus);
sysTray = new SysTrayIcon();
sysTray->setFirstCardWithNullPin(readerStatus->firstCardWithNullPin());
connect(readerStatus.get(), &SmartCard::ReaderStatus::firstCardWithNullPinChanged, sysTray, &SysTrayIcon::setFirstCardWithNullPin);
#endif
}
private:
void connectConfigureDialog()
{
if (configureDialog) {
if (q->mainWindow()) {
connect(configureDialog, SIGNAL(configCommitted()), q->mainWindow(), SLOT(slotConfigCommitted()));
}
connect(configureDialog, &ConfigureDialog::configCommitted, q, &KleopatraApplication::configurationChanged);
}
}
void disconnectConfigureDialog()
{
if (configureDialog) {
if (q->mainWindow()) {
disconnect(configureDialog, SIGNAL(configCommitted()), q->mainWindow(), SLOT(slotConfigCommitted()));
}
disconnect(configureDialog, &ConfigureDialog::configCommitted, q, &KleopatraApplication::configurationChanged);
}
}
public:
bool ignoreNewInstance;
bool firstNewInstance;
QPointer<FocusFrame> focusFrame;
QPointer<ConfigureDialog> configureDialog;
QPointer<GroupsConfigDialog> groupsConfigDialog;
QPointer<MainWindow> mainWindow;
+ QPointer<SmartCardWindow> smartCardWindow;
std::unique_ptr<SmartCard::ReaderStatus> readerStatus;
#ifndef QT_NO_SYSTEMTRAYICON
SysTrayIcon *sysTray;
#endif
std::shared_ptr<KeyGroupConfig> groupConfig;
std::shared_ptr<KeyCache> keyCache;
std::shared_ptr<Log> log;
std::shared_ptr<FileSystemWatcher> watcher;
std::shared_ptr<QSettings> distroSettings;
public:
void setupKeyCache()
{
keyCache = KeyCache::mutableInstance();
keyCache->setRefreshInterval(SMimeValidationPreferences{}.refreshInterval());
watcher.reset(new FileSystemWatcher);
watcher->whitelistFiles(gnupgFileWhitelist());
watcher->addPaths(gnupgFolderWhitelist());
watcher->setDelay(1000);
keyCache->addFileSystemWatcher(watcher);
keyCache->setGroupConfig(groupConfig);
keyCache->setGroupsEnabled(Settings().groupsEnabled());
// always enable remarks (aka tags); in particular, this triggers a
// relisting of the keys with signatures and signature notations
// after the initial (fast) key listing
keyCache->enableRemarks(true);
}
void setUpFilterManager()
{
if (!Settings{}.cmsEnabled()) {
KeyFilterManager::instance()->alwaysFilterByProtocol(GpgME::OpenPGP);
}
}
void setupLogging()
{
log = Log::mutableInstance();
const QByteArray envOptions = qgetenv("KLEOPATRA_LOGOPTIONS");
const bool logAll = envOptions.trimmed() == "all";
const QList<QByteArray> options = envOptions.isEmpty() ? default_logging_options() : envOptions.split(',');
const QByteArray dirNative = qgetenv("KLEOPATRA_LOGDIR");
if (dirNative.isEmpty()) {
return;
}
const QString dir = QFile::decodeName(dirNative);
const QString logFileName = QDir(dir).absoluteFilePath(QStringLiteral("kleopatra.log.%1").arg(QCoreApplication::applicationPid()));
std::unique_ptr<QFile> logFile(new QFile(logFileName));
if (!logFile->open(QIODevice::WriteOnly | QIODevice::Append)) {
qCDebug(KLEOPATRA_LOG) << "Could not open file for logging: " << logFileName << "\nLogging disabled";
return;
}
log->setOutputDirectory(dir);
if (logAll || options.contains("io")) {
log->setIOLoggingEnabled(true);
}
qInstallMessageHandler(Log::messageHandler);
if (logAll || options.contains("pipeio")) {
KDPipeIODevice::setDebugLevel(KDPipeIODevice::Debug);
}
UiServer::setLogStream(log->logFile());
}
void updateFocusFrame(QWidget *focusWidget)
{
if (focusWidget && focusWidget->inherits("QLabel") && focusWidget->window()->testAttribute(Qt::WA_KeyboardFocusChange)) {
if (!focusFrame) {
focusFrame = new FocusFrame{focusWidget};
}
focusFrame->setWidget(focusWidget);
} else if (focusFrame) {
focusFrame->setWidget(nullptr);
}
}
};
KleopatraApplication::KleopatraApplication(int &argc, char *argv[])
: QApplication(argc, argv)
, d(new Private(this))
{
// disable parent<->child navigation in tree views with left/right arrow keys
// because this interferes with column by column navigation that is required
// for accessibility
setStyleSheet(QStringLiteral("QTreeView { arrow-keys-navigate-into-children: 0; }"));
#ifdef Q_OS_WIN
if (SystemInfo::isHighContrastModeActive()) {
// use colors specified by Windows if high-contrast mode is active
QPalette highContrastPalette = palette();
const QColor linkColor = win_getSysColor(COLOR_HOTLIGHT);
highContrastPalette.setColor(QPalette::All, QPalette::Link, linkColor);
highContrastPalette.setColor(QPalette::All, QPalette::LinkVisited, linkColor);
setPalette(highContrastPalette);
}
#endif
connect(this, &QApplication::focusChanged, this, [this](QWidget *, QWidget *now) {
d->updateFocusFrame(now);
});
}
void KleopatraApplication::init()
{
const QString groupConfigPath = Kleo::gnupgHomeDirectory() + QStringLiteral("/kleopatra/kleopatragroupsrc");
d->groupConfig = std::make_shared<KeyGroupConfig>(groupConfigPath);
#ifdef Q_OS_WIN
QWindowsWindowFunctions::setWindowActivationBehavior(QWindowsWindowFunctions::AlwaysActivateWindow);
#endif
const auto blockedUrlSchemes = Settings{}.blockedUrlSchemes();
for (const auto &scheme : blockedUrlSchemes) {
QDesktopServices::setUrlHandler(scheme, this, "blockUrl");
}
add_resources();
DN::setAttributeOrder(Settings{}.attributeOrder());
/* Start the gpg-agent early, this is done explicitly
* because on an empty keyring our keylistings wont start
* the agent. In that case any assuan-connect calls to
* the agent will fail. The requested start via the
* connection is additionally done in case the gpg-agent
* is killed while Kleopatra is running. */
startGpgAgent();
d->readerStatus.reset(new SmartCard::ReaderStatus);
connect(d->readerStatus.get(), &SmartCard::ReaderStatus::startOfGpgAgentRequested, this, &KleopatraApplication::startGpgAgent);
d->setupKeyCache();
d->setUpSysTrayIcon();
d->setUpFilterManager();
d->setupLogging();
#ifdef Q_OS_WIN
if (!SystemInfo::isHighContrastModeActive()) {
/* In high contrast mode we do not want our own colors */
new KColorSchemeManager(this);
}
#else
new KColorSchemeManager(this);
#endif
#ifndef QT_NO_SYSTEMTRAYICON
if (d->sysTray) {
d->sysTray->show();
}
#endif
if (!Kleo::userIsElevated()) {
// For users running Kleo with elevated permissions on Windows we
// always quit the application when the last window is closed.
setQuitOnLastWindowClosed(false);
}
// Sync config when we are about to quit
connect(this, &QApplication::aboutToQuit, this, []() {
KSharedConfig::openConfig()->sync();
});
}
KleopatraApplication::~KleopatraApplication()
{
delete d->groupsConfigDialog;
+ delete d->smartCardWindow;
delete d->mainWindow;
}
namespace
{
using Func = void (KleopatraApplication::*)(const QStringList &, GpgME::Protocol);
}
void KleopatraApplication::slotActivateRequested(const QStringList &arguments, const QString &workingDirectory)
{
QCommandLineParser parser;
kleopatra_options(&parser);
QString err;
if (!arguments.isEmpty() && !parser.parse(arguments)) {
err = parser.errorText();
} else if (arguments.isEmpty()) {
// KDBusServices omits the application name if no other
// arguments are provided. In that case the parser prints
// a warning.
parser.parse(QStringList() << QCoreApplication::applicationFilePath());
}
if (err.isEmpty()) {
err = newInstance(parser, workingDirectory);
}
if (!err.isEmpty()) {
KMessageBox::error(nullptr, err.toHtmlEscaped(), i18n("Failed to execute command"));
Q_EMIT setExitValue(1);
return;
}
Q_EMIT setExitValue(0);
}
QString KleopatraApplication::newInstance(const QCommandLineParser &parser, const QString &workingDirectory)
{
if (d->ignoreNewInstance) {
qCDebug(KLEOPATRA_LOG) << "New instance ignored because of ignoreNewInstance";
return QString();
}
QStringList files;
const QDir cwd = QDir(workingDirectory);
bool queryMode = parser.isSet(QStringLiteral("query")) || parser.isSet(QStringLiteral("search"));
// Query and Search treat positional arguments differently, see below.
if (!queryMode) {
const auto positionalArguments = parser.positionalArguments();
for (const QString &file : positionalArguments) {
// We do not check that file exists here. Better handle
// these errors in the UI.
if (QFileInfo(file).isAbsolute()) {
files << file;
} else {
files << cwd.absoluteFilePath(file);
}
}
}
GpgME::Protocol protocol = GpgME::UnknownProtocol;
if (parser.isSet(QStringLiteral("openpgp"))) {
qCDebug(KLEOPATRA_LOG) << "found OpenPGP";
protocol = GpgME::OpenPGP;
}
if (parser.isSet(QStringLiteral("cms"))) {
qCDebug(KLEOPATRA_LOG) << "found CMS";
if (protocol == GpgME::OpenPGP) {
return i18n("Ambiguous protocol: --openpgp and --cms");
}
protocol = GpgME::CMS;
}
// Check for Parent Window id
WId parentId = 0;
if (parser.isSet(QStringLiteral("parent-windowid"))) {
#ifdef Q_OS_WIN
// WId is not a portable type as it is a pointer type on Windows.
// casting it from an integer is ok though as the values are guaranteed to
// be compatible in the documentation.
parentId = reinterpret_cast<WId>(parser.value(QStringLiteral("parent-windowid")).toUInt());
#else
parentId = parser.value(QStringLiteral("parent-windowid")).toUInt();
#endif
}
// Handle openpgp4fpr URI scheme
QString needle;
if (queryMode) {
needle = parser.positionalArguments().join(QLatin1Char(' '));
}
if (needle.startsWith(QLatin1StringView("openpgp4fpr:"))) {
needle.remove(0, 12);
}
// Check for --search command.
if (parser.isSet(QStringLiteral("search"))) {
// This is an extra command instead of a combination with the
// similar query to avoid changing the older query commands behavior
// and query's "show details if a certificate exist or search on a
// keyserver" logic is hard to explain and use consistently.
if (needle.isEmpty()) {
return i18n("No search string specified for --search");
}
auto const cmd = new LookupCertificatesCommand(needle, nullptr);
cmd->setParentWId(parentId);
cmd->start();
return QString();
}
// Check for --query command
if (parser.isSet(QStringLiteral("query"))) {
if (needle.isEmpty()) {
return i18n("No fingerprint argument specified for --query");
}
auto cmd = Command::commandForQuery(needle);
cmd->setParentWId(parentId);
cmd->start();
return QString();
}
// Check for --gen-key command
if (parser.isSet(QStringLiteral("gen-key"))) {
if (protocol == GpgME::CMS) {
const Kleo::Settings settings{};
if (settings.cmsEnabled() && settings.cmsCertificateCreationAllowed()) {
auto cmd = new NewCertificateSigningRequestCommand;
cmd->setParentWId(parentId);
cmd->start();
} else {
return i18n("You are not allowed to create S/MIME certificate signing requests.");
}
} else {
auto cmd = new NewOpenPGPCertificateCommand;
cmd->setParentWId(parentId);
cmd->start();
}
return QString();
}
// Check for --config command
if (parser.isSet(QStringLiteral("config"))) {
openConfigDialogWithForeignParent(parentId);
return QString();
}
struct FuncInfo {
QString optionName;
Func func;
};
// While most of these options can be handled by the content autodetection
// below it might be useful to override the autodetection if the input is in
// doubt and you e.g. only want to import .asc files or fail and not decrypt them
// if they are actually encrypted data.
static const std::vector<FuncInfo> funcMap{
{QStringLiteral("import-certificate"), &KleopatraApplication::importCertificatesFromFile},
{QStringLiteral("encrypt"), &KleopatraApplication::encryptFiles},
{QStringLiteral("sign"), &KleopatraApplication::signFiles},
{QStringLiteral("encrypt-sign"), &KleopatraApplication::signEncryptFiles},
{QStringLiteral("sign-encrypt"), &KleopatraApplication::signEncryptFiles},
{QStringLiteral("decrypt"), &KleopatraApplication::decryptFiles},
{QStringLiteral("verify"), &KleopatraApplication::verifyFiles},
{QStringLiteral("decrypt-verify"), &KleopatraApplication::decryptVerifyFiles},
{QStringLiteral("checksum"), &KleopatraApplication::checksumFiles},
};
QString found;
Func foundFunc = nullptr;
for (const auto &[opt, fn] : funcMap) {
if (parser.isSet(opt) && found.isEmpty()) {
found = opt;
foundFunc = fn;
} else if (parser.isSet(opt)) {
return i18n(R"(Ambiguous commands "%1" and "%2")", found, opt);
}
}
QStringList errors;
if (!found.isEmpty()) {
if (files.empty()) {
return i18n("No files specified for \"%1\" command", found);
}
qCDebug(KLEOPATRA_LOG) << "found" << found;
(this->*foundFunc)(files, protocol);
} else {
if (files.empty()) {
if (!(d->firstNewInstance && isSessionRestored())) {
qCDebug(KLEOPATRA_LOG) << "openOrRaiseMainWindow";
openOrRaiseMainWindow();
}
} else {
for (const QString &fileName : std::as_const(files)) {
QFileInfo fi(fileName);
if (!fi.isReadable()) {
errors << i18n("Cannot read \"%1\"", fileName);
}
}
handleFiles(files, parentId);
}
}
d->firstNewInstance = false;
#ifdef Q_OS_WIN
// On Windows we might be started from the
// explorer in any working directory. E.g.
// a double click on a file. To avoid preventing
// the folder from deletion we set the
// working directory to the users homedir.
QDir::setCurrent(QDir::homePath());
#endif
return errors.join(QLatin1Char('\n'));
}
void KleopatraApplication::handleFiles(const QStringList &files, WId parentId)
{
auto mw = mainWindow();
if (!mw) {
mw = new MainWindow;
mw->setAttribute(Qt::WA_DeleteOnClose);
setMainWindow(mw);
d->connectConfigureDialog();
}
const QList<Command *> allCmds = Command::commandsForFiles(files, mw->keyListController());
for (Command *cmd : allCmds) {
if (parentId) {
cmd->setParentWId(parentId);
} else {
cmd->setParentWidget(mw);
}
if (dynamic_cast<ImportCertificateFromFileCommand *>(cmd)) {
openOrRaiseMainWindow();
}
cmd->start();
}
}
const MainWindow *KleopatraApplication::mainWindow() const
{
return d->mainWindow;
}
MainWindow *KleopatraApplication::mainWindow()
{
return d->mainWindow;
}
void KleopatraApplication::setMainWindow(MainWindow *mainWindow)
{
if (mainWindow == d->mainWindow) {
return;
}
d->disconnectConfigureDialog();
d->mainWindow = mainWindow;
#ifndef QT_NO_SYSTEMTRAYICON
if (d->sysTray) {
d->sysTray->setMainWindow(mainWindow);
}
#endif
d->connectConfigureDialog();
}
static void open_or_raise(QWidget *w)
{
#ifdef Q_OS_WIN
if (w->isMinimized()) {
qCDebug(KLEOPATRA_LOG) << __func__ << "unminimizing and raising window";
w->raise();
} else if (w->isVisible()) {
qCDebug(KLEOPATRA_LOG) << __func__ << "raising window";
w->raise();
#else
if (w->isVisible()) {
qCDebug(KLEOPATRA_LOG) << __func__ << "activating window";
KWindowSystem::updateStartupId(w->windowHandle());
KWindowSystem::activateWindow(w->windowHandle());
#endif
} else {
qCDebug(KLEOPATRA_LOG) << __func__ << "showing window";
w->show();
}
}
void KleopatraApplication::toggleMainWindowVisibility()
{
if (mainWindow()) {
mainWindow()->setVisible(!mainWindow()->isVisible());
} else {
openOrRaiseMainWindow();
}
if (mainWindow()->isVisible()) {
mainWindow()->exportWindow();
} else {
mainWindow()->unexportWindow();
}
}
void KleopatraApplication::restoreMainWindow()
{
qCDebug(KLEOPATRA_LOG) << "restoring main window";
// Sanity checks
if (!isSessionRestored()) {
qCDebug(KLEOPATRA_LOG) << "Not in session restore";
return;
}
if (mainWindow()) {
qCDebug(KLEOPATRA_LOG) << "Already have main window";
return;
}
auto mw = new MainWindow;
if (KMainWindow::canBeRestored(1)) {
// restore to hidden state, Mainwindow::readProperties() will
// restore saved visibility.
mw->restore(1, false);
}
mw->setAttribute(Qt::WA_DeleteOnClose);
setMainWindow(mw);
d->connectConfigureDialog();
}
void KleopatraApplication::openOrRaiseMainWindow()
{
MainWindow *mw = mainWindow();
if (!mw) {
mw = new MainWindow;
mw->setAttribute(Qt::WA_DeleteOnClose);
setMainWindow(mw);
d->connectConfigureDialog();
}
open_or_raise(mw);
UpdateNotification::checkUpdate(mw);
}
+void KleopatraApplication::openOrRaiseSmartCardWindow()
+{
+ if (!d->smartCardWindow) {
+ d->smartCardWindow = new SmartCardWindow;
+ d->smartCardWindow->setAttribute(Qt::WA_DeleteOnClose);
+ }
+ open_or_raise(d->smartCardWindow);
+}
+
void KleopatraApplication::openConfigDialogWithForeignParent(WId parentWId)
{
if (!d->configureDialog) {
d->configureDialog = new ConfigureDialog;
d->configureDialog->setAttribute(Qt::WA_DeleteOnClose);
d->connectConfigureDialog();
}
// This is similar to what the commands do.
if (parentWId) {
if (QWidget *pw = QWidget::find(parentWId)) {
d->configureDialog->setParent(pw, d->configureDialog->windowFlags());
} else {
d->configureDialog->setAttribute(Qt::WA_NativeWindow, true);
KWindowSystem::setMainWindow(d->configureDialog->windowHandle(), parentWId);
}
}
open_or_raise(d->configureDialog);
// If we have a parent we want to raise over it.
if (parentWId) {
d->configureDialog->raise();
}
}
void KleopatraApplication::openOrRaiseConfigDialog()
{
openConfigDialogWithForeignParent(0);
}
void KleopatraApplication::openOrRaiseGroupsConfigDialog(QWidget *parent)
{
if (!d->groupsConfigDialog) {
d->groupsConfigDialog = new GroupsConfigDialog{parent};
d->groupsConfigDialog->setAttribute(Qt::WA_DeleteOnClose);
} else {
// reparent the dialog to ensure it's shown on top of the (modal) parent
d->groupsConfigDialog->setParent(parent, Qt::Dialog);
}
open_or_raise(d->groupsConfigDialog);
}
#ifndef QT_NO_SYSTEMTRAYICON
void KleopatraApplication::startMonitoringSmartCard()
{
Q_ASSERT(d->readerStatus);
d->readerStatus->startMonitoring();
}
#endif // QT_NO_SYSTEMTRAYICON
void KleopatraApplication::importCertificatesFromFile(const QStringList &files, GpgME::Protocol /*proto*/)
{
openOrRaiseMainWindow();
if (!files.empty()) {
mainWindow()->importCertificatesFromFile(files);
}
}
void KleopatraApplication::encryptFiles(const QStringList &files, GpgME::Protocol proto)
{
auto const cmd = new SignEncryptFilesCommand(files, nullptr);
cmd->setEncryptionPolicy(Force);
cmd->setSigningPolicy(Allow);
if (proto != GpgME::UnknownProtocol) {
cmd->setProtocol(proto);
}
cmd->start();
}
void KleopatraApplication::signFiles(const QStringList &files, GpgME::Protocol proto)
{
auto const cmd = new SignEncryptFilesCommand(files, nullptr);
cmd->setSigningPolicy(Force);
cmd->setEncryptionPolicy(Deny);
if (proto != GpgME::UnknownProtocol) {
cmd->setProtocol(proto);
}
cmd->start();
}
void KleopatraApplication::signEncryptFiles(const QStringList &files, GpgME::Protocol proto)
{
auto const cmd = new SignEncryptFilesCommand(files, nullptr);
if (proto != GpgME::UnknownProtocol) {
cmd->setProtocol(proto);
}
cmd->start();
}
void KleopatraApplication::decryptFiles(const QStringList &files, GpgME::Protocol /*proto*/)
{
auto const cmd = new DecryptVerifyFilesCommand(files, nullptr);
cmd->setOperation(Decrypt);
cmd->start();
}
void KleopatraApplication::verifyFiles(const QStringList &files, GpgME::Protocol /*proto*/)
{
auto const cmd = new DecryptVerifyFilesCommand(files, nullptr);
cmd->setOperation(Verify);
cmd->start();
}
void KleopatraApplication::decryptVerifyFiles(const QStringList &files, GpgME::Protocol /*proto*/)
{
auto const cmd = new DecryptVerifyFilesCommand(files, nullptr);
cmd->start();
}
void KleopatraApplication::checksumFiles(const QStringList &files, GpgME::Protocol /*proto*/)
{
QStringList verifyFiles, createFiles;
for (const QString &file : files) {
if (isChecksumFile(file)) {
verifyFiles << file;
} else {
createFiles << file;
}
}
if (!verifyFiles.isEmpty()) {
auto const cmd = new ChecksumVerifyFilesCommand(verifyFiles, nullptr);
cmd->start();
}
if (!createFiles.isEmpty()) {
auto const cmd = new ChecksumCreateFilesCommand(createFiles, nullptr);
cmd->start();
}
}
void KleopatraApplication::setIgnoreNewInstance(bool ignore)
{
d->ignoreNewInstance = ignore;
}
bool KleopatraApplication::ignoreNewInstance() const
{
return d->ignoreNewInstance;
}
void KleopatraApplication::blockUrl(const QUrl &url)
{
qCDebug(KLEOPATRA_LOG) << "Blocking URL" << url;
KMessageBox::error(mainWindow(), i18n("Opening an external link is administratively prohibited."), i18n("Prohibited"));
}
void KleopatraApplication::startGpgAgent()
{
Kleo::launchGpgAgent();
}
void KleopatraApplication::setDistributionSettings(const std::shared_ptr<QSettings> &settings)
{
d->distroSettings = settings;
}
std::shared_ptr<QSettings> KleopatraApplication::distributionSettings() const
{
return d->distroSettings;
}
#include "kleopatraapplication.moc"
#include "moc_kleopatraapplication.cpp"
diff --git a/src/kleopatraapplication.h b/src/kleopatraapplication.h
index a0e27935f..96b6b4499 100644
--- a/src/kleopatraapplication.h
+++ b/src/kleopatraapplication.h
@@ -1,117 +1,118 @@
/*
kleopatraapplication.h
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2016 Bundesamt für Sicherheit in der Informationstechnik
SPDX-FileContributor: Intevation GmbH
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QApplication>
#include <QCommandLineParser>
#include <QElapsedTimer>
#include <gpgme++/global.h>
#include <memory>
extern QElapsedTimer startupTimer;
#define STARTUP_TIMING qCDebug(KLEOPATRA_LOG) << "Startup timing:" << startupTimer.elapsed() << "ms:"
#define STARTUP_TRACE qCDebug(KLEOPATRA_LOG) << "Startup timing:" << startupTimer.elapsed() << "ms:" << SRCNAME << __func__ << __LINE__;
class MainWindow;
class SysTrayIcon;
class QSettings;
class KleopatraApplication : public QApplication
{
Q_OBJECT
public:
/** Create a new Application object. You have to
* make sure to call init afterwards to get a valid object.
* This is to delay initialisation after the UniqueService
* call is done and our init / call might be forwarded to
* another instance. */
KleopatraApplication(int &argc, char *argv[]);
~KleopatraApplication() override;
/** Initialize the application. Without calling init any
* other call to KleopatraApplication will result in undefined behavior
* and likely crash. */
void init();
static KleopatraApplication *instance()
{
return qobject_cast<KleopatraApplication *>(qApp);
}
/** Starts a new instance or a command from the command line.
*
* Handles the parser options and starts the according commands.
* If ignoreNewInstance is set this function does nothing.
* The parser should have been initialized with kleopatra_options and
* already processed.
* If kleopatra is not session restored
*
* @param parser: The command line parser to use.
* @param workingDirectory: Optional working directory for file arguments.
*
* @returns an empty QString on success. A localized error message otherwise.
* */
QString newInstance(const QCommandLineParser &parser, const QString &workingDirectory = QString());
void setMainWindow(MainWindow *mw);
const MainWindow *mainWindow() const;
MainWindow *mainWindow();
void setIgnoreNewInstance(bool on);
bool ignoreNewInstance() const;
void toggleMainWindowVisibility();
void restoreMainWindow();
void openConfigDialogWithForeignParent(WId parentWId);
/* Add optional signed settings for specialized distributions */
void setDistributionSettings(const std::shared_ptr<QSettings> &settings);
std::shared_ptr<QSettings> distributionSettings() const;
public Q_SLOTS:
void openOrRaiseMainWindow();
+ void openOrRaiseSmartCardWindow();
void openOrRaiseConfigDialog();
void openOrRaiseGroupsConfigDialog(QWidget *parent);
#ifndef QT_NO_SYSTEMTRAYICON
void startMonitoringSmartCard();
#endif
void importCertificatesFromFile(const QStringList &files, GpgME::Protocol proto);
void encryptFiles(const QStringList &files, GpgME::Protocol proto);
void signFiles(const QStringList &files, GpgME::Protocol proto);
void signEncryptFiles(const QStringList &files, GpgME::Protocol proto);
void decryptFiles(const QStringList &files, GpgME::Protocol proto);
void verifyFiles(const QStringList &files, GpgME::Protocol proto);
void decryptVerifyFiles(const QStringList &files, GpgME::Protocol proto);
void checksumFiles(const QStringList &files, GpgME::Protocol /* unused */);
void slotActivateRequested(const QStringList &arguments, const QString &workingDirectory);
void handleFiles(const QStringList &files, WId parentId = 0);
Q_SIGNALS:
/* Emitted from slotActivateRequested to enable setting the
* correct exitValue */
void setExitValue(int value);
void configurationChanged();
private Q_SLOTS:
// used as URL handler for URLs with schemes that shall be blocked
void blockUrl(const QUrl &url);
void startGpgAgent();
private:
class Private;
const std::unique_ptr<Private> d;
};
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index b960b5fbc..1637217c4 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -1,999 +1,988 @@
/* -*- mode: c++; c-basic-offset:4 -*-
mainwindow.cpp
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 "aboutdata.h"
#include "kleopatraapplication.h"
#include "mainwindow.h"
#include "settings.h"
#include <interfaces/focusfirstchild.h>
#include "view/keycacheoverlay.h"
#include "view/keylistcontroller.h"
#include "view/padwidget.h"
#include "view/searchbar.h"
-#include "view/smartcardwidget.h"
#include "view/tabwidget.h"
#include "view/welcomewidget.h"
#include "commands/decryptverifyfilescommand.h"
#include "commands/importcertificatefromfilecommand.h"
#include "commands/importcrlcommand.h"
#include "commands/selftestcommand.h"
#include "commands/signencryptfilescommand.h"
#include "utils/action_data.h"
#include "utils/clipboardmenu.h"
#include "utils/detail_p.h"
#include "utils/filedialog.h"
#include "utils/gui-helper.h"
#include "utils/keyexportdraghandler.h"
#include "utils/userinfo.h"
#include <Libkleo/GnuPG>
#include "dialogs/debugdialog.h"
#include "dialogs/updatenotification.h"
// needed for GPGME_VERSION_NUMBER
#include <gpgme.h>
#include "kleopatra_debug.h"
#include <KAboutApplicationDialog>
#include <KAboutData>
#include <KActionCollection>
#include <KActionMenu>
#include <KColorScheme>
#include <KConfigDialog>
#include <KConfigGroup>
#include <KEditToolBar>
#include <KHelpMenu>
#include <KLocalizedString>
#include <KMessageBox>
#include <KShortcutsDialog>
#include <KStandardAction>
#include <KStandardGuiItem>
#include <KToolBar>
#include <KXMLGUIFactory>
#include <QAction>
#include <QApplication>
#include <QLineEdit>
#include <QSize>
#include <QAbstractItemView>
#include <QCloseEvent>
#include <QDesktopServices>
#include <QDir>
#include <QLabel>
#include <QMenu>
#include <QMimeData>
#include <QPixmap>
#include <QProcess>
#include <QSettings>
#include <QStackedWidget>
#include <QStatusBar>
#include <QTimer>
#include <QVBoxLayout>
#include <Libkleo/Classify>
#include <Libkleo/Compliance>
#include <Libkleo/DocAction>
#include <Libkleo/Formatting>
#include <Libkleo/GnuPG>
#include <Libkleo/KeyCache>
#include <Libkleo/KeyListModel>
#include <Libkleo/KeyListSortFilterProxyModel>
#include <Libkleo/Stl_Util>
#include <Libkleo/SystemInfo>
#include <KSharedConfig>
#ifdef Q_OS_UNIX
#include <KWaylandExtras>
#endif
#include <chrono>
#include <vector>
using namespace std::chrono_literals;
using namespace Kleo;
using namespace Kleo::Commands;
using namespace GpgME;
static KGuiItem KStandardGuiItem_quit()
{
static const QString app = KAboutData::applicationData().displayName();
KGuiItem item = KStandardGuiItem::quit();
item.setText(xi18nc("@action:button", "&Quit <application>%1</application>", app));
return item;
}
static KGuiItem KStandardGuiItem_close()
{
KGuiItem item = KStandardGuiItem::close();
item.setText(i18nc("@action:button", "Only &Close Window"));
return item;
}
static bool isQuitting = false;
namespace
{
static const std::vector<QString> mainViewActionNames = {
QStringLiteral("view_certificate_overview"),
- QStringLiteral("manage_smartcard"),
QStringLiteral("pad_view"),
};
class CertificateView : public QWidget, public FocusFirstChild
{
Q_OBJECT
public:
CertificateView(QWidget *parent = nullptr)
: QWidget{parent}
, ui{this}
{
}
SearchBar *searchBar() const
{
return ui.searchBar;
}
TabWidget *tabWidget() const
{
return ui.tabWidget;
}
void focusFirstChild(Qt::FocusReason reason) override
{
ui.searchBar->lineEdit()->setFocus(reason);
}
private:
struct UI {
TabWidget *tabWidget = nullptr;
SearchBar *searchBar = nullptr;
explicit UI(CertificateView *q)
{
auto vbox = new QVBoxLayout{q};
vbox->setSpacing(0);
searchBar = new SearchBar{q};
vbox->addWidget(searchBar);
tabWidget = new TabWidget{KeyTreeView::Option::NoDefaultContextMenu, q};
vbox->addWidget(tabWidget);
tabWidget->connectSearchBar(searchBar);
}
} ui;
};
}
class MainWindow::Private
{
friend class ::MainWindow;
MainWindow *const q;
public:
explicit Private(MainWindow *qq);
~Private();
template<typename T>
void createAndStart()
{
(new T(this->currentView(), &this->controller))->start();
}
template<typename T>
void createAndStart(QAbstractItemView *view)
{
(new T(view, &this->controller))->start();
}
template<typename T>
void createAndStart(const QStringList &a)
{
(new T(a, this->currentView(), &this->controller))->start();
}
template<typename T>
void createAndStart(const QStringList &a, QAbstractItemView *view)
{
(new T(a, view, &this->controller))->start();
}
void closeAndQuit()
{
if (Kleo::userIsElevated()) {
// For users running Kleo with elevated permissions on Windows we
// always quit the application to avoid some problems.
qApp->quit();
}
const QString app = KAboutData::applicationData().displayName();
const int rc = KMessageBox::questionTwoActionsCancel(q,
xi18n("<application>%1</application> may be used by other applications as a service.<nl/>"
"You may instead want to close this window without exiting <application>%1</application>.",
app),
i18nc("@title:window", "Really Quit?"),
KStandardGuiItem_close(),
KStandardGuiItem_quit(),
KStandardGuiItem::cancel(),
QLatin1StringView("really-quit-") + app.toLower());
if (rc == KMessageBox::Cancel) {
return;
}
isQuitting = rc == KMessageBox::ButtonCode::SecondaryAction;
if (!q->close()) {
return;
}
// WARNING: 'this' might be deleted at this point!
if (rc == KMessageBox::ButtonCode::SecondaryAction) {
qApp->quit();
}
}
void configureToolbars()
{
KEditToolBar dlg(q->factory());
dlg.exec();
}
void editKeybindings()
{
KShortcutsDialog::showDialog(q->actionCollection(), KShortcutsEditor::LetterShortcutsAllowed, q);
updateSearchBarClickMessage();
}
void updateSearchBarClickMessage()
{
const QString shortcutStr = focusToClickSearchAction->shortcut().toString(QKeySequence::NativeText);
ui.searchTab->searchBar()->updateClickMessage(shortcutStr);
}
void updateStatusBar()
{
auto statusBar = std::make_unique<QStatusBar>();
auto settings = KleopatraApplication::instance()->distributionSettings();
bool showStatusbar = false;
if (settings) {
const QString statusline = settings->value(QStringLiteral("statusline"), {}).toString();
if (!statusline.isEmpty()) {
auto customStatusLbl = new QLabel(statusline);
statusBar->insertWidget(0, customStatusLbl);
showStatusbar = true;
}
}
if (DeVSCompliance::isActive()) {
auto statusLbl = std::make_unique<QLabel>(DeVSCompliance::name());
if (!SystemInfo::isHighContrastModeActive()) {
const auto color = KColorScheme(QPalette::Active, KColorScheme::View)
.foreground(DeVSCompliance::isCompliant() ? KColorScheme::NormalText : KColorScheme::NegativeText)
.color();
const auto background = KColorScheme(QPalette::Active, KColorScheme::View)
.background(DeVSCompliance::isCompliant() ? KColorScheme::PositiveBackground : KColorScheme::NegativeBackground)
.color();
statusLbl->setStyleSheet(QStringLiteral("QLabel { color: %1; background-color: %2; }").arg(color.name()).arg(background.name()));
}
statusBar->insertPermanentWidget(0, statusLbl.release());
showStatusbar = true;
}
if (showStatusbar) {
q->setStatusBar(statusBar.release()); // QMainWindow takes ownership
} else {
q->setStatusBar(nullptr);
}
}
void selfTest()
{
createAndStart<SelfTestCommand>();
}
void configureGroups()
{
// open groups config dialog as independent top-level window
KleopatraApplication::instance()->openOrRaiseGroupsConfigDialog(nullptr);
}
void showHandbook();
void gnupgLogViewer()
{
// Warning: Don't assume that the program needs to be in PATH. On Windows, it will also be found next to the calling process.
if (!QProcess::startDetached(QStringLiteral("kwatchgnupg"), QStringList()))
KMessageBox::error(q,
i18n("Could not start the GnuPG Log Viewer (kwatchgnupg). "
"Please check your installation."),
i18n("Error Starting KWatchGnuPG"));
}
void forceUpdateCheck()
{
UpdateNotification::forceUpdateCheck(q);
}
void slotConfigCommitted();
void slotContextMenuRequested(QAbstractItemView *, const QPoint &p)
{
if (auto const menu = qobject_cast<QMenu *>(q->factory()->container(QStringLiteral("listview_popup"), q))) {
menu->exec(p);
} else {
qCDebug(KLEOPATRA_LOG) << "no \"listview_popup\" <Menu> in kleopatra's ui.rc file";
}
}
void slotFocusQuickSearch()
{
ui.searchTab->searchBar()->lineEdit()->setFocus();
}
void showView(const QString &actionName, QWidget *widget)
{
const auto coll = q->actionCollection();
if (coll) {
for (const QString &name : mainViewActionNames) {
if (auto action = coll->action(name)) {
action->setChecked(name == actionName);
}
}
}
ui.stackWidget->setCurrentWidget(widget);
if (auto ffci = dynamic_cast<Kleo::FocusFirstChild *>(widget)) {
ffci->focusFirstChild(Qt::TabFocusReason);
}
}
void showCertificateView()
{
if (KeyCache::instance()->keys().empty()) {
showView(QStringLiteral("view_certificate_overview"), ui.welcomeWidget);
} else {
showView(QStringLiteral("view_certificate_overview"), ui.searchTab);
}
}
- void showSmartcardView()
- {
- showView(QStringLiteral("manage_smartcard"), ui.scWidget);
- }
-
void showPadView()
{
if (!ui.padWidget) {
ui.padWidget = new PadWidget;
ui.stackWidget->addWidget(ui.padWidget);
}
showView(QStringLiteral("pad_view"), ui.padWidget);
ui.stackWidget->resize(ui.padWidget->sizeHint());
}
void restartDaemons()
{
Kleo::restartGpgAgent();
}
void showAboutDialog()
{
// we show the About dialog ourselves so that we can pass up-to-date about data to it;
// KXmlGuiWindow takes a copy of the about data on creation and this copy might not
// contain the backend version information that's set by a background thread
if (!aboutDialog) {
qCDebug(KLEOPATRA_LOG) << __func__ << "Creating About dialog";
aboutDialog = new KAboutApplicationDialog(KAboutData::applicationData(), q);
aboutDialog->setAttribute(Qt::WA_DeleteOnClose);
}
if (aboutDialog->isMinimized()) {
qCDebug(KLEOPATRA_LOG) << __func__ << "Unminimizing About dialog";
aboutDialog->setWindowState((aboutDialog->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
}
qCDebug(KLEOPATRA_LOG) << __func__ << "Showing About dialog";
aboutDialog->show();
}
private:
void setupActions();
QAbstractItemView *currentView() const
{
return ui.searchTab->tabWidget()->currentView();
}
void keyListingDone()
{
const auto curWidget = ui.stackWidget->currentWidget();
- if (curWidget == ui.scWidget || curWidget == ui.padWidget) {
+ if (curWidget == ui.padWidget) {
return;
}
showCertificateView();
}
private:
Kleo::KeyListController controller;
bool firstShow : 1;
struct UI {
CertificateView *searchTab = nullptr;
PadWidget *padWidget = nullptr;
- SmartCardWidget *scWidget = nullptr;
WelcomeWidget *welcomeWidget = nullptr;
QStackedWidget *stackWidget = nullptr;
explicit UI(MainWindow *q);
} ui;
QAction *focusToClickSearchAction = nullptr;
ClipboardMenu *clipboadMenu = nullptr;
QPointer<KAboutApplicationDialog> aboutDialog;
};
MainWindow::Private::UI::UI(MainWindow *q)
: padWidget(nullptr)
{
auto mainWidget = new QWidget{q};
auto mainLayout = new QVBoxLayout(mainWidget);
mainLayout->setContentsMargins({});
stackWidget = new QStackedWidget{q};
searchTab = new CertificateView{q};
stackWidget->addWidget(searchTab);
new KeyCacheOverlay(mainWidget, q);
- scWidget = new SmartCardWidget{q};
- stackWidget->addWidget(scWidget);
-
welcomeWidget = new WelcomeWidget{q};
stackWidget->addWidget(welcomeWidget);
mainLayout->addWidget(stackWidget);
q->setCentralWidget(mainWidget);
}
MainWindow::Private::Private(MainWindow *qq)
: q(qq)
, controller(q)
, firstShow(true)
, ui(q)
{
Q_SET_OBJECT_NAME(controller);
AbstractKeyListModel *flatModel = AbstractKeyListModel::createFlatKeyListModel(q);
AbstractKeyListModel *hierarchicalModel = AbstractKeyListModel::createHierarchicalKeyListModel(q);
Q_SET_OBJECT_NAME(flatModel);
Q_SET_OBJECT_NAME(hierarchicalModel);
#if GPGME_VERSION_NUMBER >= 0x011800 // 1.24.0
auto keyExportDragHandler = std::make_shared<KeyExportDragHandler>();
flatModel->setDragHandler(keyExportDragHandler);
hierarchicalModel->setDragHandler(keyExportDragHandler);
#endif
controller.setFlatModel(flatModel);
controller.setHierarchicalModel(hierarchicalModel);
controller.setTabWidget(ui.searchTab->tabWidget());
ui.searchTab->tabWidget()->setFlatModel(flatModel);
ui.searchTab->tabWidget()->setHierarchicalModel(hierarchicalModel);
#ifdef Q_OS_UNIX
connect(KWaylandExtras::self(), &KWaylandExtras::windowExported, q, [this](const auto &window, const auto &token) {
if (window == q->windowHandle()) {
qputenv("PINENTRY_GEOM_HINT", QUrl::toPercentEncoding(token));
}
});
q->exportWindow();
#endif
setupActions();
ui.stackWidget->setCurrentWidget(ui.searchTab);
if (auto action = q->actionCollection()->action(QStringLiteral("view_certificate_overview"))) {
action->setChecked(true);
}
connect(&controller, SIGNAL(contextMenuRequested(QAbstractItemView *, QPoint)), q, SLOT(slotContextMenuRequested(QAbstractItemView *, QPoint)));
connect(KeyCache::instance().get(), &KeyCache::keyListingDone, q, [this]() {
keyListingDone();
});
q->createGUI(QStringLiteral("kleopatra.rc"));
if (auto helpMenu = q->findChild<KHelpMenu *>()) {
qCDebug(KLEOPATRA_LOG) << "Hook into the help menu to show the About dialog ourselves";
connect(helpMenu, &KHelpMenu::showAboutApplication, q, [this]() {
showAboutDialog();
});
}
// make toolbar buttons accessible by keyboard
auto toolbar = q->findChild<KToolBar *>();
if (toolbar) {
auto toolbarButtons = toolbar->findChildren<QToolButton *>();
for (auto b : toolbarButtons) {
b->setFocusPolicy(Qt::TabFocus);
}
// move toolbar and its child widgets before the central widget in the tab order;
// this is necessary to make Shift+Tab work as expected
forceSetTabOrder(q, toolbar);
auto toolbarChildren = toolbar->findChildren<QWidget *>();
std::for_each(std::rbegin(toolbarChildren), std::rend(toolbarChildren), [toolbar](auto w) {
forceSetTabOrder(toolbar, w);
});
}
if (auto action = q->actionCollection()->action(QStringLiteral("help_whats_this"))) {
delete action;
}
q->setAcceptDrops(true);
// set default window size
q->resize(QSize(1024, 500));
q->setAutoSaveSettings();
updateSearchBarClickMessage();
updateStatusBar();
if (KeyCache::instance()->initialized()) {
keyListingDone();
}
// delay setting the models to use the key cache so that the UI (including
// the "Loading certificate cache..." overlay) is shown before the
// blocking key cache initialization happens
QMetaObject::invokeMethod(
q,
[flatModel, hierarchicalModel]() {
flatModel->useKeyCache(true, KeyList::AllKeys);
hierarchicalModel->useKeyCache(true, KeyList::AllKeys);
},
Qt::QueuedConnection);
}
MainWindow::Private::~Private()
{
}
MainWindow::MainWindow(QWidget *parent, Qt::WindowFlags flags)
: KXmlGuiWindow(parent, flags)
, d(new Private(this))
{
}
MainWindow::~MainWindow()
{
}
void MainWindow::Private::setupActions()
{
KActionCollection *const coll = q->actionCollection();
const std::vector<action_data> action_data = {
// see keylistcontroller.cpp for more actions
// Tools menu
#ifndef Q_OS_WIN
{
"tools_start_kwatchgnupg",
i18n("GnuPG Log Viewer"),
QString(),
"kwatchgnupg",
q,
[this](bool) {
gnupgLogViewer();
},
QString(),
},
#endif
{
"tools_debug_view",
i18n("Debug View"),
QString(),
"",
q,
[this](bool) {
auto dialog = new DebugDialog(q);
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->open();
},
QString(),
},
{
"tools_restart_backend",
i18nc("@action:inmenu", "Restart Background Processes"),
i18nc("@info:tooltip", "Restart the background processes, e.g. after making changes to the configuration."),
"view-refresh",
q,
[this](bool) {
restartDaemons();
},
{},
},
// Help menu
#ifdef Q_OS_WIN
{
"help_check_updates",
i18n("Check for updates"),
QString(),
"gpg4win-compact",
q,
[this](bool) {
forceUpdateCheck();
},
QString(),
},
#endif
// View menu
{
"view_certificate_overview",
i18nc("@action show certificate overview", "Certificates"),
i18n("Show certificate overview"),
"view-certificate",
q,
[this](bool) {
showCertificateView();
},
QString(),
},
{
"pad_view",
i18nc("@action show input / output area for encrypting/signing resp. decrypting/verifying text", "Notepad"),
i18n("Show pad for encrypting/decrypting and signing/verifying text"),
"note",
q,
[this](bool) {
showPadView();
},
QString(),
},
{
"manage_smartcard",
i18nc("@action show smartcard management view", "Smartcards"),
i18n("Show smartcard management"),
"auth-sim-locked",
q,
- [this](bool) {
- showSmartcardView();
+ [](bool) {
+ KleopatraApplication::instance()->openOrRaiseSmartCardWindow();
},
QString(),
},
// Settings menu
{
"settings_self_test",
i18n("Perform Self-Test"),
QString(),
nullptr,
q,
[this](bool) {
selfTest();
},
QString(),
},
{
"configure_groups",
i18n("Configure Groups..."),
QString(),
"group",
q,
[this](bool) {
configureGroups();
},
QString(),
},
// Toolbar
{
"configure_groups_toolbar",
i18nc("@action:intoolbar", "Groups"),
QString(),
"group",
q,
[this](bool) {
configureGroups();
},
QString(),
}};
make_actions_from_data(action_data, coll);
if (!Settings().groupsEnabled()) {
if (auto action = coll->action(QStringLiteral("configure_groups"))) {
delete action;
}
}
for (const QString &name : mainViewActionNames) {
if (auto action = coll->action(name)) {
action->setCheckable(true);
}
}
KStandardAction::close(q, SLOT(close()), coll);
KStandardAction::quit(q, SLOT(closeAndQuit()), coll);
KStandardAction::configureToolbars(q, SLOT(configureToolbars()), coll);
KStandardAction::keyBindings(q, SLOT(editKeybindings()), coll);
KStandardAction::preferences(qApp, SLOT(openOrRaiseConfigDialog()), coll);
focusToClickSearchAction = new QAction(i18nc("@action", "Set Focus to Quick Search"), q);
coll->addAction(QStringLiteral("focus_to_quickseach"), focusToClickSearchAction);
coll->setDefaultShortcut(focusToClickSearchAction, QKeySequence(Qt::ALT | Qt::Key_Q));
connect(focusToClickSearchAction, SIGNAL(triggered(bool)), q, SLOT(slotFocusQuickSearch()));
clipboadMenu = new ClipboardMenu(q);
clipboadMenu->setMainWindow(q);
clipboadMenu->clipboardMenu()->setIcon(QIcon::fromTheme(QStringLiteral("edit-paste")));
clipboadMenu->clipboardMenu()->setPopupMode(QToolButton::InstantPopup);
coll->addAction(QStringLiteral("clipboard_menu"), clipboadMenu->clipboardMenu());
/* Add additional help actions for documentation */
const auto compendium = new DocAction(QIcon::fromTheme(QStringLiteral("gpg4win-compact")),
i18n("Gpg4win Compendium"),
i18nc("The Gpg4win compendium is only available"
"at this point (24.7.2017) in german and english."
"Please check with Gpg4win before translating this filename.",
"gpg4win-compendium-en.pdf"),
QStringLiteral("../share/gpg4win"),
QUrl(),
coll);
coll->addAction(QStringLiteral("help_doc_compendium"), compendium);
/* Documentation centered around the german approved VS-NfD mode for official
* RESTRICTED communication. This is only available in some distributions with
* the focus on official communications. */
const auto quickguide =
new DocAction(QIcon::fromTheme(QStringLiteral("help-contextual")),
i18n("&Quick Guide Encrypt and Sign"),
i18nc("Only available in German and English. Leave to English for other languages.", "encrypt_and_sign_gnupgvsd_en.pdf"),
QStringLiteral("../share/doc/gnupg-vsd"),
QUrl(),
coll);
coll->addAction(QStringLiteral("help_doc_quickguide"), quickguide);
const auto symguide =
new DocAction(QIcon::fromTheme(QStringLiteral("help-contextual")),
i18n("&Password-based Encryption"),
i18nc("Only available in German and English. Leave to English for other languages.", "symmetric_encryption_gnupgvsd_en.pdf"),
QStringLiteral("../share/doc/gnupg-vsd"),
QUrl(),
coll);
coll->addAction(QStringLiteral("help_doc_symenc"), symguide);
const auto groups = new DocAction(QIcon::fromTheme(QStringLiteral("help-contextual")),
i18n("Certificate &Groups"),
i18nc("Only available in German and English. Leave to English for other languages.", "groupfeature_gnupgvsd_en.pdf"),
QStringLiteral("../share/doc/gnupg-vsd"),
QUrl(),
coll);
coll->addAction(QStringLiteral("help_doc_groups"), groups);
#ifdef Q_OS_WIN
const auto gpgol =
new DocAction(QIcon::fromTheme(QStringLiteral("help-contextual")),
i18n("&Mail Encryption in Outlook"),
i18nc("Only available in German and English. Leave to English for other languages. Only shown on Windows.", "gpgol_outlook_addin_en.pdf"),
QStringLiteral("../share/doc/gnupg-vsd"),
QUrl(),
coll);
coll->addAction(QStringLiteral("help_doc_gpgol"), gpgol);
#endif
/* The submenu with advanced topics */
const auto certmngmnt =
new DocAction(QIcon::fromTheme(QStringLiteral("help-contextual")),
i18n("&Certification Management"),
i18nc("Only available in German and English. Leave to English for other languages.", "certification_management_gnupgvsd_en.pdf"),
QStringLiteral("../share/doc/gnupg-vsd"),
QUrl(),
coll);
coll->addAction(QStringLiteral("help_doc_cert_management"), certmngmnt);
const auto smartcard =
new DocAction(QIcon::fromTheme(QStringLiteral("help-contextual")),
i18n("&Smartcard Setup"),
i18nc("Only available in German and English. Leave to English for other languages.", "smartcard_setup_gnupgvsd_en.pdf"),
QStringLiteral("../share/doc/gnupg-vsd"),
QUrl(),
coll);
coll->addAction(QStringLiteral("help_doc_smartcard"), smartcard);
const auto man_gnupg = new DocAction(QIcon::fromTheme(QStringLiteral("help-contextual")),
i18n("GnuPG Command&line"),
QStringLiteral("gnupg_manual_en.pdf"),
QStringLiteral("../share/doc/gnupg-vsd"),
QUrl(QStringLiteral("https://gnupg.org/documentation/manuals/gnupg/")),
coll);
coll->addAction(QStringLiteral("help_doc_gnupg"), man_gnupg);
/* The secops */
const auto approvalmanual =
new DocAction(QIcon::fromTheme(QStringLiteral("dvipdf")),
i18n("Manual for VS-NfD Approval"),
i18nc("Only available in German and English. Keep the English file name for other languages.", "handbuch_zulassung_gnupgvsd_en.pdf"),
QStringLiteral("../share/doc/gnupg-vsd"),
QUrl(),
coll);
coll->addAction(QStringLiteral("help_doc_approval_manual"), approvalmanual);
const auto vsa =
new DocAction(QIcon::fromTheme(QStringLiteral("dvipdf")),
i18n("SecOps for VS-NfD Approval"),
i18nc("Only available in German and English. Keep the English file name for other languages.", "BSI-VSA-10867_ENG_secops.pdf"),
QStringLiteral("../share/doc/gnupg-vsd"),
QUrl(),
coll);
coll->addAction(QStringLiteral("help_doc_vsa"), vsa);
q->setStandardToolBarMenuEnabled(true);
controller.createActions(coll);
ui.searchTab->tabWidget()->createActions(coll);
}
void MainWindow::Private::slotConfigCommitted()
{
controller.updateConfig();
updateStatusBar();
}
void MainWindow::closeEvent(QCloseEvent *e)
{
// KMainWindow::closeEvent() insists on quitting the application,
// so do not let it touch the event...
qCDebug(KLEOPATRA_LOG);
if (d->controller.hasRunningCommands()) {
if (d->controller.shutdownWarningRequired()) {
const int ret = KMessageBox::warningContinueCancel(this,
i18n("There are still some background operations ongoing. "
"These will be terminated when closing the window. "
"Proceed?"),
i18n("Ongoing Background Tasks"));
if (ret != KMessageBox::Continue) {
e->ignore();
return;
}
}
d->controller.cancelCommands();
if (d->controller.hasRunningCommands()) {
// wait for them to be finished:
setEnabled(false);
QEventLoop ev;
QTimer::singleShot(100ms, &ev, &QEventLoop::quit);
connect(&d->controller, &KeyListController::commandsExecuting, &ev, &QEventLoop::quit);
ev.exec();
if (d->controller.hasRunningCommands())
qCWarning(KLEOPATRA_LOG) << "controller still has commands running, this may crash now...";
setEnabled(true);
}
}
unexportWindow();
if (isQuitting || qApp->isSavingSession() || Kleo::userIsElevated()) {
d->ui.searchTab->tabWidget()->saveViews();
KConfigGroup grp(KConfigGroup(KSharedConfig::openConfig(), autoSaveGroup()));
saveMainWindowSettings(grp);
e->accept();
} else {
e->ignore();
hide();
}
}
void MainWindow::showEvent(QShowEvent *e)
{
KXmlGuiWindow::showEvent(e);
if (d->firstShow) {
d->ui.searchTab->tabWidget()->loadViews(KSharedConfig::openStateConfig(), QStringLiteral("KeyList"));
d->firstShow = false;
}
if (!savedGeometry.isEmpty()) {
restoreGeometry(savedGeometry);
}
}
void MainWindow::hideEvent(QHideEvent *e)
{
savedGeometry = saveGeometry();
KXmlGuiWindow::hideEvent(e);
}
void MainWindow::importCertificatesFromFile(const QStringList &files)
{
if (!files.empty()) {
d->createAndStart<ImportCertificateFromFileCommand>(files);
}
}
static QStringList extract_local_files(const QMimeData *data)
{
const QList<QUrl> urls = data->urls();
// begin workaround KDE/Qt misinterpretation of text/uri-list
QList<QUrl>::const_iterator end = urls.end();
if (urls.size() > 1 && !urls.back().isValid()) {
--end;
}
// end workaround
QStringList result;
std::transform(urls.begin(), end, std::back_inserter(result), std::mem_fn(&QUrl::toLocalFile));
result.erase(std::remove_if(result.begin(), result.end(), std::mem_fn(&QString::isEmpty)), result.end());
return result;
}
static bool can_decode_local_files(const QMimeData *data)
{
if (!data) {
return false;
}
return !extract_local_files(data).empty();
}
void MainWindow::dragEnterEvent(QDragEnterEvent *e)
{
qCDebug(KLEOPATRA_LOG);
if (can_decode_local_files(e->mimeData())) {
e->acceptProposedAction();
}
}
void MainWindow::dropEvent(QDropEvent *e)
{
qCDebug(KLEOPATRA_LOG);
if (e->source()) {
// The event comes from kleopatra itself; we don't want to import in this case.
return;
}
if (!can_decode_local_files(e->mimeData())) {
return;
}
e->setDropAction(Qt::CopyAction);
const QStringList files = extract_local_files(e->mimeData());
KleopatraApplication::instance()->handleFiles(files);
e->accept();
}
void MainWindow::readProperties(const KConfigGroup &cg)
{
qCDebug(KLEOPATRA_LOG);
KXmlGuiWindow::readProperties(cg);
setHidden(cg.readEntry("hidden", false));
}
void MainWindow::saveProperties(KConfigGroup &cg)
{
qCDebug(KLEOPATRA_LOG);
KXmlGuiWindow::saveProperties(cg);
cg.writeEntry("hidden", isHidden());
}
void MainWindow::exportWindow()
{
#ifdef Q_OS_UNIX
(void)winId(); // Ensures that windowHandle() returns the window
KWaylandExtras::self()->exportWindow(windowHandle());
#endif
}
void MainWindow::unexportWindow()
{
#ifdef Q_OS_UNIX
KWaylandExtras::self()->unexportWindow(windowHandle());
#endif
}
KeyListController *MainWindow::keyListController()
{
return &d->controller;
}
#include "mainwindow.moc"
#include "moc_mainwindow.cpp"
diff --git a/src/view/smartcardwidget.cpp b/src/view/smartcardwidget.cpp
index 11ab1b029..a7c7c7887 100644
--- a/src/view/smartcardwidget.cpp
+++ b/src/view/smartcardwidget.cpp
@@ -1,249 +1,231 @@
/* view/smartcardwidget.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2017 Bundesamt für Sicherheit in der Informationstechnik
SPDX-FileContributor: Intevation GmbH
SPDX-FileCopyrightText: 2020 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "smartcardwidget.h"
#include "smartcard/netkeycard.h"
#include "smartcard/openpgpcard.h"
#include "smartcard/p15card.h"
#include "smartcard/pivcard.h"
#include "smartcard/readerstatus.h"
#include "smartcard/utils.h"
#include "view/netkeywidget.h"
#include "view/p15cardwidget.h"
#include "view/pgpcardwidget.h"
#include "view/pivcardwidget.h"
#include "kleopatra_debug.h"
#include <KLocalizedString>
#include <QHBoxLayout>
#include <QLabel>
#include <QPointer>
#include <QPushButton>
#include <QStackedWidget>
#include <QTabWidget>
#include <QVBoxLayout>
using namespace Kleo;
using namespace Kleo::SmartCard;
namespace
{
class PlaceHolderWidget : public QWidget
{
Q_OBJECT
public:
explicit PlaceHolderWidget(QWidget *parent = nullptr)
: QWidget{parent}
{
auto lay = new QVBoxLayout;
lay->addStretch(-1);
const QStringList supported = QStringList() << i18nc("OpenPGP refers to a smartcard protocol", "OpenPGP v2.0 - v3.3")
<< i18nc("Gnuk is a cryptographic token for GnuPG", "Gnuk")
<< i18nc("NetKey refers to a smartcard protocol", "NetKey v3")
<< i18nc("PIV refers to a smartcard protocol", "PIV (requires GnuPG 2.3 or later)")
<< i18nc("CardOS is a smartcard operating system", "CardOS 5 (various apps)");
lay->addWidget(new QLabel(QStringLiteral("\t\t<h3>") + i18n("Please insert a compatible smartcard.") + QStringLiteral("</h3>"), this));
lay->addSpacing(10);
lay->addWidget(new QLabel(QStringLiteral("\t\t") + i18n("Kleopatra currently supports the following card types:") + QStringLiteral("<ul><li>")
+ supported.join(QLatin1StringView("</li><li>")) + QStringLiteral("</li></ul>"),
this));
lay->addSpacing(10);
{
auto hbox = new QHBoxLayout;
hbox->addStretch(1);
mReloadButton = new QPushButton{i18n("Reload"), this};
hbox->addWidget(mReloadButton);
hbox->addStretch(1);
lay->addLayout(hbox);
}
lay->addStretch(-1);
auto hLay = new QHBoxLayout(this);
hLay->addStretch(-1);
hLay->addLayout(lay);
hLay->addStretch(-1);
lay->addStretch(-1);
connect(mReloadButton, &QPushButton::clicked, this, &PlaceHolderWidget::reload);
}
Q_SIGNALS:
void reload();
private:
QPushButton *mReloadButton = nullptr;
};
} // namespace
class SmartCardWidget::Private
{
friend class ::Kleo::SmartCardWidget;
public:
Private(SmartCardWidget *qq);
void cardAddedOrChanged(const std::string &serialNumber, const std::string &appName);
void cardRemoved(const std::string &serialNumber, const std::string &appName);
private:
template<typename C, typename W>
void cardAddedOrChanged(const std::string &serialNumber);
private:
SmartCardWidget *const q;
QMap<std::pair<std::string, std::string>, QPointer<QWidget>> mCardWidgets;
PlaceHolderWidget *mPlaceHolderWidget;
QStackedWidget *mStack;
QTabWidget *mTabWidget;
};
SmartCardWidget::Private::Private(SmartCardWidget *qq)
: q{qq}
{
auto vLay = new QVBoxLayout(q);
- vLay->addWidget(new QLabel(QStringLiteral("<h2>") + i18n("Smartcard Management") + QStringLiteral("</h2>")));
-
mStack = new QStackedWidget;
vLay->addWidget(mStack);
mPlaceHolderWidget = new PlaceHolderWidget;
mStack->addWidget(mPlaceHolderWidget);
mTabWidget = new QTabWidget;
mStack->addWidget(mTabWidget);
mStack->setCurrentWidget(mPlaceHolderWidget);
connect(mPlaceHolderWidget, &PlaceHolderWidget::reload, q, &SmartCardWidget::reload);
connect(ReaderStatus::instance(), &ReaderStatus::cardAdded, q, [this](const std::string &serialNumber, const std::string &appName) {
cardAddedOrChanged(serialNumber, appName);
});
connect(ReaderStatus::instance(), &ReaderStatus::cardChanged, q, [this](const std::string &serialNumber, const std::string &appName) {
cardAddedOrChanged(serialNumber, appName);
});
connect(ReaderStatus::instance(), &ReaderStatus::cardRemoved, q, [this](const std::string &serialNumber, const std::string &appName) {
cardRemoved(serialNumber, appName);
});
}
void SmartCardWidget::Private::cardAddedOrChanged(const std::string &serialNumber, const std::string &appName)
{
if (appName == SmartCard::NetKeyCard::AppName) {
cardAddedOrChanged<NetKeyCard, NetKeyWidget>(serialNumber);
} else if (appName == SmartCard::OpenPGPCard::AppName) {
cardAddedOrChanged<OpenPGPCard, PGPCardWidget>(serialNumber);
} else if (appName == SmartCard::PIVCard::AppName) {
cardAddedOrChanged<PIVCard, PIVCardWidget>(serialNumber);
} else if (appName == SmartCard::P15Card::AppName) {
cardAddedOrChanged<P15Card, P15CardWidget>(serialNumber);
} else {
qCWarning(KLEOPATRA_LOG) << "SmartCardWidget::Private::cardAddedOrChanged:"
<< "App" << appName.c_str() << "is not supported";
}
}
namespace
{
static QString getCardLabel(const std::shared_ptr<Card> &card)
{
if (!card->cardHolder().isEmpty()) {
return i18nc("@title:tab smartcard application - name of card holder - serial number of smartcard",
"%1 - %2 - %3",
displayAppName(card->appName()),
card->cardHolder(),
card->displaySerialNumber());
} else {
return i18nc("@title:tab smartcard application - serial number of smartcard", "%1 - %2", displayAppName(card->appName()), card->displaySerialNumber());
}
}
}
template<typename C, typename W>
void SmartCardWidget::Private::cardAddedOrChanged(const std::string &serialNumber)
{
const auto card = ReaderStatus::instance()->getCard<C>(serialNumber);
if (!card) {
qCWarning(KLEOPATRA_LOG) << "SmartCardWidget::Private::cardAddedOrChanged:"
<< "New or changed card" << serialNumber.c_str() << "with app" << C::AppName.c_str() << "not found";
return;
}
W *cardWidget = dynamic_cast<W *>(mCardWidgets.value({serialNumber, C::AppName}).data());
if (!cardWidget) {
cardWidget = new W;
mCardWidgets.insert({serialNumber, C::AppName}, cardWidget);
mTabWidget->addTab(cardWidget, getCardLabel(card));
if (mCardWidgets.size() == 1) {
mStack->setCurrentWidget(mTabWidget);
}
}
cardWidget->setCard(card.get());
}
void SmartCardWidget::Private::cardRemoved(const std::string &serialNumber, const std::string &appName)
{
QWidget *cardWidget = mCardWidgets.take({serialNumber, appName});
if (cardWidget) {
const int index = mTabWidget->indexOf(cardWidget);
if (index != -1) {
mTabWidget->removeTab(index);
}
delete cardWidget;
}
if (mCardWidgets.empty()) {
mStack->setCurrentWidget(mPlaceHolderWidget);
}
}
SmartCardWidget::SmartCardWidget(QWidget *parent)
: QWidget{parent}
, d{std::make_unique<Private>(this)}
{
}
-Kleo::SmartCardWidget::~SmartCardWidget() = default;
-
-QWidget *getFirstEnabledFocusWidget(QWidget *parent)
-{
- for (auto w = parent->nextInFocusChain(); w != parent; w = w->nextInFocusChain()) {
- if (w->isEnabled() && (w->focusPolicy() != Qt::NoFocus)) {
- return w;
- }
- }
- return nullptr;
-}
+SmartCardWidget::~SmartCardWidget() = default;
-void SmartCardWidget::focusFirstChild(Qt::FocusReason reason)
+void SmartCardWidget::showCards(const std::vector<std::shared_ptr<Kleo::SmartCard::Card>> &cards)
{
- if (d->mStack->currentWidget() == d->mPlaceHolderWidget) {
- if (auto w = getFirstEnabledFocusWidget(d->mPlaceHolderWidget)) {
- w->setFocus(reason);
- }
- } else if (auto cardWidget = d->mTabWidget->currentWidget()) {
- if (auto w = getFirstEnabledFocusWidget(cardWidget)) {
- w->setFocus(reason);
- }
+ for (const auto &card : cards) {
+ d->cardAddedOrChanged(card->serialNumber(), card->appName());
}
}
void SmartCardWidget::reload()
{
ReaderStatus::mutableInstance()->updateStatus();
}
#include "smartcardwidget.moc"
#include "moc_smartcardwidget.cpp"
diff --git a/src/view/smartcardwidget.h b/src/view/smartcardwidget.h
index 481a8a089..64397aa47 100644
--- a/src/view/smartcardwidget.h
+++ b/src/view/smartcardwidget.h
@@ -1,38 +1,41 @@
/* view/smartcardwidget.h
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2017 Bundesamt für Sicherheit in der Informationstechnik
SPDX-FileContributor: Intevation GmbH
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
-#include <interfaces/focusfirstchild.h>
-
#include <QWidget>
#include <memory>
+#include <vector>
namespace Kleo
{
+namespace SmartCard
+{
+class Card;
+}
/* SmartCardWidget a generic widget to interact with smartcards */
-class SmartCardWidget : public QWidget, public FocusFirstChild
+class SmartCardWidget : public QWidget
{
Q_OBJECT
public:
explicit SmartCardWidget(QWidget *parent = nullptr);
~SmartCardWidget() override;
- void focusFirstChild(Qt::FocusReason reason = Qt::OtherFocusReason) override;
+ void showCards(const std::vector<std::shared_ptr<Kleo::SmartCard::Card>> &cards);
public Q_SLOTS:
void reload();
private:
class Private;
std::unique_ptr<Private> d;
};
} // namespace Kleo

File Metadata

Mime Type
text/x-diff
Expires
Mon, Dec 23, 1:42 PM (1 d, 7 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
ac/e7/62c12523a23f10c5660132815131

Event Timeline