Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F34215432
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
83 KB
Subscribers
None
View Options
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fb68b63de..622164c73 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,142 +1,144 @@
project(kleopatra)
cmake_minimum_required(VERSION 3.0)
option(FORCE_DISABLE_KCMUTILS "Force building Kleopatra without KCMUtils. Doing this will disable configuration KCM Plugins. [default=OFF]" OFF)
option(DISABLE_KWATCHGNUPG "Don't build the kwatchgnupg tool [default=OFF]" OFF)
# Standalone build. Find / include everything neccessary.
set(KF5_VERSION "5.31.0")
set(KMIME_VERSION "5.4.40")
set(LIBKLEO_VERSION "5.4.40")
set(QT_REQUIRED_VERSION "5.6.0")
+set(GPGME_REQUIRED_VERSION "1.8.0")
find_package(ECM ${KF5_VERSION} REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH})
include(ECMOptionalAddSubdirectory)
include(ECMInstallIcons)
include(ECMSetupVersion)
include(ECMAddTests)
include(ECMMarkNonGuiExecutable)
include(GenerateExportHeader)
include(ECMGenerateHeaders)
include(CMakePackageConfigHelpers)
include(FeatureSummary)
include(CheckFunctionExists)
include(ECMGeneratePriFile)
include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDECompilerSettings NO_POLICY_SCOPE)
include(ECMAddAppIcon)
include(ECMQtDeclareLoggingCategory)
include(ECMCoverageOption)
# Find KF5 packages
if (NOT FORCE_DISABLE_KCMUTILS)
find_package(KF5KCMUtils ${KF5_VERSION} CONFIG REQUIRED)
endif()
find_package(KF5WidgetsAddons ${KF5_VERSION} CONFIG REQUIRED)
find_package(KF5ConfigWidgets ${KF5_VERSION} CONFIG REQUIRED)
find_package(KF5CoreAddons ${KF5_VERSION} CONFIG REQUIRED)
find_package(KF5Codecs ${KF5_VERSION} CONFIG REQUIRED)
find_package(KF5Config ${KF5_VERSION} CONFIG REQUIRED)
find_package(KF5I18n ${KF5_VERSION} CONFIG REQUIRED)
find_package(KF5IconThemes ${KF5_VERSION} CONFIG REQUIRED)
find_package(KF5ItemModels ${KF5_VERSION} CONFIG REQUIRED)
find_package(KF5XmlGui ${KF5_VERSION} CONFIG REQUIRED)
find_package(KF5WindowSystem ${KF5_VERSION} CONFIG REQUIRED)
find_package(KF5DocTools ${KF5_VERSION} CONFIG)
set_package_properties(KF5DocTools PROPERTIES DESCRIPTION "Documentation tools" TYPE OPTIONAL PURPOSE "Required to generate Kleopatra documentation.")
# Optional packages
if (WIN32)
# Only a replacement available for Windows so this
# is required on other platforms.
find_package(KF5DBusAddons ${KF5_VERSION} CONFIG)
set_package_properties(KF5DBusAddons PROPERTIES DESCRIPTION "Support library to work with DBus"
PURPOSE "DBus session integration"
URL "http://inqlude.org/libraries/kdbusaddons.html"
TYPE OPTIONAL)
else()
find_package(KF5DBusAddons ${KF5_VERSION} CONFIG REQUIRED)
set(_kleopatra_dbusaddons_libs KF5::DBusAddons)
endif()
set(HAVE_QDBUS ${Qt5DBus_FOUND})
-find_package(Gpgmepp "1.7.1" CONFIG REQUIRED)
+find_package(Gpgmepp ${GPGME_REQUIRED_VERSION} CONFIG REQUIRED)
+find_package(QGpgme ${GPGME_REQUIRED_VERSION} CONFIG REQUIRED)
# Kdepimlibs packages
find_package(KF5Libkleo ${LIBKLEO_VERSION} CONFIG REQUIRED)
find_package(KF5Mime ${KMIME_VERSION} CONFIG REQUIRED)
find_package(Qt5 ${QT_REQUIRED_VERSION} CONFIG REQUIRED Widgets Test Network PrintSupport)
find_package(Assuan2 REQUIRED)
set(HAVE_KCMUTILS ${KF5KCMUtils_FOUND})
find_package(Boost 1.34.0 REQUIRED)
find_path(Boost_TOPOLOGICAL_SORT_DIR NAMES boost/graph/topological_sort.hpp PATHS ${Boost_INCLUDE_DIRS})
if(NOT Boost_TOPOLOGICAL_SORT_DIR)
message(FATAL_ERROR "The Boost Topological_sort header was NOT found. Should be part of Boost graph module.")
endif()
set(kleopatra_version 2.3.0${KLEOPATRA_VERSION_SUFFIX})
set(kleopatra_release FALSE)
if(NOT kleopatra_release)
if(GIT_FOUND)
execute_process(COMMAND ${GIT_EXECUTABLE} log -1 --oneline --format=%h ${CMAKE_CURRENT_SOURCE_DIR}
WORKING_DIRECTORY ${kdepim_SOURCE_DIR}/kleopatra
OUTPUT_VARIABLE Kleopatra_WC_REVISION)
string(REGEX REPLACE "\n" "" Kleopatra_WC_REVISION "${Kleopatra_WC_REVISION}")
execute_process(COMMAND ${GIT_EXECUTABLE} log -1 --oneline --format=%ci ${CMAKE_CURRENT_SOURCE_DIR}
WORKING_DIRECTORY ${kdepim_SOURCE_DIR}/kleopatra
OUTPUT_VARIABLE Kleopatra_WC_LAST_CHANGED_DATE)
string(REGEX REPLACE " [-0-9:+ ]*\n" "" Kleopatra_WC_LAST_CHANGED_DATE "${Kleopatra_WC_LAST_CHANGED_DATE}")
set(kleopatra_version "${kleopatra_version}-git${Kleopatra_WC_REVISION} (${Kleopatra_WC_LAST_CHANGED_DATE})")
endif()
endif()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version-kleopatra.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/version-kleopatra.h)
include (ConfigureChecks.cmake)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config-kleopatra.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kleopatra.h)
include_directories(
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${Boost_INCLUDE_DIR}
${ASSUAN2_INCLUDES}
)
add_definitions(-D_ASSUAN_ONLY_GPG_ERRORS)
add_definitions(-DQT_NO_URL_CAST_FROM_STRING)
if(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-missing-braces -Wno-parentheses -Wno-ignored-qualifiers")
endif()
kde_enable_exceptions()
add_subdirectory(pics)
add_subdirectory(src)
if(BUILD_TESTING)
add_subdirectory(tests)
add_subdirectory(autotests)
endif()
install( FILES kleopatra.renamecategories kleopatra.categories DESTINATION ${KDE_INSTALL_CONFDIR} )
if(KF5DocTools_FOUND)
add_subdirectory(doc)
endif()
diff --git a/pics/CMakeLists.txt b/pics/CMakeLists.txt
index 0fbb892b4..6bc62cbe2 100644
--- a/pics/CMakeLists.txt
+++ b/pics/CMakeLists.txt
@@ -1,7 +1,12 @@
+if (WIN32)
+ set(EXTRAWINFILES gpg4win-compact.png)
+endif()
+
install(FILES
kleopatra_wizard.png
kleopatra_wizard.svgz
kleopatra_splashscreen.png
kleopatra_splashscreen.svgz
+ gpg4win-compact.png
DESTINATION ${KDE_INSTALL_DATADIR}/kleopatra/pics
)
diff --git a/pics/gpg4win-compact.png b/pics/gpg4win-compact.png
new file mode 100644
index 000000000..1a335ac6c
Binary files /dev/null and b/pics/gpg4win-compact.png differ
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 408b723b4..d48ce902a 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,311 +1,312 @@
add_subdirectory(icons)
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)
add_subdirectory(kconf_update)
if(WIN32)
set(_kleopatra_extra_uiserver_SRCS uiserver/uiserver_win.cpp)
set(_kleopatra_extra_SRCS utils/gnupg-registry.c selftest/registrycheck.cpp)
else()
set(_kleopatra_extra_uiserver_SRCS uiserver/uiserver_unix.cpp)
set(_kleopatra_extra_SRCS)
endif()
set(_kleopatra_uiserver_SRCS
uiserver/sessiondata.cpp
uiserver/uiserver.cpp
${_kleopatra_extra_uiserver_SRCS}
uiserver/assuanserverconnection.cpp
uiserver/echocommand.cpp
uiserver/decryptverifycommandemailbase.cpp
uiserver/decryptverifycommandfilesbase.cpp
uiserver/signcommand.cpp
uiserver/signencryptfilescommand.cpp
uiserver/prepencryptcommand.cpp
uiserver/prepsigncommand.cpp
uiserver/encryptcommand.cpp
uiserver/selectcertificatecommand.cpp
uiserver/importfilescommand.cpp
uiserver/createchecksumscommand.cpp
uiserver/verifychecksumscommand.cpp
selftest/uiservercheck.cpp
)
if(ASSUAN2_FOUND)
include_directories(${ASSUAN2_INCLUDES})
set(_kleopatra_uiserver_extra_libs ${ASSUAN2_LIBRARIES})
else()
include_directories(${ASSUAN_INCLUDES})
if(WIN32)
set(_kleopatra_uiserver_extra_libs ${ASSUAN_VANILLA_LIBRARIES})
else()
set(_kleopatra_uiserver_extra_libs ${ASSUAN_PTHREAD_LIBRARIES})
endif()
endif()
if(HAVE_GPG_ERR_SOURCE_KLEO)
add_definitions(-DGPG_ERR_SOURCE_DEFAULT=GPG_ERR_SOURCE_KLEO)
else()
add_definitions(-DGPG_ERR_SOURCE_DEFAULT=GPG_ERR_SOURCE_USER_1)
endif()
ki18n_wrap_ui(_kleopatra_uiserver_SRCS crypto/gui/signingcertificateselectionwidget.ui)
set(_kleopatra_SRCS
utils/gnupg-helper.cpp
utils/filedialog.cpp
utils/kdpipeiodevice.cpp
utils/kdlogtextwidget.cpp
utils/headerview.cpp
utils/scrollarea.cpp
utils/dragqueen.cpp
utils/multivalidator.cpp
utils/systemtrayicon.cpp
utils/hex.cpp
utils/path-helper.cpp
utils/input.cpp
utils/output.cpp
utils/validation.cpp
utils/wsastarter.cpp
utils/iodevicelogger.cpp
utils/log.cpp
utils/action_data.cpp
utils/types.cpp
utils/archivedefinition.cpp
utils/auditlog.cpp
utils/clipboardmenu.cpp
utils/kuniqueservice.cpp
selftest/selftest.cpp
selftest/enginecheck.cpp
selftest/gpgconfcheck.cpp
selftest/gpgagentcheck.cpp
selftest/libkleopatrarccheck.cpp
${_kleopatra_extra_SRCS}
view/keylistcontroller.cpp
view/keytreeview.cpp
view/searchbar.cpp
view/smartcardwidget.cpp
view/pgpcardwidget.cpp
view/tabwidget.cpp
view/keycacheoverlay.cpp
view/welcomewidget.cpp
dialogs/certificateselectiondialog.cpp
dialogs/expirydialog.cpp
dialogs/lookupcertificatesdialog.cpp
dialogs/ownertrustdialog.cpp
dialogs/selftestdialog.cpp
dialogs/certifycertificatedialog.cpp
dialogs/exportsecretkeydialog.cpp
dialogs/adduseriddialog.cpp
dialogs/exportcertificatesdialog.cpp
dialogs/deletecertificatesdialog.cpp
dialogs/setinitialpindialog.cpp
dialogs/certificatedetailswidget.cpp
dialogs/trustchainwidget.cpp
dialogs/subkeyswidget.cpp
dialogs/gencardkeydialog.cpp
+ dialogs/updatenotification.cpp
crypto/controller.cpp
crypto/certificateresolver.cpp
crypto/sender.cpp
crypto/recipient.cpp
crypto/task.cpp
crypto/taskcollection.cpp
crypto/decryptverifytask.cpp
crypto/decryptverifyemailcontroller.cpp
crypto/decryptverifyfilescontroller.cpp
crypto/autodecryptverifyfilescontroller.cpp
crypto/encryptemailtask.cpp
crypto/encryptemailcontroller.cpp
crypto/newsignencryptemailcontroller.cpp
crypto/signencryptfilestask.cpp
crypto/signencryptfilescontroller.cpp
crypto/signemailtask.cpp
crypto/signemailcontroller.cpp
crypto/createchecksumscontroller.cpp
crypto/verifychecksumscontroller.cpp
crypto/gui/wizard.cpp
crypto/gui/wizardpage.cpp
crypto/gui/certificateselectionline.cpp
crypto/gui/certificatelineedit.cpp
crypto/gui/signingcertificateselectionwidget.cpp
crypto/gui/signingcertificateselectiondialog.cpp
crypto/gui/resultitemwidget.cpp
crypto/gui/resultlistwidget.cpp
crypto/gui/resultpage.cpp
crypto/gui/newresultpage.cpp
crypto/gui/signencryptfileswizard.cpp
crypto/gui/signencryptemailconflictdialog.cpp
crypto/gui/decryptverifyoperationwidget.cpp
crypto/gui/decryptverifyfileswizard.cpp
crypto/gui/decryptverifyfilesdialog.cpp
crypto/gui/objectspage.cpp
crypto/gui/resolverecipientspage.cpp
crypto/gui/signerresolvepage.cpp
crypto/gui/encryptemailwizard.cpp
crypto/gui/signemailwizard.cpp
crypto/gui/signencryptwidget.cpp
crypto/gui/signencryptwizard.cpp
crypto/gui/verifychecksumsdialog.cpp
commands/command.cpp
commands/gnupgprocesscommand.cpp
commands/detailscommand.cpp
commands/exportcertificatecommand.cpp
commands/importcertificatescommand.cpp
commands/importcertificatefromfilecommand.cpp
commands/importcertificatefromclipboardcommand.cpp
commands/lookupcertificatescommand.cpp
commands/reloadkeyscommand.cpp
commands/refreshx509certscommand.cpp
commands/refreshopenpgpcertscommand.cpp
commands/deletecertificatescommand.cpp
commands/decryptverifyfilescommand.cpp
commands/signencryptfilescommand.cpp
commands/signencryptfoldercommand.cpp
commands/encryptclipboardcommand.cpp
commands/signclipboardcommand.cpp
commands/decryptverifyclipboardcommand.cpp
commands/clearcrlcachecommand.cpp
commands/dumpcrlcachecommand.cpp
commands/dumpcertificatecommand.cpp
commands/importcrlcommand.cpp
commands/changeexpirycommand.cpp
commands/changeownertrustcommand.cpp
commands/changeroottrustcommand.cpp
commands/changepassphrasecommand.cpp
commands/certifycertificatecommand.cpp
commands/selftestcommand.cpp
commands/exportsecretkeycommand.cpp
commands/exportopenpgpcertstoservercommand.cpp
commands/adduseridcommand.cpp
commands/newcertificatecommand.cpp
commands/setinitialpincommand.cpp
commands/learncardkeyscommand.cpp
commands/checksumcreatefilescommand.cpp
commands/checksumverifyfilescommand.cpp
commands/exportpaperkeycommand.cpp
commands/genrevokecommand.cpp
${_kleopatra_uiserver_files}
conf/configuredialog.cpp
newcertificatewizard/listwidget.cpp
newcertificatewizard/newcertificatewizard.cpp
smartcard/readerstatus.cpp
smartcard/card.cpp
smartcard/openpgpcard.cpp
aboutdata.cpp
systrayicon.cpp
kleopatraapplication.cpp
mainwindow.cpp
main.cpp
)
if(HAVE_KCMUTILS)
set (_kleopatra_extra_libs KF5::KCMUtils)
else()
set (_kleopatra_SRCS conf/kleopageconfigdialog.cpp ${_kleopatra_SRCS})
endif()
ecm_qt_declare_logging_category(_kleopatra_SRCS HEADER kleopatra_debug.h IDENTIFIER KLEOPATRA_LOG CATEGORY_NAME org.kde.pim.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/certificationoptionswidget.ui
dialogs/expirydialog.ui
dialogs/lookupcertificatesdialog.ui
dialogs/ownertrustdialog.ui
dialogs/selectchecklevelwidget.ui
dialogs/selftestdialog.ui
dialogs/exportsecretkeydialog.ui
dialogs/adduseriddialog.ui
dialogs/setinitialpindialog.ui
dialogs/certificatedetailswidget.ui
dialogs/trustchainwidget.ui
dialogs/subkeyswidget.ui
newcertificatewizard/listwidget.ui
newcertificatewizard/chooseprotocolpage.ui
newcertificatewizard/enterdetailspage.ui
newcertificatewizard/overviewpage.ui
newcertificatewizard/keycreationpage.ui
newcertificatewizard/resultpage.ui
newcertificatewizard/advancedsettingsdialog.ui
)
kconfig_add_kcfg_files(_kleopatra_SRCS
kcfg/tooltippreferences.kcfgc
kcfg/emailoperationspreferences.kcfgc
kcfg/fileoperationspreferences.kcfgc
kcfg/smimevalidationpreferences.kcfgc
)
file(GLOB ICONS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/icons/*-apps-kleopatra.png")
ecm_add_app_icon(_kleopatra_SRCS ICONS ${ICONS_SRCS})
qt5_add_resources(_kleopatra_SRCS kleopatra.qrc)
add_executable(kleopatra_bin ${_kleopatra_SRCS} ${_kleopatra_uiserver_SRCS})
set_target_properties(kleopatra_bin PROPERTIES OUTPUT_NAME kleopatra)
target_link_libraries(kleopatra_bin
Gpgmepp
QGpgme
${_kleopatra_extra_libs}
KF5::Libkleo
KF5::Mime
KF5::I18n
KF5::XmlGui
KF5::IconThemes
KF5::WindowSystem
KF5::CoreAddons
KF5::ItemModels
Qt5::Network
Qt5::PrintSupport # Printing secret keys
${_kleopatra_uiserver_extra_libs}
${_kleopatra_dbusaddons_libs}
kleopatraclientcore
)
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_signencryptfiles.desktop
data/kleopatra_signencryptfolders.desktop
data/kleopatra_decryptverifyfiles.desktop
data/kleopatra_decryptverifyfolders.desktop
DESTINATION ${KDE_INSTALL_KSERVICES5DIR}
)
diff --git a/src/dialogs/updatenotification.cpp b/src/dialogs/updatenotification.cpp
new file mode 100644
index 000000000..4f9d11561
--- /dev/null
+++ b/src/dialogs/updatenotification.cpp
@@ -0,0 +1,186 @@
+/* dialogs/updatenotification.cpp
+
+ This file is part of Kleopatra, the KDE keymanager
+ Copyright (c) 2017 Intevation GmbH
+
+ Kleopatra is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ Kleopatra is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+#include "updatenotification.h"
+
+#include "utils/gnupg-helper.h"
+
+#include "kleopatra_debug.h"
+
+#include <QIcon>
+#include <QGridLayout>
+#include <QCheckBox>
+#include <QDialogButtonBox>
+#include <QDesktopServices>
+#include <QPushButton>
+#include <QLabel>
+#include <QUrl>
+#include <QDateTime>
+
+#include <KIconLoader>
+#include <KLocalizedString>
+#include <KConfigGroup>
+#include <KSharedConfig>
+#include <KMessageBox>
+
+#include <QGpgME/CryptoConfig>
+#include <QGpgME/Protocol>
+
+#include <gpgme++/gpgmefw.h>
+#include <gpgme++/swdbresult.h>
+#include <gpgme++/error.h>
+
+using namespace Kleo;
+
+namespace
+{
+static void gpgconf_set_update_check(bool value)
+{
+ auto conf = QGpgME::cryptoConfig();
+ auto entry = conf->entry(QStringLiteral("dirmngr"),
+ QStringLiteral("Enforcement"),
+ QStringLiteral("allow-version-check"));
+ if (!entry) {
+ qCDebug(KLEOPATRA_LOG) << "allow-version-check entry not found";
+ }
+ entry->setBoolValue(value);
+ conf->sync(true);
+}
+} // namespace
+
+void UpdateNotification::checkUpdate(QWidget *parent, bool force)
+{
+#ifdef Q_OS_WIN
+ if (force) {
+ gpgconf_set_update_check(true);
+ }
+
+ const auto current = gpg4winVersion();
+ GpgME::Error err;
+ KConfigGroup updatecfg(KSharedConfig::openConfig(), "UpdateNotification");
+ const auto lastshown = updatecfg.readEntry("LastShown", QDateTime());
+
+ if (!force && lastshown.isValid() &&
+ lastshown.addSecs(20 * 60 * 60) > QDateTime::currentDateTime()) {
+ qDebug() << QDateTime::currentDateTime().addSecs(20 * 60 * 60);
+ return;
+ }
+
+ const auto results = GpgME::SwdbResult::query("gpg4win",
+ current.toUtf8().constData(),
+ &err);
+ if (err) {
+ qCDebug(KLEOPATRA_LOG) << "update check failed: " << err.asString();
+ return;
+ }
+
+ if (results.size() != 1) {
+ /* Should not happen */
+ qCDebug(KLEOPATRA_LOG) << "more then one result";
+ return;
+ }
+
+ const auto result = results[0];
+
+ if (result.update()) {
+ const QString newVersion = QStringLiteral("%1.%2.%3").arg(result.version().major)
+ .arg(result.version().minor)
+ .arg(result.version().patch);
+ qCDebug(KLEOPATRA_LOG) << "Have update to version:" << newVersion;
+ UpdateNotification notifier(parent, newVersion);
+ notifier.exec();
+ updatecfg.writeEntry("LastShown", QDateTime::currentDateTime());
+ updatecfg.sync();
+ } else {
+ qCDebug(KLEOPATRA_LOG) << "No update for:" << current;
+ if (force) {
+ KMessageBox::information(parent,
+ i18nc("@info",
+ "No update found in the available version database."),
+ i18nc("@title", "Up to date"));
+ }
+ }
+#endif
+}
+
+
+UpdateNotification::UpdateNotification(QWidget *parent, const QString &version) :
+ QDialog(parent)
+{
+ resize(400, 200);
+ auto lay = new QGridLayout;
+ setLayout (lay);
+ auto logo = new QLabel;
+ logo->setMaximumWidth(110);
+
+ setAttribute(Qt::WA_QuitOnClose, false);
+
+ KIconLoader *const il = KIconLoader::global();
+ const QString iconPath = il->iconPath(QLatin1String("gpg4win"),
+ KIconLoader::User);
+ logo->setPixmap(QIcon(iconPath).pixmap(100, 100));
+
+ auto label = new QLabel;
+ const QString boldVersion = QStringLiteral("<b>%1</b>").arg(version);
+ label->setText (i18nc("%1 is the version number", "Version %1 is available.", boldVersion) +
+ QStringLiteral("<br><br>") +
+ i18nc("Link to NEWS style changelog",
+ "See the <a href=\"https://www.gpg4win.org/change-history.html\">new features</a>."));
+ label->setOpenExternalLinks(true);
+ label->setTextInteractionFlags(Qt::TextBrowserInteraction);
+ label->setWordWrap(true);
+ setWindowTitle(i18n("Update available!"));
+ setWindowIcon(QIcon(QLatin1String("gpg4win")));
+
+ lay->addWidget(logo, 0, 0);
+ lay->addWidget(label, 0, 1);
+ const auto chk = new QCheckBox (i18n("Show this notification for future updates."));
+ lay->addWidget(chk, 1, 0, 1, -1);
+ chk->setChecked(true);
+
+ const auto bb = new QDialogButtonBox();
+ const auto b = bb->addButton(i18n("&Get update"), QDialogButtonBox::AcceptRole);
+ b->setDefault(true);
+ b->setIcon(QIcon::fromTheme("arrow-down"));
+ bb->addButton(QDialogButtonBox::Cancel);
+ lay->addWidget(bb, 2, 0, 1, -1);
+ connect (bb, &QDialogButtonBox::accepted, this, [this, chk]() {
+ QDesktopServices::openUrl(QUrl("https://www.gpg4win.org/download.html"));
+ KConfigGroup updatecfg(KSharedConfig::openConfig(), "UpdateNotification");
+
+ updatecfg.writeEntry("NeverShow", !chk->isChecked());
+ QDialog::accept();
+ });
+ connect (bb, &QDialogButtonBox::rejected, this, [this, chk]() {
+ KConfigGroup updatecfg(KSharedConfig::openConfig(), "UpdateNotification");
+ updatecfg.writeEntry("NeverShow", !chk->isChecked());
+ QDialog::reject();
+ });
+}
diff --git a/src/utils/gnupg-helper.h b/src/dialogs/updatenotification.h
similarity index 67%
copy from src/utils/gnupg-helper.h
copy to src/dialogs/updatenotification.h
index 6fab90811..9d4f7aa39 100644
--- a/src/utils/gnupg-helper.h
+++ b/src/dialogs/updatenotification.h
@@ -1,62 +1,54 @@
-/* -*- mode: c++; c-basic-offset:4 -*-
- utils/gnupg-helper.h
+/* dialogs/updatenotification.h
This file is part of Kleopatra, the KDE keymanager
- Copyright (c) 2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2017 Intevation GmbH
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
-#ifndef __KLEOPATRA_GNUPGHELPER_H__
-#define __KLEOPATRA_GNUPGHELPER_H__
+#ifndef DIALOGS_UPDATENOTIFICATION_H
+#define DIALOGS_UPDATENOTIFICATION_H
-#include <gpgme++/engineinfo.h>
-
-class QString;
-class QStringList;
+#include <QString>
+#include <QDialog>
namespace Kleo
{
-QString gnupgHomeDirectory();
-
-QString gpgConfPath();
-QString gpgSmPath();
-QString gpgPath();
-
-QString gpgConfListDir(const char *which);
-QString gpg4winInstallPath();
-QString gnupgInstallPath();
-const QString& paperKeyInstallPath();
-
-QStringList gnupgFileWhitelist();
-
-int makeGnuPGError(int code);
-
-bool engineIsVersion(int major, int minor, int patch, GpgME::Engine = GpgME::GpgConfEngine);
-}
-
-#endif // __KLEOPATRA_GNUPGHELPER_H__
+/** Updatenotification for Gpg4win
+ *
+ * On Windows it is usual for Applications to notifiy the user
+ * about updates. To avoid network access in Kleopatra and
+ * to have only one TLS stack in our package this is implemented
+ * in dirmngr.
+ */
+class UpdateNotification : public QDialog
+{
+public:
+ static void checkUpdate(QWidget *parent, bool force = false);
+ UpdateNotification(QWidget *parent, const QString &version);};
+} // namespace Kleo
+#endif // DIALOGS_UPDATENOTIFICATION_H
diff --git a/src/kleopatra.rc b/src/kleopatra.rc
index 229033d69..e7e3bcc81 100644
--- a/src/kleopatra.rc
+++ b/src/kleopatra.rc
@@ -1,119 +1,123 @@
<!DOCTYPE kpartgui >
-<kpartgui name="kleopatra" version="500" >
+<kpartgui name="kleopatra" version="501" >
<MenuBar>
<Menu name="file">
<text>&File</text>
<Action name="file_new_certificate"/>
<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"/>
<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>&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"/>
</Menu>
<Menu name="certMenu">
<text>&Certificates</text>
<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_change_expiry"/>
<Action name="certificates_change_passphrase"/>
<Action name="certificates_add_userid"/>
<Separator/>
<Action name="certificates_delete"/>
<Separator/>
<Action name="certificates_dump_certificate"/>
</Menu>
<Menu name="tools">
<text>&Tools</text>
<Action name="tools_start_kwatchgnupg"/>
<Separator/>
<Action name="tools_refresh_x509_certificates"/>
<Action name="tools_refresh_openpgp_certificates"/>
<Separator/>
<Action name="manage_smartcard"/>
<Separator/>
<Action name="crl_import_crl"/>
<Separator/>
<Action name="crl_clear_crl_cache"/>
<Action name="crl_dump_crl_cache"/>
<Separator/>
<Action name="configure_backend"/>
</Menu>
<Menu name="settings">
<text>&Settings</text>
<Action name="settings_self_test"/>
</Menu>
<Menu name="window" append="settings_merge">
<text>&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>&Help</text>
+ <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="clipboard_menu"/>
</ToolBar>
<Menu name="listview_popup">
<text>&Certificates</text>
<Action name="certificates_certify_certificate"/>
<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_delete"/>
<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"/>
<Separator/>
<Action name="view_certificate_details"/>
</Menu>
</kpartgui>
diff --git a/src/kleopatraapplication.cpp b/src/kleopatraapplication.cpp
index e7d39c71a..a1068fe2d 100644
--- a/src/kleopatraapplication.cpp
+++ b/src/kleopatraapplication.cpp
@@ -1,599 +1,602 @@
/*
kleopatraapplication.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2008 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include <config-kleopatra.h>
#include "kleopatraapplication.h"
#include "mainwindow.h"
#include "kleopatra_options.h"
#include "systrayicon.h"
#include <smartcard/readerstatus.h>
#include <conf/configuredialog.h>
#include <utils/gnupg-helper.h>
#include <utils/kdpipeiodevice.h>
#include <utils/log.h>
#include <utils/getpid.h>
#include <gpgme++/key.h>
#include <Libkleo/FileSystemWatcher>
#include <Libkleo/KeyCache>
#include <Libkleo/Classify>
#ifdef HAVE_USABLE_ASSUAN
# include <uiserver/uiserver.h>
#endif
#include "commands/signencryptfilescommand.h"
#include "commands/decryptverifyfilescommand.h"
#include "commands/lookupcertificatescommand.h"
#include "commands/checksumcreatefilescommand.h"
#include "commands/checksumverifyfilescommand.h"
#include "commands/detailscommand.h"
#include "commands/newcertificatecommand.h"
+#include "dialogs/updatenotification.h"
+
#include <KIconLoader>
#include <KLocalizedString>
#include "kleopatra_debug.h"
#include <KMessageBox>
#include <KWindowSystem>
#include <QUrl>
#include <QFile>
#include <QDir>
#include <QPointer>
#include <QCommandLineOption>
#include <memory>
#include <KSharedConfig>
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;
}
class KleopatraApplication::Private
{
friend class ::KleopatraApplication;
KleopatraApplication *const q;
public:
explicit Private(KleopatraApplication *qq)
: q(qq),
ignoreNewInstance(true),
sysTray(nullptr)
{
}
~Private() {
delete sysTray;
}
void init()
{
KDAB_SET_OBJECT_NAME(readerStatus);
#ifndef QT_NO_SYSTEMTRAYICON
sysTray = new SysTrayIcon();
sysTray->setAnyCardHasNullPin(readerStatus.anyCardHasNullPin());
sysTray->setAnyCardCanLearnKeys(readerStatus.anyCardCanLearnKeys());
connect(&readerStatus, &SmartCard::ReaderStatus::anyCardHasNullPinChanged,
sysTray, &SysTrayIcon::setAnyCardHasNullPin);
connect(&readerStatus, &SmartCard::ReaderStatus::anyCardCanLearnKeysChanged,
sysTray, &SysTrayIcon::setAnyCardCanLearnKeys);
#endif
}
private:
void connectConfigureDialog()
{
if (configureDialog && q->mainWindow()) {
connect(configureDialog, SIGNAL(configCommitted()), q->mainWindow(), SLOT(slotConfigCommitted()));
}
}
void disconnectConfigureDialog()
{
if (configureDialog && q->mainWindow()) {
disconnect(configureDialog, SIGNAL(configCommitted()), q->mainWindow(), SLOT(slotConfigCommitted()));
}
}
public:
bool ignoreNewInstance;
QPointer<ConfigureDialog> configureDialog;
QPointer<MainWindow> mainWindow;
SmartCard::ReaderStatus readerStatus;
#ifndef QT_NO_SYSTEMTRAYICON
SysTrayIcon *sysTray;
#endif
std::shared_ptr<KeyCache> keyCache;
std::shared_ptr<Log> log;
std::shared_ptr<FileSystemWatcher> watcher;
public:
void setupKeyCache()
{
keyCache = KeyCache::mutableInstance();
watcher.reset(new FileSystemWatcher);
watcher->whitelistFiles(gnupgFileWhitelist());
watcher->addPath(gnupgHomeDirectory());
watcher->setDelay(1000);
keyCache->addFileSystemWatcher(watcher);
}
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(mygetpid()));
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);
#ifdef HAVE_USABLE_ASSUAN
if (logAll || options.contains("pipeio")) {
KDPipeIODevice::setDebugLevel(KDPipeIODevice::Debug);
}
UiServer::setLogStream(log->logFile());
#endif
}
};
KleopatraApplication::KleopatraApplication(int &argc, char *argv[])
: QApplication(argc, argv), d(new Private(this))
{
}
void KleopatraApplication::init()
{
d->init();
add_resources();
d->setupKeyCache();
d->setupLogging();
#ifndef QT_NO_SYSTEMTRAYICON
d->sysTray->show();
#endif
setQuitOnLastWindowClosed(false);
KWindowSystem::allowExternalProcessWindowActivation();
}
KleopatraApplication::~KleopatraApplication()
{
// work around kdelibs bug https://bugs.kde.org/show_bug.cgi?id=162514
KSharedConfig::openConfig()->sync();
}
namespace
{
typedef void (KleopatraApplication::*Func)(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::sorry(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);
Q_FOREACH (const QString &file, parser.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 guranteed 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
}
// 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.
const QString needle = parser.value(QStringLiteral("search"));
if (needle.isEmpty()) {
return i18n("No search string specified for --search");
}
LookupCertificatesCommand *const cmd = new LookupCertificatesCommand(needle, nullptr);
cmd->setParentWId(parentId);
cmd->start();
return QString();
}
// Check for --query command
if (parser.isSet(QStringLiteral("query"))) {
const QString query = parser.value(QStringLiteral("query"));
if (query.isEmpty()) {
return i18n("No fingerprint argument specified for --query");
}
auto cmd = Command::commandForQuery(query);
cmd->setParentWId(parentId);
cmd->start();
return QString();
}
// Check for --gen-key command
if (parser.isSet("gen-key")) {
auto cmd = new NewCertificateCommand(nullptr);
cmd->setParentWId(parentId);
cmd->setProtocol(protocol);
cmd->start();
return QString();
}
static const QMap<QString, Func> 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;
Q_FOREACH (const QString &opt, funcMap.keys()) {
if (parser.isSet(opt) && found.isEmpty()) {
found = opt;
} else if (parser.isSet(opt)) {
return i18n("Ambiguous commands \"%1\" and \"%2\"", found, opt);
}
}
if (!found.isEmpty()) {
if (files.empty()) {
return i18n("No files specified for \"%1\" command", found);
}
qCDebug(KLEOPATRA_LOG) << "found" << found;
(this->*funcMap.value(found))(files, protocol);
} else {
if (files.empty()) {
if (!isSessionRestored()) {
qCDebug(KLEOPATRA_LOG) << "openOrRaiseMainWindow";
openOrRaiseMainWindow();
}
} else {
QStringList errors;
Q_FOREACH (const QString& fileName, files) {
QFileInfo fi(fileName);
if (!fi.isReadable()) {
errors << i18n("Cannot read \"%1\"", fileName);
}
}
Q_FOREACH (Command *cmd, Command::commandsForFiles(files)) {
cmd->setParentWId(parentId);
cmd->start();
}
return errors.join("\n");
}
}
return QString();
}
#ifndef QT_NO_SYSTEMTRAYICON
const SysTrayIcon *KleopatraApplication::sysTrayIcon() const
{
return d->sysTray;
}
SysTrayIcon *KleopatraApplication::sysTrayIcon()
{
return d->sysTray;
}
#endif
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
d->sysTray->setMainWindow(mainWindow);
#endif
d->connectConfigureDialog();
}
static void open_or_raise(QWidget *w)
{
if (w->isMinimized()) {
KWindowSystem::unminimizeWindow(w->winId());
w->raise();
} else if (w->isVisible()) {
w->raise();
} else {
w->show();
}
}
void KleopatraApplication::toggleMainWindowVisibility()
{
if (mainWindow()) {
mainWindow()->setVisible(!mainWindow()->isVisible());
} else {
openOrRaiseMainWindow();
}
}
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;
}
MainWindow *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::openOrRaiseConfigDialog()
{
if (!d->configureDialog) {
d->configureDialog = new ConfigureDialog;
d->configureDialog->setAttribute(Qt::WA_DeleteOnClose);
d->connectConfigureDialog();
}
open_or_raise(d->configureDialog);
}
#ifndef QT_NO_SYSTEMTRAYICON
void KleopatraApplication::startMonitoringSmartCard()
{
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)
{
SignEncryptFilesCommand *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)
{
SignEncryptFilesCommand *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)
{
SignEncryptFilesCommand *const cmd = new SignEncryptFilesCommand(files, nullptr);
if (proto != GpgME::UnknownProtocol) {
cmd->setProtocol(proto);
}
cmd->start();
}
void KleopatraApplication::decryptFiles(const QStringList &files, GpgME::Protocol /*proto*/)
{
DecryptVerifyFilesCommand *const cmd = new DecryptVerifyFilesCommand(files, nullptr);
cmd->setOperation(Decrypt);
cmd->start();
}
void KleopatraApplication::verifyFiles(const QStringList &files, GpgME::Protocol /*proto*/)
{
DecryptVerifyFilesCommand *const cmd = new DecryptVerifyFilesCommand(files, nullptr);
cmd->setOperation(Verify);
cmd->start();
}
void KleopatraApplication::decryptVerifyFiles(const QStringList &files, GpgME::Protocol /*proto*/)
{
DecryptVerifyFilesCommand *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;
}
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 847b4b496..c67c97312 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -1,620 +1,633 @@
/* -*- mode: c++; c-basic-offset:4 -*-
mainwindow.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2007 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include <config-kleopatra.h>
#include "mainwindow.h"
#include "aboutdata.h"
#include "view/searchbar.h"
#include "view/tabwidget.h"
#include "view/keylistcontroller.h"
#include "view/keycacheoverlay.h"
#include "view/smartcardwidget.h"
#include "view/welcomewidget.h"
#include "commands/selftestcommand.h"
#include "commands/importcrlcommand.h"
#include "commands/importcertificatefromfilecommand.h"
#include "commands/decryptverifyfilescommand.h"
#include "commands/signencryptfilescommand.h"
#include "utils/detail_p.h"
#include "utils/gnupg-helper.h"
#include "utils/action_data.h"
#include "utils/filedialog.h"
#include "utils/clipboardmenu.h"
+#include "dialogs/updatenotification.h"
+
#include <KXMLGUIFactory>
#include <QApplication>
#include <KActionCollection>
#include <KLocalizedString>
#include <KStandardAction>
#include <QAction>
#include <KAboutData>
#include <KMessageBox>
#include <KStandardGuiItem>
#include <KShortcutsDialog>
#include <KEditToolBar>
#include <KAboutApplicationDialog>
#include "kleopatra_debug.h"
#include <QLineEdit>
#include <KActionMenu>
#include <KConfigGroup>
#include <QAbstractItemView>
#include <QApplication>
#include <QCloseEvent>
#include <QMenu>
#include <QTimer>
#include <QProcess>
#include <QVBoxLayout>
#include <QMimeData>
#include <QDesktopWidget>
#include <Libkleo/KeyListModel>
#include <Libkleo/KeyListSortFilterProxyModel>
#include <libkleo/cryptoconfigdialog.h>
#include <Libkleo/Stl_Util>
#include <Libkleo/Classify>
#include <Libkleo/KeyCache>
#include <QGpgME/CryptoConfig>
#include <QGpgME/Protocol>
#include <vector>
#include <KSharedConfig>
using namespace Kleo;
using namespace Kleo::Commands;
using namespace GpgME;
static KGuiItem KStandardGuiItem_quit()
{
static const QString app = KAboutData::applicationData().componentName();
KGuiItem item = KStandardGuiItem::quit();
item.setText(i18nc("Quit [ApplicationName]", "&Quit %1", app));
return item;
}
static KGuiItem KStandardGuiItem_close()
{
KGuiItem item = KStandardGuiItem::close();
item.setText(i18n("Only &Close Window"));
return item;
}
static bool isQuitting = false;
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()
{
const QString app = KAboutData::applicationData().componentName();
const int rc = KMessageBox::questionYesNoCancel(q,
i18n("%1 may be used by other applications as a service.\n"
"You may instead want to close this window without exiting %1.", app),
i18n("Really Quit?"), KStandardGuiItem_close(), KStandardGuiItem_quit(), KStandardGuiItem::cancel(),
QLatin1String("really-quit-") + app.toLower());
if (rc == KMessageBox::Cancel) {
return;
}
isQuitting = true;
if (!q->close()) {
return;
}
// WARNING: 'this' might be deleted at this point!
if (rc == KMessageBox::No) {
qApp->quit();
}
}
void configureToolbars()
{
KEditToolBar dlg(q->factory());
dlg.exec();
}
void editKeybindings()
{
KShortcutsDialog::configure(q->actionCollection(), KShortcutsEditor::LetterShortcutsAllowed);
updateSearchBarClickMessage();
}
void updateSearchBarClickMessage()
{
const QString shortcutStr = focusToClickSearchAction->shortcut().toString();
ui.searchBar->updateClickMessage(shortcutStr);
}
void selfTest()
{
createAndStart<SelfTestCommand>();
}
void configureBackend();
void showHandbook();
void gnupgLogViewer()
{
if (!QProcess::startDetached(QStringLiteral("kwatchgnupg")))
KMessageBox::error(q, i18n("Could not start the GnuPG Log Viewer (kwatchgnupg). "
"Please check your installation."),
i18n("Error Starting KWatchGnuPG"));
}
+ void forceUpdateCheck()
+ {
+ UpdateNotification::checkUpdate(q, true);
+ }
+
void slotConfigCommitted();
void slotContextMenuRequested(QAbstractItemView *, const QPoint &p)
{
if (QMenu *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.searchBar->lineEdit()->setFocus();
}
void toggleSmartcardView()
{
if (ui.scWidget->isVisible()) {
ui.scWidget->hide();
ui.searchBar->show();
ui.tabWidget.show();
} else {
ui.scWidget->show();
ui.searchBar->hide();
ui.tabWidget.hide();
ui.welcomeWidget->hide();
}
}
private:
void setupActions();
QAbstractItemView *currentView() const
{
return ui.tabWidget.currentView();
}
void checkWelcomePage()
{
if (ui.scWidget->isVisible()) {
return;
}
if (KeyCache::instance()->keys().empty()) {
ui.searchBar->hide();
ui.tabWidget.hide();
ui.welcomeWidget->show();
} else {
ui.welcomeWidget->hide();
ui.searchBar->show();
ui.tabWidget.show();
}
}
private:
Kleo::KeyListController controller;
bool firstShow : 1;
struct UI {
TabWidget tabWidget;
SearchBar *searchBar;
SmartCardWidget *scWidget;
WelcomeWidget *welcomeWidget;
explicit UI(MainWindow *q);
} ui;
QAction *focusToClickSearchAction;
ClipboardMenu *clipboadMenu;
};
MainWindow::Private::UI::UI(MainWindow *q)
: tabWidget(q)
{
KDAB_SET_OBJECT_NAME(tabWidget);
QWidget *mainWidget = new QWidget;
QVBoxLayout *vbox = new QVBoxLayout;
vbox->setSpacing(0);
mainWidget->setLayout(vbox);
searchBar = new SearchBar;
vbox->addWidget(searchBar);
tabWidget.connectSearchBar(searchBar);
vbox->addWidget(&tabWidget);
new KeyCacheOverlay(mainWidget, q);
scWidget = new SmartCardWidget();
vbox->addWidget(scWidget);
scWidget->hide();
welcomeWidget = new WelcomeWidget();
vbox->addWidget(welcomeWidget);
welcomeWidget->hide();
q->setCentralWidget(mainWidget);
}
MainWindow::Private::Private(MainWindow *qq)
: q(qq),
controller(q),
firstShow(true),
ui(q)
{
KDAB_SET_OBJECT_NAME(controller);
AbstractKeyListModel *flatModel = AbstractKeyListModel::createFlatKeyListModel(q);
AbstractKeyListModel *hierarchicalModel = AbstractKeyListModel::createHierarchicalKeyListModel(q);
KDAB_SET_OBJECT_NAME(flatModel);
KDAB_SET_OBJECT_NAME(hierarchicalModel);
controller.setFlatModel(flatModel);
controller.setHierarchicalModel(hierarchicalModel);
controller.setTabWidget(&ui.tabWidget);
ui.tabWidget.setFlatModel(flatModel);
ui.tabWidget.setHierarchicalModel(hierarchicalModel);
setupActions();
connect(&controller, SIGNAL(contextMenuRequested(QAbstractItemView*,QPoint)), q, SLOT(slotContextMenuRequested(QAbstractItemView*,QPoint)));
connect(ui.scWidget, &SmartCardWidget::backRequested, q, [this]() {
auto action = q->actionCollection()->action(QStringLiteral("manage_smartcard"));
Q_ASSERT(action);
action->setChecked(false);
});
connect(KeyCache::instance().get(), &KeyCache::keyListingDone, q, [this] () {checkWelcomePage();});
q->createGUI(QStringLiteral("kleopatra.rc"));
q->setAcceptDrops(true);
q->setAutoSaveSettings();
updateSearchBarClickMessage();
}
MainWindow::Private::~Private() {}
MainWindow::MainWindow(QWidget *parent, Qt::WindowFlags flags)
: KXmlGuiWindow(parent, flags), d(new Private(this))
{
const auto desk = QApplication::desktop()->screenGeometry(this);
resize(desk.width() / 2, desk.height() / 3);
}
MainWindow::~MainWindow() {}
void MainWindow::Private::setupActions()
{
KActionCollection *const coll = q->actionCollection();
const action_data action_data[] = {
// most have been MOVED TO keylistcontroller.cpp
// Tools menu
#ifndef Q_OS_WIN
{
"tools_start_kwatchgnupg", i18n("GnuPG Log Viewer"), QString(),
"kwatchgnupg", q, SLOT(gnupgLogViewer()), QString(), false, true
},
+#endif
+#ifdef Q_OS_WIN
+ {
+ "help_check_updates", i18n("Check for updates"), QString(),
+ "gpg4win-compact", q, SLOT(forceUpdateCheck()), QString(), false, true
+ },
#endif
// most have been MOVED TO keylistcontroller.cpp
#if 0
{
"configure_backend", i18n("Configure GnuPG Backend..."), QString(),
0, q, SLOT(configureBackend()), QString(), false, true
},
#endif
// Settings menu
{
"settings_self_test", i18n("Perform Self-Test"), QString(),
nullptr, q, SLOT(selfTest()), QString(), false, true
},
{
"manage_smartcard", i18n("Manage Smartcards"),
i18n("Edit or initialize a crypto hardware token."), "secure-card", q, SLOT(toggleSmartcardView()), QString(), true, true
}
// most have been MOVED TO keylistcontroller.cpp
};
make_actions_from_data(action_data, /*sizeof action_data / sizeof *action_data,*/ coll);
if (QAction *action = coll->action(QStringLiteral("configure_backend"))) {
action->setMenuRole(QAction::NoRole); //prevent Qt OS X heuristics for config* actions
}
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(i18n("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()->setDelayed(false);
coll->addAction(QStringLiteral("clipboard_menu"), clipboadMenu->clipboardMenu());
q->setStandardToolBarMenuEnabled(true);
controller.createActions(coll);
ui.tabWidget.createActions(coll);
}
void MainWindow::Private::configureBackend()
{
QGpgME::CryptoConfig *const config = QGpgME::cryptoConfig();
if (!config) {
KMessageBox::error(q, i18n("Could not configure the cryptography backend (gpgconf tool not found)"), i18n("Configuration Error"));
return;
}
Kleo::CryptoConfigDialog dlg(config);
const int result = dlg.exec();
// Forget all data parsed from gpgconf, so that we show updated information
// when reopening the configuration dialog.
config->clear();
if (result == QDialog::Accepted) {
#if 0
// Tell other apps (e.g. kmail) that the gpgconf data might have changed
QDBusMessage message =
QDBusMessage::createSignal(QString(), "org.kde.kleo.CryptoConfig", "changed");
QDBusConnection::sessionBus().send(message);
#endif
}
}
void MainWindow::Private::slotConfigCommitted()
{
controller.updateConfig();
}
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(100, &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);
}
}
if (isQuitting || qApp->isSavingSession()) {
d->ui.tabWidget.saveViews(KSharedConfig::openConfig().data());
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.tabWidget.loadViews(KSharedConfig::openConfig().data());
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 (!can_decode_local_files(e->mimeData())) {
return;
}
e->setDropAction(Qt::CopyAction);
const QStringList files = extract_local_files(e->mimeData());
const unsigned int classification = classify(files);
QMenu menu;
QAction *const signEncrypt = menu.addAction(i18n("Sign/Encrypt..."));
QAction *const decryptVerify = mayBeAnyMessageType(classification) ? menu.addAction(i18n("Decrypt/Verify...")) : nullptr;
if (signEncrypt || decryptVerify) {
menu.addSeparator();
}
QAction *const importCerts = mayBeAnyCertStoreType(classification) ? menu.addAction(i18n("Import Certificates")) : nullptr;
QAction *const importCRLs = mayBeCertificateRevocationList(classification) ? menu.addAction(i18n("Import CRLs")) : nullptr;
if (importCerts || importCRLs) {
menu.addSeparator();
}
if (!signEncrypt && !decryptVerify && !importCerts && !importCRLs) {
return;
}
menu.addAction(i18n("Cancel"));
const QAction *const chosen = menu.exec(mapToGlobal(e->pos()));
if (!chosen) {
return;
}
if (chosen == signEncrypt) {
d->createAndStart<SignEncryptFilesCommand>(files);
} else if (chosen == decryptVerify) {
d->createAndStart<DecryptVerifyFilesCommand>(files);
} else if (chosen == importCerts) {
d->createAndStart<ImportCertificateFromFileCommand>(files);
} else if (chosen == importCRLs) {
d->createAndStart<ImportCrlCommand>(files);
}
e->accept();
}
void MainWindow::readProperties(const KConfigGroup &cg)
{
qCDebug(KLEOPATRA_LOG);
KXmlGuiWindow::readProperties(cg);
savedGeometry = cg.readEntry("savedGeometry", QByteArray());
if (!savedGeometry.isEmpty()) {
restoreGeometry(savedGeometry);
}
if (! cg.readEntry<bool>("hidden", false)) {
show();
}
}
void MainWindow::saveProperties(KConfigGroup &cg)
{
qCDebug(KLEOPATRA_LOG);
KXmlGuiWindow::saveProperties(cg);
cg.writeEntry("hidden", isHidden());
if (isHidden()) {
cg.writeEntry("savedGeometry", savedGeometry);
} else {
cg.writeEntry("savedGeometry", saveGeometry());
}
}
#include "moc_mainwindow.cpp"
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 584babeb5..5b711c606 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -1,76 +1,77 @@
/* -*- mode: c++; c-basic-offset:4 -*-
mainwindow.h
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2007 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#ifndef __KLEOPATRA_MAINWINDOW_DESKTOP_H__
#define __KLEOPATRA_MAINWINDOW_DESKTOP_H__
#include <KXmlGuiWindow>
#include <utils/pimpl_ptr.h>
class MainWindow : public KXmlGuiWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr, Qt::WindowFlags f = KDE_DEFAULT_WINDOWFLAGS);
~MainWindow();
public Q_SLOTS:
void importCertificatesFromFile(const QStringList &files);
protected:
QByteArray savedGeometry;
void closeEvent(QCloseEvent *e) Q_DECL_OVERRIDE;
void showEvent(QShowEvent *e) Q_DECL_OVERRIDE;
void hideEvent(QHideEvent *e) Q_DECL_OVERRIDE;
void dragEnterEvent(QDragEnterEvent *) Q_DECL_OVERRIDE;
void dropEvent(QDropEvent *) Q_DECL_OVERRIDE;
void readProperties(const KConfigGroup &cg) Q_DECL_OVERRIDE;
void saveProperties(KConfigGroup &cg) Q_DECL_OVERRIDE;
private:
class Private;
kdtools::pimpl_ptr<Private> d;
Q_PRIVATE_SLOT(d, void closeAndQuit())
Q_PRIVATE_SLOT(d, void selfTest())
Q_PRIVATE_SLOT(d, void configureBackend())
Q_PRIVATE_SLOT(d, void configureToolbars())
Q_PRIVATE_SLOT(d, void editKeybindings())
Q_PRIVATE_SLOT(d, void gnupgLogViewer())
Q_PRIVATE_SLOT(d, void slotConfigCommitted())
Q_PRIVATE_SLOT(d, void slotContextMenuRequested(QAbstractItemView *, QPoint))
Q_PRIVATE_SLOT(d, void slotFocusQuickSearch())
Q_PRIVATE_SLOT(d, void toggleSmartcardView())
+ Q_PRIVATE_SLOT(d, void forceUpdateCheck())
};
#endif /* __KLEOPATRA_MAINWINDOW_DESKTOP_H__ */
diff --git a/src/utils/gnupg-helper.cpp b/src/utils/gnupg-helper.cpp
index a814b59e2..c9c59bd36 100644
--- a/src/utils/gnupg-helper.cpp
+++ b/src/utils/gnupg-helper.cpp
@@ -1,236 +1,253 @@
/* -*- mode: c++; c-basic-offset:4 -*-
utils/gnupg-helper.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2008 Klarälvdalens Datakonsult AB
2016 Intevation GmbH
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include <config-kleopatra.h>
#include "gnupg-helper.h"
#include "utils/hex.h"
#include <gpgme++/engineinfo.h>
#include <gpgme++/error.h>
#include "kleopatra_debug.h"
#include <QDir>
#include <QFile>
#include <QString>
#include <QProcess>
#include <QByteArray>
#include <QStandardPaths>
#include <QCoreApplication>
#include <gpg-error.h>
#ifdef Q_OS_WIN
#include "gnupg-registry.h"
#endif // Q_OS_WIN
#include <algorithm>
#include <array>
#include <cassert>
using namespace GpgME;
QString Kleo::gnupgHomeDirectory()
{
#ifdef Q_OS_WIN
return QFile::decodeName(default_homedir());
#else
const QByteArray gnupgHome = qgetenv("GNUPGHOME");
if (!gnupgHome.isEmpty()) {
return QFile::decodeName(gnupgHome);
} else {
return QDir::homePath() + QLatin1String("/.gnupg");
}
#endif
}
int Kleo::makeGnuPGError(int code)
{
return gpg_error(static_cast<gpg_err_code_t>(code));
}
static QString findGpgExe(GpgME::Engine engine, const QString &exe)
{
const GpgME::EngineInfo info = GpgME::engineInfo(engine);
return info.fileName() ? QFile::decodeName(info.fileName()) : QStandardPaths::findExecutable(exe);
}
QString Kleo::gpgConfPath()
{
return findGpgExe(GpgME::GpgConfEngine, QStringLiteral("gpgconf"));
}
QString Kleo::gpgSmPath()
{
return findGpgExe(GpgME::GpgSMEngine, QStringLiteral("gpgsm"));
}
QString Kleo::gpgPath()
{
return findGpgExe(GpgME::GpgEngine, QStringLiteral("gpg"));
}
QStringList Kleo::gnupgFileWhitelist()
{
return QStringList()
// The obvious pubring
<< QStringLiteral("pubring.gpg")
// GnuPG 2.1 pubring
<< QStringLiteral("pubring.kbx")
// Trust in X509 Certificates
<< QStringLiteral("trustlist.txt")
// Trustdb controls ownertrust and thus WOT validity
<< QStringLiteral("trustdb.gpg")
// We want to update when smartcard status changes
<< QStringLiteral("reader*.status")
// No longer used in 2.1 but for 2.0 we want this
<< QStringLiteral("secring.gpg")
// Changes to the trustmodel * because you can have different
// configs for different versions.
<< QStringLiteral("gpg.conf*")
;
}
+QString Kleo::gpg4winVersion()
+{
+ QFile versionFile(gpg4winInstallPath() + QStringLiteral("/../VERSION"));
+ if (!versionFile.open(QIODevice::ReadOnly)) {
+ // No need to translate this should only be the case in development
+ // builds.
+ return QStringLiteral("Unknown (no VERSION file found)");
+ }
+ const QString g4wTag = QString::fromUtf8(versionFile.readLine());
+ if (!g4wTag.startsWith(QStringLiteral("gpg4win"))) {
+ // Hu? Something unknown
+ return QStringLiteral("Unknown (invalid VERSION file found)");
+ }
+ // Next line is version.
+ return QString::fromUtf8(versionFile.readLine()).trimmed();
+}
+
QString Kleo::gpg4winInstallPath()
{
#ifdef Q_OS_WIN
// QApplication::applicationDirPath is only used as a fallback
// to support the case where Kleopatra is not installed from
// Gpg4win but Gpg4win is also installed.
char *instDir = read_w32_registry_string("HKEY_LOCAL_MACHINE",
"Software/GPG4Win",
"Install Directory");
if (!instDir) {
// Fallback to HKCU
instDir = read_w32_registry_string("HKEY_CURRENT_USER",
"Software/GPG4Win",
"Install Directory");
}
if (instDir) {
QString ret = QString::fromLocal8Bit(instDir) + QStringLiteral("/bin");
free(instDir);
return ret;
}
qCDebug(KLEOPATRA_LOG) << "Gpg4win not found. Falling back to Kleopatra instdir.";
#endif
return QCoreApplication::applicationDirPath();
}
QString Kleo::gnupgInstallPath()
{
return gpgConfListDir("bindir");
}
QString Kleo::gpgConfListDir(const char *which)
{
if (!which || !*which) {
return QString();
}
const QString gpgConfPath = Kleo::gpgConfPath();
if (gpgConfPath.isEmpty()) {
return QString();
}
QProcess gpgConf;
qCDebug(KLEOPATRA_LOG) << "gpgConfListDir: starting " << qPrintable(gpgConfPath) << " --list-dirs";
gpgConf.start(gpgConfPath, QStringList() << QStringLiteral("--list-dirs"));
if (!gpgConf.waitForFinished()) {
qCDebug(KLEOPATRA_LOG) << "gpgConfListDir(): failed to execute gpgconf: " << qPrintable(gpgConf.errorString());
qCDebug(KLEOPATRA_LOG) << "output was:" << endl << gpgConf.readAllStandardError().constData();
return QString();
}
const QList<QByteArray> lines = gpgConf.readAllStandardOutput().split('\n');
for (const QByteArray &line : lines)
if (line.startsWith(which) && line[qstrlen(which)] == ':') {
const int begin = qstrlen(which) + 1;
int end = line.size();
while (end && (line[end - 1] == '\n' || line[end - 1] == '\r')) {
--end;
}
const QString result = QDir::fromNativeSeparators(QFile::decodeName(hexdecode(line.mid(begin, end - begin))));
qCDebug(KLEOPATRA_LOG) << "gpgConfListDir: found " << qPrintable(result)
<< " for '" << which << "'entry";
return result;
}
qCDebug(KLEOPATRA_LOG) << "gpgConfListDir(): didn't find '" << which << "'"
<< "entry in output:" << endl << gpgConf.readAllStandardError().constData();
return QString();
}
bool Kleo::engineIsVersion(int major, int minor, int patch, Engine engine)
{
static QMap<Engine, std::array<int, 3> > cachedVersions;
const int required_version[] = {major, minor, patch};
// Gpgconf means spawning processes which is expensive on windows.
std::array<int, 3> actual_version;
if (!cachedVersions.contains(engine)) {
const Error err = checkEngine(engine);
if (err.code() == GPG_ERR_INV_ENGINE) {
qCDebug(KLEOPATRA_LOG) << "isVersion: invalid engine. '";
return false;
}
const char *actual = GpgME::engineInfo(engine).version();
QRegExp rx(QLatin1String("(\\d+)\\.(\\d+)\\.(\\d+)(?:-svn\\d+)?.*"));
if (!rx.exactMatch(QString::fromUtf8(actual))) {
qCDebug(KLEOPATRA_LOG) << "Can't parse version " << actual;
return false;
}
bool ok;
for (int i = 0; i < 3; ++i) {
ok = false;
actual_version[i] = rx.cap(i + 1).toUInt(&ok);
assert(ok);
}
qCDebug(KLEOPATRA_LOG) << "Parsed" << actual << "as: "
<< actual_version[0] << '.'
<< actual_version[1] << '.'
<< actual_version[2] << '.';
cachedVersions.insert(engine, actual_version);
} else {
actual_version = cachedVersions.value(engine);
}
// return ! ( actual_version < required_version )
return !std::lexicographical_compare(std::begin(actual_version), std::end(actual_version),
std::begin(required_version), std::end(required_version));
}
const QString& Kleo::paperKeyInstallPath()
{
static const QString pkPath = QStandardPaths::findExecutable(QStringLiteral("paperkey"), QStringList() << QCoreApplication::applicationDirPath()).isEmpty() ?
QStandardPaths::findExecutable(QStringLiteral("paperkey")) :
QStandardPaths::findExecutable(QStringLiteral("paperkey"), QStringList() << QCoreApplication::applicationDirPath());
return pkPath;
}
diff --git a/src/utils/gnupg-helper.h b/src/utils/gnupg-helper.h
index 6fab90811..b99f23440 100644
--- a/src/utils/gnupg-helper.h
+++ b/src/utils/gnupg-helper.h
@@ -1,62 +1,63 @@
/* -*- mode: c++; c-basic-offset:4 -*-
utils/gnupg-helper.h
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2008 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#ifndef __KLEOPATRA_GNUPGHELPER_H__
#define __KLEOPATRA_GNUPGHELPER_H__
#include <gpgme++/engineinfo.h>
class QString;
class QStringList;
namespace Kleo
{
QString gnupgHomeDirectory();
QString gpgConfPath();
QString gpgSmPath();
QString gpgPath();
QString gpgConfListDir(const char *which);
QString gpg4winInstallPath();
+QString gpg4winVersion();
QString gnupgInstallPath();
const QString& paperKeyInstallPath();
QStringList gnupgFileWhitelist();
int makeGnuPGError(int code);
bool engineIsVersion(int major, int minor, int patch, GpgME::Engine = GpgME::GpgConfEngine);
}
#endif // __KLEOPATRA_GNUPGHELPER_H__
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Dec 19, 2:29 PM (1 d, 11 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
80/8e/f793f6b795bdd4a81d4bdae52c63
Attached To
rKLEOPATRA Kleopatra
Event Timeline
Log In to Comment