Page MenuHome GnuPG

No OneTemporary

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 761722894..94d7975f5 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,408 +1,409 @@
# 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)
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
utils/windowsprocessdevice.cpp
utils/userinfo_win.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)
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(KF5IdentityManagement_FOUND AND KF5MailTransport_FOUND AND KF5MailTransportAkonadi_FOUND)
set(_kleopatra_mail_libs
KF5::IdentityManagement # Export OpenPGP keys using WKS
KF5::MailTransport
KF5::MailTransportAkonadi
)
add_definitions(-DMAILAKONADI_ENABLED)
endif()
ki18n_wrap_ui(_kleopatra_uiserver_SRCS crypto/gui/signingcertificateselectionwidget.ui)
set(_kleopatra_SRCS
utils/accessibility.cpp
utils/gui-helper.cpp
utils/filedialog.cpp
utils/kdpipeiodevice.cpp
utils/headerview.cpp
utils/scrollarea.cpp
utils/dragqueen.cpp
utils/multivalidator.cpp
utils/systemtrayicon.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
utils/tags.cpp
utils/writecertassuantransaction.cpp
utils/keyparameters.cpp
utils/userinfo.cpp
utils/keys.cpp
selftest/selftest.cpp
selftest/enginecheck.cpp
selftest/gpgconfcheck.cpp
selftest/gpgagentcheck.cpp
selftest/libkleopatrarccheck.cpp
selftest/compliancecheck.cpp
${_kleopatra_extra_SRCS}
view/errorlabel.cpp
view/formtextinput.cpp
view/htmllabel.cpp
view/keylistcontroller.cpp
view/keytreeview.cpp
view/searchbar.cpp
view/smartcardwidget.cpp
view/openpgpkeycardwidget.cpp
view/padwidget.cpp
view/pgpcardwidget.cpp
view/pivcardwidget.cpp
view/p15cardwidget.cpp
view/netkeywidget.cpp
view/nullpinwidget.cpp
view/tabwidget.cpp
view/keycacheoverlay.cpp
view/urllabel.cpp
view/waitwidget.cpp
view/welcomewidget.cpp
dialogs/certificateselectiondialog.cpp
dialogs/certifywidget.cpp
dialogs/expirydialog.cpp
dialogs/lookupcertificatesdialog.cpp
dialogs/ownertrustdialog.cpp
dialogs/selftestdialog.cpp
dialogs/certifycertificatedialog.cpp
dialogs/revokecertificationwidget.cpp
dialogs/revokecertificationdialog.cpp
dialogs/adduseriddialog.cpp
dialogs/deletecertificatesdialog.cpp
dialogs/setinitialpindialog.cpp
dialogs/certificatedetailsdialog.cpp
dialogs/certificatedetailswidget.cpp
dialogs/trustchainwidget.cpp
dialogs/weboftrustwidget.cpp
dialogs/weboftrustdialog.cpp
dialogs/exportdialog.cpp
dialogs/subkeyswidget.cpp
dialogs/gencardkeydialog.cpp
dialogs/updatenotification.cpp
dialogs/pivcardapplicationadministrationkeyinputdialog.cpp
dialogs/certificatedetailsinputwidget.cpp
dialogs/createcsrforcardkeydialog.cpp
dialogs/groupdetailsdialog.cpp
dialogs/editgroupdialog.cpp
dialogs/revokekeydialog.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/signencrypttask.cpp
crypto/signencryptfilescontroller.cpp
crypto/signemailtask.cpp
crypto/signemailcontroller.cpp
crypto/createchecksumscontroller.cpp
crypto/verifychecksumscontroller.cpp
+ crypto/checksumsutils_p.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/unknownrecipientwidget.cpp
crypto/gui/verifychecksumsdialog.cpp
commands/command.cpp
commands/gnupgprocesscommand.cpp
commands/detailscommand.cpp
commands/exportcertificatecommand.cpp
commands/exportgroupscommand.cpp
commands/importcertificatescommand.cpp
commands/importcertificatefromfilecommand.cpp
commands/importcertificatefromclipboardcommand.cpp
commands/importcertificatefromdatacommand.cpp
commands/importcertificatefromkeyservercommand.cpp
commands/lookupcertificatescommand.cpp
commands/reloadkeyscommand.cpp
commands/refreshcertificatecommand.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/revokecertificationcommand.cpp
commands/selftestcommand.cpp
commands/exportsecretkeycommand.cpp
commands/exportsecretkeycommand_old.cpp
commands/exportsecretsubkeycommand.cpp
commands/exportopenpgpcertstoservercommand.cpp
commands/exportopenpgpcerttoprovidercommand.cpp
commands/adduseridcommand.cpp
commands/newcertificatecommand.cpp
commands/setinitialpincommand.cpp
commands/learncardkeyscommand.cpp
commands/checksumcreatefilescommand.cpp
commands/checksumverifyfilescommand.cpp
commands/exportpaperkeycommand.cpp
commands/importpaperkeycommand.cpp
commands/genrevokecommand.cpp
commands/keytocardcommand.cpp
commands/cardcommand.cpp
commands/pivgeneratecardkeycommand.cpp
commands/changepincommand.cpp
commands/authenticatepivcardapplicationcommand.cpp
commands/setpivcardapplicationadministrationkeycommand.cpp
commands/certificatetopivcardcommand.cpp
commands/importcertificatefrompivcardcommand.cpp
commands/createopenpgpkeyfromcardkeyscommand.cpp
commands/createcsrforcardkeycommand.cpp
commands/revokekeycommand.cpp
commands/revokeuseridcommand.cpp
${_kleopatra_uiserver_files}
conf/configuredialog.cpp
conf/groupsconfigdialog.cpp
conf/groupsconfigpage.cpp
conf/groupsconfigwidget.cpp
newcertificatewizard/advancedsettingsdialog.cpp
newcertificatewizard/chooseprotocolpage.cpp
newcertificatewizard/enterdetailspage.cpp
newcertificatewizard/keyalgo.cpp
newcertificatewizard/keycreationpage.cpp
newcertificatewizard/listwidget.cpp
newcertificatewizard/newcertificatewizard.cpp
newcertificatewizard/resultpage.cpp
newcertificatewizard/wizardpage.cpp
smartcard/readerstatus.cpp
smartcard/card.cpp
smartcard/openpgpcard.cpp
smartcard/netkeycard.cpp
smartcard/pivcard.cpp
smartcard/p15card.cpp
smartcard/keypairinfo.cpp
smartcard/utils.cpp
smartcard/deviceinfowatcher.cpp
accessibility/accessiblerichtextlabel.cpp
accessibility/accessiblewidgetfactory.cpp
aboutdata.cpp
systrayicon.cpp
kleopatraapplication.cpp
mainwindow.cpp
main.cpp
kleopatra.qrc
)
if(WIN32)
configure_file (versioninfo.rc.in versioninfo.rc)
set(_kleopatra_SRCS ${CMAKE_CURRENT_BINARY_DIR}/versioninfo.rc ${_kleopatra_SRCS})
endif()
set (_kleopatra_SRCS conf/kleopageconfigdialog.cpp ${_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/ownertrustdialog.ui
dialogs/selectchecklevelwidget.ui
dialogs/selftestdialog.ui
dialogs/setinitialpindialog.ui
dialogs/trustchainwidget.ui
dialogs/subkeyswidget.ui
newcertificatewizard/listwidget.ui
)
kconfig_add_kcfg_files(_kleopatra_SRCS
kcfg/tooltippreferences.kcfgc
kcfg/emailoperationspreferences.kcfgc
kcfg/fileoperationspreferences.kcfgc
kcfg/smimevalidationpreferences.kcfgc
kcfg/tagspreferences.kcfgc
kcfg/settings.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
QGpgme
${_kleopatra_extra_libs}
KF5::Libkleo
KF5::Mime
KF5::I18n
KF5::XmlGui
KF5::IconThemes
KF5::WindowSystem
KF5::CoreAddons
KF5::ItemModels
KF5::Crash
${_kleopatra_mail_libs}
Qt${QT_MAJOR_VERSION}::Network
Qt${QT_MAJOR_VERSION}::PrintSupport # Printing secret keys
${_kleopatra_uiserver_extra_libs}
${_kleopatra_dbusaddons_libs}
kleopatraclientcore
${_kleopatra_platform_libs}
)
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(
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/crypto/checksumsutils_p.h b/src/crypto/checksumsutils_p.cpp
similarity index 71%
copy from src/crypto/checksumsutils_p.h
copy to src/crypto/checksumsutils_p.cpp
index 1b1e61221..6b213c73b 100644
--- a/src/crypto/checksumsutils_p.h
+++ b/src/crypto/checksumsutils_p.cpp
@@ -1,136 +1,108 @@
/* -*- mode: c++; c-basic-offset:4 -*-
- crypto/checksumsutils_p.h
+ crypto/checksumsutils_p.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB
SPDX-License-Identifier: GPL-2.0-or-later
*/
-#pragma once
-
+#include "checksumsutils_p.h"
#include <Libkleo/ChecksumDefinition>
#include "kleopatra_debug.h"
#include <QFile>
-#include <QRegularExpression>
#include <QTextStream>
-#ifdef Q_OS_UNIX
-// Can we use QAbstractFileEngine::caseSensitive()?
-static const Qt::CaseSensitivity fs_cs = Qt::CaseSensitive;
-
-static const QRegularExpression::PatternOption s_regex_cs = QRegularExpression::NoPatternOption;
-#else
-static const Qt::CaseSensitivity fs_cs = Qt::CaseInsensitive;
-static const QRegularExpression::PatternOption s_regex_cs = QRegularExpression::CaseInsensitiveOption;
-#endif
-
-static std::vector<QRegularExpression> get_patterns(const std::vector<std::shared_ptr<Kleo::ChecksumDefinition>> &checksumDefinitions)
+std::vector<QRegularExpression> ChecksumsUtils::get_patterns(const std::vector<std::shared_ptr<Kleo::ChecksumDefinition>> &checksumDefinitions)
{
std::vector<QRegularExpression> result;
for (const auto &cd : checksumDefinitions) {
if (!cd) {
continue;
}
const QStringList &patterns = cd->patterns();
result.reserve(result.size() + patterns.size());
std::transform(patterns.cbegin(), patterns.cend(), std::back_inserter(result), [](const QString &pattern) {
return QRegularExpression(QRegularExpression::anchoredPattern(pattern), s_regex_cs);
});
}
return result;
}
-struct matches_any : std::unary_function<QString, bool> {
- const std::vector<QRegularExpression> m_regexps;
- explicit matches_any(const std::vector<QRegularExpression> &regexps) : m_regexps(regexps) {}
- bool operator()(const QString &s) const
- {
- return std::any_of(m_regexps.cbegin(), m_regexps.cend(),
- [&s](const QRegularExpression &rx) { return rx.match(s).hasMatch(); });
- }
-};
-
-struct File {
- QString name;
- QByteArray checksum;
- bool binary;
-};
-
static QString decode(const QString &encoded)
{
QString decoded;
decoded.reserve(encoded.size());
bool shift = false;
for (const QChar ch : encoded)
if (shift) {
switch (ch.toLatin1()) {
case '\\': decoded += QLatin1Char('\\'); break;
case 'n': decoded += QLatin1Char('\n'); break;
default:
qCDebug(KLEOPATRA_LOG) << "invalid escape sequence" << '\\' << ch << "(interpreted as '" << ch << "')";
decoded += ch;
break;
}
shift = false;
} else {
if (ch == QLatin1Char('\\')) {
shift = true;
} else {
decoded += ch;
}
}
return decoded;
}
-static std::vector<File> parse_sum_file(const QString &fileName)
+std::vector<ChecksumsUtils::File> ChecksumsUtils::parse_sum_file(const QString &fileName)
{
std::vector<File> files;
QFile f(fileName);
if (!f.open(QIODevice::ReadOnly)) {
return {};
}
QTextStream s(&f);
static const QRegularExpression rx(QRegularExpression::anchoredPattern(uR"((\\?)([a-f0-9A-F]+) ([ *])([^\\n]+)\\n*)"));
while (!s.atEnd()) {
const QString line = s.readLine();
QRegularExpressionMatch match = rx.match(line);
if (!match.hasMatch()) {
continue;
}
Q_ASSERT(!match.capturedView(4).endsWith(QLatin1Char('\n')));
const File file = {
match.capturedView(1) == QLatin1Char('\\') ? decode(match.captured(4)) : match.captured(4),
match.capturedView(2).toLatin1(),
match.capturedView(3) == QLatin1Char('*'),
};
files.push_back(file);
}
return files;
}
-static std::shared_ptr<Kleo::ChecksumDefinition> filename2definition(const QString &fileName,
+std::shared_ptr<Kleo::ChecksumDefinition> ChecksumsUtils::filename2definition(const QString &fileName,
const std::vector<std::shared_ptr<Kleo::ChecksumDefinition>> &checksumDefinitions)
{
auto matchFileName = [&fileName](const std::shared_ptr<Kleo::ChecksumDefinition> &cd) {
if (!cd) {
return false;
}
const QStringList &patterns = cd->patterns();
return std::any_of(patterns.cbegin(), patterns.cend(), [&fileName](const QString &pattern) {
const QRegularExpression re(QRegularExpression::anchoredPattern(pattern), s_regex_cs);
return re.match(fileName).hasMatch();
});
};
auto it = std::find_if(checksumDefinitions.cbegin(), checksumDefinitions.cend(), matchFileName);
return it != checksumDefinitions.cend() ? *it : std::shared_ptr<Kleo::ChecksumDefinition>{};
}
diff --git a/src/crypto/checksumsutils_p.h b/src/crypto/checksumsutils_p.h
index 1b1e61221..1e89f84a5 100644
--- a/src/crypto/checksumsutils_p.h
+++ b/src/crypto/checksumsutils_p.h
@@ -1,136 +1,55 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/checksumsutils_p.h
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
-#include <Libkleo/ChecksumDefinition>
-
#include "kleopatra_debug.h"
-#include <QFile>
#include <QRegularExpression>
-#include <QTextStream>
+namespace Kleo
+{
+class ChecksumDefinition;
+}
+
+namespace ChecksumsUtils {
#ifdef Q_OS_UNIX
// Can we use QAbstractFileEngine::caseSensitive()?
static const Qt::CaseSensitivity fs_cs = Qt::CaseSensitive;
static const QRegularExpression::PatternOption s_regex_cs = QRegularExpression::NoPatternOption;
#else
static const Qt::CaseSensitivity fs_cs = Qt::CaseInsensitive;
static const QRegularExpression::PatternOption s_regex_cs = QRegularExpression::CaseInsensitiveOption;
#endif
-static std::vector<QRegularExpression> get_patterns(const std::vector<std::shared_ptr<Kleo::ChecksumDefinition>> &checksumDefinitions)
-{
- std::vector<QRegularExpression> result;
- for (const auto &cd : checksumDefinitions) {
- if (!cd) {
- continue;
- }
- const QStringList &patterns = cd->patterns();
- result.reserve(result.size() + patterns.size());
- std::transform(patterns.cbegin(), patterns.cend(), std::back_inserter(result), [](const QString &pattern) {
- return QRegularExpression(QRegularExpression::anchoredPattern(pattern), s_regex_cs);
- });
- }
-
- return result;
-}
+std::vector<QRegularExpression> get_patterns(const std::vector<std::shared_ptr<Kleo::ChecksumDefinition>> &checksumDefinitions);
struct matches_any : std::unary_function<QString, bool> {
const std::vector<QRegularExpression> m_regexps;
explicit matches_any(const std::vector<QRegularExpression> &regexps) : m_regexps(regexps) {}
bool operator()(const QString &s) const
{
return std::any_of(m_regexps.cbegin(), m_regexps.cend(),
[&s](const QRegularExpression &rx) { return rx.match(s).hasMatch(); });
}
};
struct File {
QString name;
QByteArray checksum;
bool binary;
};
-static QString decode(const QString &encoded)
-{
- QString decoded;
- decoded.reserve(encoded.size());
- bool shift = false;
- for (const QChar ch : encoded)
- if (shift) {
- switch (ch.toLatin1()) {
- case '\\': decoded += QLatin1Char('\\'); break;
- case 'n': decoded += QLatin1Char('\n'); break;
- default:
- qCDebug(KLEOPATRA_LOG) << "invalid escape sequence" << '\\' << ch << "(interpreted as '" << ch << "')";
- decoded += ch;
- break;
- }
- shift = false;
- } else {
- if (ch == QLatin1Char('\\')) {
- shift = true;
- } else {
- decoded += ch;
- }
- }
- return decoded;
-}
-
-static std::vector<File> parse_sum_file(const QString &fileName)
-{
- std::vector<File> files;
- QFile f(fileName);
- if (!f.open(QIODevice::ReadOnly)) {
- return {};
- }
-
- QTextStream s(&f);
- static const QRegularExpression rx(QRegularExpression::anchoredPattern(uR"((\\?)([a-f0-9A-F]+) ([ *])([^\\n]+)\\n*)"));
- while (!s.atEnd()) {
- const QString line = s.readLine();
- QRegularExpressionMatch match = rx.match(line);
- if (!match.hasMatch()) {
- continue;
- }
+std::vector<File> parse_sum_file(const QString &fileName);
- Q_ASSERT(!match.capturedView(4).endsWith(QLatin1Char('\n')));
- const File file = {
- match.capturedView(1) == QLatin1Char('\\') ? decode(match.captured(4)) : match.captured(4),
- match.capturedView(2).toLatin1(),
- match.capturedView(3) == QLatin1Char('*'),
- };
- files.push_back(file);
- }
-
- return files;
-}
+std::shared_ptr<Kleo::ChecksumDefinition> filename2definition(const QString &fileName,
+ const std::vector<std::shared_ptr<Kleo::ChecksumDefinition>> &checksumDefinitions);
-static std::shared_ptr<Kleo::ChecksumDefinition> filename2definition(const QString &fileName,
- const std::vector<std::shared_ptr<Kleo::ChecksumDefinition>> &checksumDefinitions)
-{
- auto matchFileName = [&fileName](const std::shared_ptr<Kleo::ChecksumDefinition> &cd) {
- if (!cd) {
- return false;
- }
-
- const QStringList &patterns = cd->patterns();
- return std::any_of(patterns.cbegin(), patterns.cend(), [&fileName](const QString &pattern) {
- const QRegularExpression re(QRegularExpression::anchoredPattern(pattern), s_regex_cs);
- return re.match(fileName).hasMatch();
- });
- };
-
- auto it = std::find_if(checksumDefinitions.cbegin(), checksumDefinitions.cend(), matchFileName);
-
- return it != checksumDefinitions.cend() ? *it : std::shared_ptr<Kleo::ChecksumDefinition>{};
-}
+} // namespace ChecksumsUtils
diff --git a/src/crypto/createchecksumscontroller.cpp b/src/crypto/createchecksumscontroller.cpp
index a7bfb23d3..8568581dd 100644
--- a/src/crypto/createchecksumscontroller.cpp
+++ b/src/crypto/createchecksumscontroller.cpp
@@ -1,609 +1,610 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/createchecksumscontroller.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-kleopatra.h>
#include "createchecksumscontroller.h"
#include "checksumsutils_p.h"
#include <utils/input.h>
#include <utils/output.h>
#include <utils/kleo_assert.h>
#include <Libkleo/Stl_Util>
+#include <Libkleo/ChecksumDefinition>
#include <Libkleo/Classify>
#include <KLocalizedString>
#include <QTemporaryFile>
#include <KConfigGroup>
#include <KSharedConfig>
#include <QDialog>
#include <QDialogButtonBox>
#include <QLabel>
#include <QListWidget>
#include <QVBoxLayout>
#include <QPointer>
#include <QFileInfo>
#include <QThread>
#include <QMutex>
#include <QProgressDialog>
#include <QDir>
#include <QProcess>
#include <gpg-error.h>
#include <deque>
#include <map>
#include <limits>
#include <functional>
using namespace Kleo;
using namespace Kleo::Crypto;
namespace
{
class ResultDialog : public QDialog
{
Q_OBJECT
public:
ResultDialog(const QStringList &created, const QStringList &errors, QWidget *parent = nullptr, Qt::WindowFlags f = {})
: QDialog(parent, f),
createdLB(created.empty()
? i18nc("@info", "No checksum files have been created.")
: i18nc("@info", "These checksum files have been successfully created:"), this),
createdLW(this),
errorsLB(errors.empty()
? i18nc("@info", "There were no errors.")
: i18nc("@info", "The following errors were encountered:"), this),
errorsLW(this),
buttonBox(QDialogButtonBox::Ok, Qt::Horizontal, this),
vlay(this)
{
KDAB_SET_OBJECT_NAME(createdLB);
KDAB_SET_OBJECT_NAME(createdLW);
KDAB_SET_OBJECT_NAME(errorsLB);
KDAB_SET_OBJECT_NAME(errorsLW);
KDAB_SET_OBJECT_NAME(buttonBox);
KDAB_SET_OBJECT_NAME(vlay);
createdLW.addItems(created);
QRect r;
for (int i = 0; i < created.size(); ++i) {
r = r.united(createdLW.visualRect(createdLW.model()->index(0, i)));
}
createdLW.setMinimumWidth(qMin(1024, r.width() + 4 * createdLW.frameWidth()));
errorsLW.addItems(errors);
vlay.addWidget(&createdLB);
vlay.addWidget(&createdLW, 1);
vlay.addWidget(&errorsLB);
vlay.addWidget(&errorsLW, 1);
vlay.addWidget(&buttonBox);
if (created.empty()) {
createdLW.hide();
}
if (errors.empty()) {
errorsLW.hide();
}
connect(&buttonBox, &QDialogButtonBox::accepted, this, &ResultDialog::accept);
connect(&buttonBox, &QDialogButtonBox::rejected, this, &ResultDialog::reject);
readConfig();
}
~ResultDialog() override
{
writeConfig();
}
void readConfig()
{
KConfigGroup dialog(KSharedConfig::openStateConfig(), "ResultDialog");
const QSize size = dialog.readEntry("Size", QSize(600, 400));
if (size.isValid()) {
resize(size);
}
}
void writeConfig()
{
KConfigGroup dialog(KSharedConfig::openStateConfig(), "ResultDialog");
dialog.writeEntry("Size", size());
dialog.sync();
}
private:
QLabel createdLB;
QListWidget createdLW;
QLabel errorsLB;
QListWidget errorsLW;
QDialogButtonBox buttonBox;
QVBoxLayout vlay;
};
}
static QStringList fs_sort(QStringList l)
{
std::sort(l.begin(), l.end(), [](const QString &lhs, const QString &rhs) {
- return QString::compare(lhs, rhs, fs_cs) < 0;
+ return QString::compare(lhs, rhs, ChecksumsUtils::fs_cs) < 0;
});
return l;
}
static QStringList fs_intersect(QStringList l1, QStringList l2)
{
fs_sort(l1);
fs_sort(l2);
QStringList result;
std::set_intersection(l1.begin(), l1.end(),
l2.begin(), l2.end(),
std::back_inserter(result),
[](const QString &lhs, const QString &rhs) {
- return QString::compare(lhs, rhs, fs_cs) < 0;
+ return QString::compare(lhs, rhs, ChecksumsUtils::fs_cs) < 0;
});
return result;
}
class CreateChecksumsController::Private : public QThread
{
Q_OBJECT
friend class ::Kleo::Crypto::CreateChecksumsController;
CreateChecksumsController *const q;
public:
explicit Private(CreateChecksumsController *qq);
~Private() override;
Q_SIGNALS:
void progress(int, int, const QString &);
private:
void slotOperationFinished()
{
#ifndef QT_NO_PROGRESSDIALOG
if (progressDialog) {
progressDialog->setValue(progressDialog->maximum());
progressDialog->close();
}
#endif // QT_NO_PROGRESSDIALOG
auto const dlg = new ResultDialog(created, errors);
dlg->setAttribute(Qt::WA_DeleteOnClose);
q->bringToForeground(dlg);
if (!errors.empty())
q->setLastError(gpg_error(GPG_ERR_GENERAL),
errors.join(QLatin1Char('\n')));
q->emitDoneOrError();
}
void slotProgress(int current, int total, const QString &what)
{
qCDebug(KLEOPATRA_LOG) << "progress: " << current << "/" << total << ": " << qPrintable(what);
#ifndef QT_NO_PROGRESSDIALOG
if (!progressDialog) {
return;
}
progressDialog->setMaximum(total);
progressDialog->setValue(current);
progressDialog->setLabelText(what);
#endif // QT_NO_PROGRESSDIALOG
}
private:
void run() override;
private:
#ifndef QT_NO_PROGRESSDIALOG
QPointer<QProgressDialog> progressDialog;
#endif
mutable QMutex mutex;
const std::vector< std::shared_ptr<ChecksumDefinition> > checksumDefinitions;
std::shared_ptr<ChecksumDefinition> checksumDefinition;
QStringList files;
QStringList errors, created;
bool allowAddition;
volatile bool canceled;
};
CreateChecksumsController::Private::Private(CreateChecksumsController *qq)
: q(qq),
#ifndef QT_NO_PROGRESSDIALOG
progressDialog(),
#endif
mutex(),
checksumDefinitions(ChecksumDefinition::getChecksumDefinitions()),
checksumDefinition(ChecksumDefinition::getDefaultChecksumDefinition(checksumDefinitions)),
files(),
errors(),
created(),
allowAddition(false),
canceled(false)
{
connect(this, SIGNAL(progress(int,int,QString)),
q, SLOT(slotProgress(int,int,QString)));
connect(this, &Private::progress,
q, &Controller::progress);
connect(this, SIGNAL(finished()),
q, SLOT(slotOperationFinished()));
}
CreateChecksumsController::Private::~Private()
{
qCDebug(KLEOPATRA_LOG);
}
CreateChecksumsController::CreateChecksumsController(QObject *p)
: Controller(p), d(new Private(this))
{
}
CreateChecksumsController::CreateChecksumsController(const std::shared_ptr<const ExecutionContext> &ctx, QObject *p)
: Controller(ctx, p), d(new Private(this))
{
}
CreateChecksumsController::~CreateChecksumsController()
{
qCDebug(KLEOPATRA_LOG);
}
void CreateChecksumsController::setFiles(const QStringList &files)
{
kleo_assert(!d->isRunning());
kleo_assert(!files.empty());
- const std::vector<QRegularExpression> patterns = get_patterns(d->checksumDefinitions);
- if (!std::all_of(files.cbegin(), files.cend(), matches_any(patterns)) &&
- !std::none_of(files.cbegin(), files.cend(), matches_any(patterns))) {
+ const std::vector<QRegularExpression> patterns = ChecksumsUtils::get_patterns(d->checksumDefinitions);
+ if (!std::all_of(files.cbegin(), files.cend(), ChecksumsUtils::matches_any(patterns)) &&
+ !std::none_of(files.cbegin(), files.cend(), ChecksumsUtils::matches_any(patterns))) {
throw Exception(gpg_error(GPG_ERR_INV_ARG), i18n("Create Checksums: input files must be either all checksum files or all files to be checksummed, not a mixture of both."));
}
const QMutexLocker locker(&d->mutex);
d->files = files;
}
void CreateChecksumsController::setAllowAddition(bool allow)
{
kleo_assert(!d->isRunning());
const QMutexLocker locker(&d->mutex);
d->allowAddition = allow;
}
bool CreateChecksumsController::allowAddition() const
{
const QMutexLocker locker(&d->mutex);
return d->allowAddition;
}
void CreateChecksumsController::start()
{
{
const QMutexLocker locker(&d->mutex);
#ifndef QT_NO_PROGRESSDIALOG
d->progressDialog = new QProgressDialog(i18n("Initializing..."), i18n("Cancel"), 0, 0);
applyWindowID(d->progressDialog);
d->progressDialog->setAttribute(Qt::WA_DeleteOnClose);
d->progressDialog->setMinimumDuration(1000);
d->progressDialog->setWindowTitle(i18nc("@title:window", "Create Checksum Progress"));
connect(d->progressDialog.data(), &QProgressDialog::canceled, this, &CreateChecksumsController::cancel);
#endif // QT_NO_PROGRESSDIALOG
d->canceled = false;
d->errors.clear();
d->created.clear();
}
d->start();
}
void CreateChecksumsController::cancel()
{
qCDebug(KLEOPATRA_LOG);
const QMutexLocker locker(&d->mutex);
d->canceled = true;
}
namespace
{
struct Dir {
QDir dir;
QString sumFile;
QStringList inputFiles;
quint64 totalSize;
std::shared_ptr<ChecksumDefinition> checksumDefinition;
};
}
static QStringList remove_checksum_files(QStringList l, const std::vector<QRegularExpression> &rxs)
{
QStringList::iterator end = l.end();
for (const auto &rx : rxs) {
end = std::remove_if(l.begin(), end,
[rx](const QString &str) {
return rx.match(str).hasMatch();
});
}
l.erase(end, l.end());
return l;
}
static quint64 aggregate_size(const QDir &dir, const QStringList &files)
{
quint64 n = 0;
for (const QString &file : files) {
n += QFileInfo(dir.absoluteFilePath(file)).size();
}
return n;
}
static std::vector<Dir> find_dirs_by_sum_files(const QStringList &files, bool allowAddition,
const std::function<void(int)> &progress,
const std::vector< std::shared_ptr<ChecksumDefinition> > &checksumDefinitions)
{
- const std::vector<QRegularExpression> patterns = get_patterns(checksumDefinitions);
+ const std::vector<QRegularExpression> patterns = ChecksumsUtils::get_patterns(checksumDefinitions);
std::vector<Dir> dirs;
dirs.reserve(files.size());
int i = 0;
for (const QString &file : files) {
const QFileInfo fi(file);
const QDir dir = fi.dir();
const QStringList entries = remove_checksum_files(dir.entryList(QDir::Files), patterns);
QStringList inputFiles;
if (allowAddition) {
inputFiles = entries;
} else {
- const std::vector<File> parsed = parse_sum_file(fi.absoluteFilePath());
+ const std::vector<ChecksumsUtils::File> parsed = ChecksumsUtils::parse_sum_file(fi.absoluteFilePath());
QStringList oldInputFiles;
oldInputFiles.reserve(parsed.size());
std::transform(parsed.cbegin(), parsed.cend(), std::back_inserter(oldInputFiles),
- std::mem_fn(&File::name));
+ std::mem_fn(&ChecksumsUtils::File::name));
inputFiles = fs_intersect(oldInputFiles, entries);
}
const Dir item = {
dir,
fi.fileName(),
inputFiles,
aggregate_size(dir, inputFiles),
- filename2definition(fi.fileName(), checksumDefinitions)
+ ChecksumsUtils::filename2definition(fi.fileName(), checksumDefinitions)
};
dirs.push_back(item);
if (progress) {
progress(++i);
}
}
return dirs;
}
namespace
{
struct less_dir : std::binary_function<QDir, QDir, bool> {
bool operator()(const QDir &lhs, const QDir &rhs) const
{
- return QString::compare(lhs.absolutePath(), rhs.absolutePath(), fs_cs) < 0;
+ return QString::compare(lhs.absolutePath(), rhs.absolutePath(), ChecksumsUtils::fs_cs) < 0;
}
};
}
static std::vector<Dir> find_dirs_by_input_files(const QStringList &files, const std::shared_ptr<ChecksumDefinition> &checksumDefinition, bool allowAddition,
const std::function<void(int)> &progress,
const std::vector< std::shared_ptr<ChecksumDefinition> > &checksumDefinitions)
{
Q_UNUSED(allowAddition)
if (!checksumDefinition) {
return std::vector<Dir>();
}
- const std::vector<QRegularExpression> patterns = get_patterns(checksumDefinitions);
+ const std::vector<QRegularExpression> patterns = ChecksumsUtils::get_patterns(checksumDefinitions);
std::map<QDir, QStringList, less_dir> dirs2files;
// Step 1: sort files by the dir they're contained in:
std::deque<QString> inputs(files.begin(), files.end());
int i = 0;
while (!inputs.empty()) {
const QString file = inputs.front();
inputs.pop_front();
const QFileInfo fi(file);
if (fi.isDir()) {
QDir dir(file);
dirs2files[ dir ] = remove_checksum_files(dir.entryList(QDir::Files), patterns);
const auto entryList = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
std::transform(entryList.cbegin(), entryList.cend(),
std::inserter(inputs, inputs.begin()),
[&dir](const QString &entry) {
return dir.absoluteFilePath(entry);
});
} else {
dirs2files[fi.dir()].push_back(file);
}
if (progress) {
progress(++i);
}
}
// Step 2: convert into vector<Dir>:
std::vector<Dir> dirs;
dirs.reserve(dirs2files.size());
for (auto it = dirs2files.begin(), end = dirs2files.end(); it != end; ++it) {
const QStringList inputFiles = remove_checksum_files(it->second, patterns);
if (inputFiles.empty()) {
continue;
}
const Dir dir = {
it->first,
checksumDefinition->outputFileName(),
inputFiles,
aggregate_size(it->first, inputFiles),
checksumDefinition
};
dirs.push_back(dir);
if (progress) {
progress(++i);
}
}
return dirs;
}
static QString process(const Dir &dir, bool *fatal)
{
const QString absFilePath = dir.dir.absoluteFilePath(dir.sumFile);
QTemporaryFile out;
QProcess p;
if (!out.open()) {
return QStringLiteral("Failed to open Temporary file.");
}
p.setWorkingDirectory(dir.dir.absolutePath());
p.setStandardOutputFile(out.fileName());
const QString program = dir.checksumDefinition->createCommand();
dir.checksumDefinition->startCreateCommand(&p, dir.inputFiles);
p.waitForFinished();
qCDebug(KLEOPATRA_LOG) << "[" << &p << "] Exit code " << p.exitCode();
if (p.exitStatus() != QProcess::NormalExit || p.exitCode() != 0) {
if (fatal && p.error() == QProcess::FailedToStart) {
*fatal = true;
}
if (p.error() == QProcess::UnknownError)
return i18n("Error while running %1: %2", program,
QString::fromLocal8Bit(p.readAllStandardError().trimmed().constData()));
else {
return i18n("Failed to execute %1: %2", program, p.errorString());
}
}
QFileInfo fi(absFilePath);
if (!(fi.exists() && !QFile::remove(absFilePath)) && QFile::copy(out.fileName(), absFilePath)) {
return QString();
}
return xi18n("Failed to overwrite <filename>%1</filename>.", dir.sumFile);
}
namespace
{
static QDebug operator<<(QDebug s, const Dir &dir)
{
return s << "Dir(" << dir.dir << "->" << dir.sumFile << "<-(" << dir.totalSize << ')' << dir.inputFiles << ")\n";
}
}
void CreateChecksumsController::Private::run()
{
QMutexLocker locker(&mutex);
const QStringList files = this->files;
const std::vector< std::shared_ptr<ChecksumDefinition> > checksumDefinitions = this->checksumDefinitions;
const std::shared_ptr<ChecksumDefinition> checksumDefinition = this->checksumDefinition;
const bool allowAddition = this->allowAddition;
locker.unlock();
QStringList errors;
QStringList created;
if (!checksumDefinition) {
errors.push_back(i18n("No checksum programs defined."));
locker.relock();
this->errors = errors;
return;
} else {
qCDebug(KLEOPATRA_LOG) << "using checksum-definition" << checksumDefinition->id();
}
//
// Step 1: build a list of work to do (no progress):
//
const QString scanning = i18n("Scanning directories...");
Q_EMIT progress(0, 0, scanning);
- const bool haveSumFiles = std::all_of(files.cbegin(), files.cend(), matches_any(get_patterns(checksumDefinitions)));
+ const bool haveSumFiles = std::all_of(files.cbegin(), files.cend(), ChecksumsUtils::matches_any(ChecksumsUtils::get_patterns(checksumDefinitions)));
const auto progressCb = [this, &scanning](int c) { Q_EMIT progress(c, 0, scanning); };
const std::vector<Dir> dirs = haveSumFiles
? find_dirs_by_sum_files(files, allowAddition, progressCb, checksumDefinitions)
: find_dirs_by_input_files(files, checksumDefinition, allowAddition, progressCb, checksumDefinitions);
for (const Dir &dir : dirs) {
qCDebug(KLEOPATRA_LOG) << dir;
}
if (!canceled) {
Q_EMIT progress(0, 0, i18n("Calculating total size..."));
const quint64 total = kdtools::accumulate_transform(dirs.cbegin(), dirs.cend(),
std::mem_fn(&Dir::totalSize),
Q_UINT64_C(0));
if (!canceled) {
//
// Step 2: perform work (with progress reporting):
//
// re-scale 'total' to fit into ints (wish QProgressDialog would use quint64...)
const quint64 factor = total / std::numeric_limits<int>::max() + 1;
quint64 done = 0;
for (const Dir &dir : dirs) {
Q_EMIT progress(done / factor, total / factor,
i18n("Checksumming (%2) in %1", dir.checksumDefinition->label(), dir.dir.path()));
bool fatal = false;
const QString error = process(dir, &fatal);
if (!error.isEmpty()) {
errors.push_back(error);
} else {
created.push_back(dir.dir.absoluteFilePath(dir.sumFile));
}
done += dir.totalSize;
if (fatal || canceled) {
break;
}
}
Q_EMIT progress(done / factor, total / factor, i18n("Done."));
}
}
locker.relock();
this->errors = errors;
this->created = created;
// mutex unlocked by QMutexLocker
}
#include "moc_createchecksumscontroller.cpp"
#include "createchecksumscontroller.moc"
diff --git a/src/crypto/verifychecksumscontroller.cpp b/src/crypto/verifychecksumscontroller.cpp
index e84f307b8..25f8edf3a 100644
--- a/src/crypto/verifychecksumscontroller.cpp
+++ b/src/crypto/verifychecksumscontroller.cpp
@@ -1,586 +1,587 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/verifychecksumscontroller.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-kleopatra.h>
#include "verifychecksumscontroller.h"
#include "checksumsutils_p.h"
#ifndef QT_NO_DIRMODEL
#include <crypto/gui/verifychecksumsdialog.h>
#include <utils/input.h>
#include <utils/output.h>
#include <utils/kleo_assert.h>
#include <Libkleo/Stl_Util>
+#include <Libkleo/ChecksumDefinition>
#include <Libkleo/Classify>
#include <KLocalizedString>
#include <QPointer>
#include <QFileInfo>
#include <QThread>
#include <QMutex>
#include <QProgressDialog>
#include <QDir>
#include <QProcess>
#include <gpg-error.h>
#include <deque>
#include <limits>
#include <set>
using namespace Kleo;
using namespace Kleo::Crypto;
using namespace Kleo::Crypto::Gui;
static const QLatin1String CHECKSUM_DEFINITION_ID_ENTRY("checksum-definition-id");
#if 0
static QStringList fs_sort(QStringList l)
{
int (*QString_compare)(const QString &, const QString &, Qt::CaseSensitivity) = &QString::compare;
std::sort(l.begin(), l.end(),
[](const QString &lhs, const QString &rhs) {
- return QString::compare(lhs, rhs, fs_cs) < 0;
+ return QString::compare(lhs, rhs, ChecksumsUtils::fs_cs) < 0;
});
return l;
}
static QStringList fs_intersect(QStringList l1, QStringList l2)
{
int (*QString_compare)(const QString &, const QString &, Qt::CaseSensitivity) = &QString::compare;
fs_sort(l1);
fs_sort(l2);
QStringList result;
std::set_intersection(l1.begin(), l1.end(),
l2.begin(), l2.end(),
std::back_inserter(result),
[](const QString &lhs, const QString &rhs) {
- return QString::compare(lhs, rhs, fs_cs) < 0;
+ return QString::compare(lhs, rhs, ChecksumsUtils::fs_cs) < 0;
});
return result;
}
#endif
namespace {
struct matches_none_of : std::unary_function<QString, bool> {
const std::vector<QRegularExpression> m_regexps;
explicit matches_none_of(const std::vector<QRegularExpression> &regexps) : m_regexps(regexps) {}
bool operator()(const QString &s) const
{
return std::none_of(m_regexps.cbegin(), m_regexps.cend(),
[&s](const QRegularExpression &rx) { return rx.match(s).hasMatch(); });
}
};
}
class VerifyChecksumsController::Private : public QThread
{
Q_OBJECT
friend class ::Kleo::Crypto::VerifyChecksumsController;
VerifyChecksumsController *const q;
public:
explicit Private(VerifyChecksumsController *qq);
~Private() override;
Q_SIGNALS:
void baseDirectories(const QStringList &);
void progress(int, int, const QString &);
void status(const QString &file, Kleo::Crypto::Gui::VerifyChecksumsDialog::Status);
private:
void slotOperationFinished()
{
if (dialog) {
dialog->setProgress(100, 100);
dialog->setErrors(errors);
}
if (!errors.empty())
q->setLastError(gpg_error(GPG_ERR_GENERAL),
errors.join(QLatin1Char('\n')));
q->emitDoneOrError();
}
private:
void run() override;
private:
QPointer<VerifyChecksumsDialog> dialog;
mutable QMutex mutex;
const std::vector< std::shared_ptr<ChecksumDefinition> > checksumDefinitions;
QStringList files;
QStringList errors;
volatile bool canceled;
};
VerifyChecksumsController::Private::Private(VerifyChecksumsController *qq)
: q(qq),
dialog(),
mutex(),
checksumDefinitions(ChecksumDefinition::getChecksumDefinitions()),
files(),
errors(),
canceled(false)
{
connect(this, &Private::progress,
q, &Controller::progress);
connect(this, SIGNAL(finished()),
q, SLOT(slotOperationFinished()));
}
VerifyChecksumsController::Private::~Private()
{
qCDebug(KLEOPATRA_LOG);
}
VerifyChecksumsController::VerifyChecksumsController(QObject *p)
: Controller(p), d(new Private(this))
{
}
VerifyChecksumsController::VerifyChecksumsController(const std::shared_ptr<const ExecutionContext> &ctx, QObject *p)
: Controller(ctx, p), d(new Private(this))
{
}
VerifyChecksumsController::~VerifyChecksumsController()
{
qCDebug(KLEOPATRA_LOG);
}
void VerifyChecksumsController::setFiles(const QStringList &files)
{
kleo_assert(!d->isRunning());
kleo_assert(!files.empty());
const QMutexLocker locker(&d->mutex);
d->files = files;
}
void VerifyChecksumsController::start()
{
{
const QMutexLocker locker(&d->mutex);
d->dialog = new VerifyChecksumsDialog;
d->dialog->setAttribute(Qt::WA_DeleteOnClose);
d->dialog->setWindowTitle(i18nc("@title:window", "Verify Checksum Results"));
connect(d->dialog.data(), &VerifyChecksumsDialog::canceled,
this, &VerifyChecksumsController::cancel);
connect(d.get(), &Private::baseDirectories,
d->dialog.data(), &VerifyChecksumsDialog::setBaseDirectories);
connect(d.get(), &Private::progress,
d->dialog.data(), &VerifyChecksumsDialog::setProgress);
connect(d.get(), &Private::status,
d->dialog.data(), &VerifyChecksumsDialog::setStatus);
d->canceled = false;
d->errors.clear();
}
d->start();
d->dialog->show();
}
void VerifyChecksumsController::cancel()
{
qCDebug(KLEOPATRA_LOG);
const QMutexLocker locker(&d->mutex);
d->canceled = true;
}
namespace
{
struct SumFile {
QDir dir;
QString sumFile;
quint64 totalSize;
std::shared_ptr<ChecksumDefinition> checksumDefinition;
};
}
static QStringList filter_checksum_files(QStringList l, const std::vector<QRegularExpression> &rxs)
{
l.erase(std::remove_if(l.begin(), l.end(),
matches_none_of(rxs)),
l.end());
return l;
}
static quint64 aggregate_size(const QDir &dir, const QStringList &files)
{
quint64 n = 0;
for (const QString &file : files) {
n += QFileInfo(dir.absoluteFilePath(file)).size();
}
return n;
}
namespace
{
struct less_dir : std::binary_function<QDir, QDir, bool> {
bool operator()(const QDir &lhs, const QDir &rhs) const
{
- return QString::compare(lhs.absolutePath(), rhs.absolutePath(), fs_cs) < 0;
+ return QString::compare(lhs.absolutePath(), rhs.absolutePath(), ChecksumsUtils::fs_cs) < 0;
}
};
struct less_file : std::binary_function<QString, QString, bool> {
bool operator()(const QString &lhs, const QString &rhs) const
{
- return QString::compare(lhs, rhs, fs_cs) < 0;
+ return QString::compare(lhs, rhs, ChecksumsUtils::fs_cs) < 0;
}
};
struct sumfile_contains_file : std::unary_function<QString, bool> {
const QDir dir;
const QString fileName;
sumfile_contains_file(const QDir &dir_, const QString &fileName_)
: dir(dir_), fileName(fileName_) {}
bool operator()(const QString &sumFile) const
{
- const std::vector<File> files = parse_sum_file(dir.absoluteFilePath(sumFile));
+ const std::vector<ChecksumsUtils::File> files = ChecksumsUtils::parse_sum_file(dir.absoluteFilePath(sumFile));
qCDebug(KLEOPATRA_LOG) << "find_sums_by_input_files: found " << files.size()
<< " files listed in " << qPrintable(dir.absoluteFilePath(sumFile));
- for (const File &file : files) {
- const bool isSameFileName = (QString::compare(file.name, fileName, fs_cs) == 0);
+ for (const ChecksumsUtils::File &file : files) {
+ const bool isSameFileName = (QString::compare(file.name, fileName, ChecksumsUtils::fs_cs) == 0);
qCDebug(KLEOPATRA_LOG) << "find_sums_by_input_files: "
<< qPrintable(file.name) << " == "
<< qPrintable(fileName) << " ? "
<< isSameFileName;
if (isSameFileName) {
return true;
}
}
return false;
}
};
}
// IF is_dir(file)
// add all sumfiles \in dir(file)
// inputs.prepend( all dirs \in dir(file) )
// ELSE IF is_sum_file(file)
// add
// ELSE IF \exists sumfile in dir(file) \where sumfile \contains file
// add sumfile
// ELSE
// error: no checksum found for "file"
static QStringList find_base_directories(const QStringList &files)
{
// Step 1: find base dirs:
std::set<QDir, less_dir> dirs;
for (const QString &file : files) {
const QFileInfo fi(file);
const QDir dir = fi.isDir() ? QDir(file) : fi.dir();
dirs.insert(dir);
}
// Step 1a: collapse direct child directories
bool changed;
do {
changed = false;
auto it = dirs.begin();
while (it != dirs.end()) {
QDir dir = *it;
if (dir.cdUp() && dirs.count(dir)) {
dirs.erase(it++);
changed = true;
} else {
++it;
}
}
} while (changed);
QStringList rv;
rv.reserve(dirs.size());
std::transform(dirs.cbegin(), dirs.cend(), std::back_inserter(rv), std::mem_fn(&QDir::absolutePath));
return rv;
}
static std::vector<SumFile> find_sums_by_input_files(const QStringList &files, QStringList &errors,
const std::function<void(int)> &progress,
const std::vector< std::shared_ptr<ChecksumDefinition> > &checksumDefinitions)
{
- const std::vector<QRegularExpression> patterns = get_patterns(checksumDefinitions);
+ const std::vector<QRegularExpression> patterns = ChecksumsUtils::get_patterns(checksumDefinitions);
- const matches_any is_sum_file(patterns);
+ const ChecksumsUtils::matches_any is_sum_file(patterns);
std::map<QDir, std::set<QString, less_file>, less_dir> dirs2sums;
// Step 1: find the sumfiles we need to check:
std::deque<QString> inputs(files.begin(), files.end());
int i = 0;
while (!inputs.empty()) {
const QString file = inputs.front();
qCDebug(KLEOPATRA_LOG) << "find_sums_by_input_files: considering " << qPrintable(file);
inputs.pop_front();
const QFileInfo fi(file);
const QString fileName = fi.fileName();
if (fi.isDir()) {
qCDebug(KLEOPATRA_LOG) << "find_sums_by_input_files: it's a directory";
QDir dir(file);
const QStringList sumfiles = filter_checksum_files(dir.entryList(QDir::Files), patterns);
qCDebug(KLEOPATRA_LOG) << "find_sums_by_input_files: found " << sumfiles.size()
<< " sum files: " << qPrintable(sumfiles.join(QLatin1String(", ")));
dirs2sums[ dir ].insert(sumfiles.begin(), sumfiles.end());
const QStringList dirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
qCDebug(KLEOPATRA_LOG) << "find_sums_by_input_files: found " << dirs.size()
<< " subdirs, prepending";
std::transform(dirs.cbegin(), dirs.cend(),
std::inserter(inputs, inputs.begin()),
[&dir](const QString &path) {
return dir.absoluteFilePath(path);
});
} else if (is_sum_file(fileName)) {
qCDebug(KLEOPATRA_LOG) << "find_sums_by_input_files: it's a sum file";
dirs2sums[fi.dir()].insert(fileName);
} else {
qCDebug(KLEOPATRA_LOG) << "find_sums_by_input_files: it's something else; checking whether we'll find a sumfile for it...";
const QDir dir = fi.dir();
const QStringList sumfiles = filter_checksum_files(dir.entryList(QDir::Files), patterns);
qCDebug(KLEOPATRA_LOG) << "find_sums_by_input_files: found " << sumfiles.size()
<< " potential sumfiles: " << qPrintable(sumfiles.join(QLatin1String(", ")));
const auto it = std::find_if(sumfiles.cbegin(), sumfiles.cend(),
sumfile_contains_file(dir, fileName));
if (it == sumfiles.end()) {
errors.push_back(i18n("Cannot find checksums file for file %1", file));
} else {
dirs2sums[dir].insert(*it);
}
}
if (progress) {
progress(++i);
}
}
// Step 2: convert into vector<SumFile>:
std::vector<SumFile> sumfiles;
sumfiles.reserve(dirs2sums.size());
for (auto it = dirs2sums.begin(), end = dirs2sums.end(); it != end; ++it) {
if (it->second.empty()) {
continue;
}
const QDir &dir = it->first;
for (const QString &sumFileName : std::as_const(it->second)) {
- const std::vector<File> summedfiles = parse_sum_file(dir.absoluteFilePath(sumFileName));
+ const std::vector<ChecksumsUtils::File> summedfiles = ChecksumsUtils::parse_sum_file(dir.absoluteFilePath(sumFileName));
QStringList files;
files.reserve(summedfiles.size());
std::transform(summedfiles.cbegin(), summedfiles.cend(),
- std::back_inserter(files), std::mem_fn(&File::name));
+ std::back_inserter(files), std::mem_fn(&ChecksumsUtils::File::name));
const SumFile sumFile = {
it->first,
sumFileName,
aggregate_size(it->first, files),
- filename2definition(sumFileName, checksumDefinitions),
+ ChecksumsUtils::filename2definition(sumFileName, checksumDefinitions),
};
sumfiles.push_back(sumFile);
}
if (progress) {
progress(++i);
}
}
return sumfiles;
}
static QStringList c_lang_environment()
{
- static const QRegularExpression re(QRegularExpression::anchoredPattern(u"LANG=.*"), s_regex_cs);
+ static const QRegularExpression re(QRegularExpression::anchoredPattern(u"LANG=.*"), ChecksumsUtils::s_regex_cs);
QStringList env = QProcess::systemEnvironment();
env.erase(std::remove_if(env.begin(), env.end(),
[](const QString &str) {
return re.match(str).hasMatch();
}),
env.end());
env.push_back(QStringLiteral("LANG=C"));
return env;
}
static const struct {
const char *string;
VerifyChecksumsDialog::Status status;
} statusStrings[] = {
{ "OK", VerifyChecksumsDialog::OK },
{ "FAILED", VerifyChecksumsDialog::Failed },
};
static const size_t numStatusStrings = sizeof statusStrings / sizeof * statusStrings;
static VerifyChecksumsDialog::Status string2status(const QByteArray &str)
{
for (unsigned int i = 0; i < numStatusStrings; ++i)
if (str == statusStrings[i].string) {
return statusStrings[i].status;
}
return VerifyChecksumsDialog::Unknown;
}
static QString process(const SumFile &sumFile, bool *fatal, const QStringList &env,
const std::function<void(const QString &, VerifyChecksumsDialog::Status)> &status)
{
QProcess p;
p.setEnvironment(env);
p.setWorkingDirectory(sumFile.dir.absolutePath());
p.setReadChannel(QProcess::StandardOutput);
const QString absFilePath = sumFile.dir.absoluteFilePath(sumFile.sumFile);
const QString program = sumFile.checksumDefinition->verifyCommand();
sumFile.checksumDefinition->startVerifyCommand(&p, QStringList(absFilePath));
QByteArray remainder; // used for filenames with newlines in them
while (p.state() != QProcess::NotRunning) {
p.waitForReadyRead();
while (p.canReadLine()) {
const QByteArray line = p.readLine();
const int colonIdx = line.lastIndexOf(':');
if (colonIdx < 0) {
remainder += line; // no colon -> probably filename with a newline
continue;
}
const QString file = QFile::decodeName(remainder + line.left(colonIdx));
remainder.clear();
const VerifyChecksumsDialog::Status result = string2status(line.mid(colonIdx + 1).trimmed());
status(sumFile.dir.absoluteFilePath(file), result);
}
}
qCDebug(KLEOPATRA_LOG) << "[" << &p << "] Exit code " << p.exitCode();
if (p.exitStatus() != QProcess::NormalExit || p.exitCode() != 0) {
if (fatal && p.error() == QProcess::FailedToStart) {
*fatal = true;
}
if (p.error() == QProcess::UnknownError)
return i18n("Error while running %1: %2", program,
QString::fromLocal8Bit(p.readAllStandardError().trimmed().constData()));
else {
return i18n("Failed to execute %1: %2", program, p.errorString());
}
}
return QString();
}
namespace
{
static QDebug operator<<(QDebug s, const SumFile &sum)
{
return s << "SumFile(" << sum.dir << "->" << sum.sumFile << "<-(" << sum.totalSize << ')' << ")\n";
}
}
void VerifyChecksumsController::Private::run()
{
QMutexLocker locker(&mutex);
const QStringList files = this->files;
const std::vector< std::shared_ptr<ChecksumDefinition> > checksumDefinitions = this->checksumDefinitions;
locker.unlock();
QStringList errors;
//
// Step 0: find base directories:
//
Q_EMIT baseDirectories(find_base_directories(files));
//
// Step 1: build a list of work to do (no progress):
//
const QString scanning = i18n("Scanning directories...");
Q_EMIT progress(0, 0, scanning);
const auto progressCb = [this, scanning](int arg) { Q_EMIT progress(arg, 0, scanning); };
const auto statusCb = [this](const QString &str, VerifyChecksumsDialog::Status st) { Q_EMIT status(str, st); };
const std::vector<SumFile> sumfiles = find_sums_by_input_files(files, errors, progressCb, checksumDefinitions);
for (const SumFile &sumfile : sumfiles) {
qCDebug(KLEOPATRA_LOG) << sumfile;
}
if (!canceled) {
Q_EMIT progress(0, 0, i18n("Calculating total size..."));
const quint64 total
= kdtools::accumulate_transform(sumfiles.cbegin(), sumfiles.cend(),
std::mem_fn(&SumFile::totalSize), Q_UINT64_C(0));
if (!canceled) {
//
// Step 2: perform work (with progress reporting):
//
const QStringList env = c_lang_environment();
// re-scale 'total' to fit into ints (wish QProgressDialog would use quint64...)
const quint64 factor = total / std::numeric_limits<int>::max() + 1;
quint64 done = 0;
for (const SumFile &sumFile : sumfiles) {
Q_EMIT progress(done / factor, total / factor,
i18n("Verifying checksums (%2) in %1", sumFile.checksumDefinition->label(), sumFile.dir.path()));
bool fatal = false;
const QString error = process(sumFile, &fatal, env, statusCb);
if (!error.isEmpty()) {
errors.push_back(error);
}
done += sumFile.totalSize;
if (fatal || canceled) {
break;
}
}
Q_EMIT progress(done / factor, total / factor, i18n("Done."));
}
}
locker.relock();
this->errors = errors;
// mutex unlocked by QMutexLocker
}
#include "moc_verifychecksumscontroller.cpp"
#include "verifychecksumscontroller.moc"
#endif // QT_NO_DIRMODEL

File Metadata

Mime Type
text/x-diff
Expires
Sun, Jan 4, 5:40 AM (1 d, 21 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
fd/05/9230823b585e4d0b838b4d19b330

Event Timeline