Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F36623903
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
114 KB
Subscribers
None
View Options
diff --git a/src/commands/dumpcrlcachecommand.cpp b/src/commands/dumpcrlcachecommand.cpp
index a94c3aab4..268ad6827 100644
--- a/src/commands/dumpcrlcachecommand.cpp
+++ b/src/commands/dumpcrlcachecommand.cpp
@@ -1,351 +1,351 @@
/* -*- mode: c++; c-basic-offset:4 -*-
commands/dumpcrlcachecommand.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-kleopatra.h>
#include "dumpcrlcachecommand.h"
#include "command_p.h"
#include <Libkleo/GnuPG>
#include <KProcess>
#include <KMessageBox>
#include <KLocalizedString>
#include <QPushButton>
#include <KStandardGuiItem>
#include <KConfigGroup>
#include <QString>
#include <QByteArray>
#include <QTimer>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <KSharedConfig>
#include <QFontDatabase>
#include <QTextEdit>
static const int PROCESS_TERMINATE_TIMEOUT = 5000; // milliseconds
namespace
{
class DumpCrlCacheDialog : public QDialog
{
Q_OBJECT
public:
explicit DumpCrlCacheDialog(QWidget *parent = nullptr)
: QDialog(parent), ui(this), mWithRevocations(false)
{
readConfig();
}
~DumpCrlCacheDialog()
{
writeConfig();
}
Q_SIGNALS:
void updateRequested();
public Q_SLOTS:
void append(const QString &line)
{
ui.logTextWidget.append(line);
ui.logTextWidget.ensureCursorVisible();
}
void clear()
{
ui.logTextWidget.clear();
}
public:
void setWithRevocations (bool value) {
mWithRevocations = value;
}
Q_REQUIRED_RESULT bool withRevocations () {
return mWithRevocations;
}
private:
void readConfig()
{
- KConfigGroup dialog(KSharedConfig::openConfig(), "DumpCrlCacheDialog");
+ KConfigGroup dialog(KSharedConfig::openStateConfig(), "DumpCrlCacheDialog");
const QSize size = dialog.readEntry("Size", QSize(600, 400));
if (size.isValid()) {
resize(size);
}
}
void writeConfig()
{
- KConfigGroup dialog(KSharedConfig::openConfig(), "DumpCrlCacheDialog");
+ KConfigGroup dialog(KSharedConfig::openStateConfig(), "DumpCrlCacheDialog");
dialog.writeEntry("Size", size());
dialog.sync();
}
struct Ui {
QTextEdit logTextWidget;
QPushButton updateButton, closeButton, revocationsButton;
QVBoxLayout vlay;
QHBoxLayout hlay;
explicit Ui(DumpCrlCacheDialog *q)
: logTextWidget(q),
updateButton(i18nc("@action:button Update the log text widget", "&Update"), q),
closeButton(q),
vlay(q),
hlay()
{
KGuiItem::assign(&closeButton, KStandardGuiItem::close());
KDAB_SET_OBJECT_NAME(logTextWidget);
KDAB_SET_OBJECT_NAME(updateButton);
KDAB_SET_OBJECT_NAME(closeButton);
KDAB_SET_OBJECT_NAME(vlay);
KDAB_SET_OBJECT_NAME(hlay);
logTextWidget.setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
logTextWidget.setReadOnly(true);
vlay.addWidget(&logTextWidget, 1);
vlay.addLayout(&hlay);
revocationsButton.setText(i18n("Show Entries"));
hlay.addWidget(&updateButton);
hlay.addWidget(&revocationsButton);
hlay.addStretch(1);
hlay.addWidget(&closeButton);
connect(&updateButton, &QAbstractButton::clicked,
q, &DumpCrlCacheDialog::updateRequested);
connect(&closeButton, &QAbstractButton::clicked,
q, &QWidget::close);
connect(&revocationsButton, &QAbstractButton::clicked,
q, [q, this] () {
q->mWithRevocations = true;
revocationsButton.setEnabled(false);
q->updateRequested();
});
}
} ui;
bool mWithRevocations;
};
}
using namespace Kleo;
using namespace Kleo::Commands;
static QByteArray chomped(QByteArray ba)
{
while (ba.endsWith('\n') || ba.endsWith('\r')) {
ba.chop(1);
}
return ba;
}
class DumpCrlCacheCommand::Private : Command::Private
{
friend class ::Kleo::Commands::DumpCrlCacheCommand;
DumpCrlCacheCommand *q_func() const
{
return static_cast<DumpCrlCacheCommand *>(q);
}
public:
explicit Private(DumpCrlCacheCommand *qq, KeyListController *c);
~Private();
QString errorString() const
{
return QString::fromLocal8Bit(errorBuffer);
}
private:
void init();
void refreshView();
private:
void slotProcessFinished(int, QProcess::ExitStatus);
void slotProcessReadyReadStandardOutput()
{
static int count;
while (process.canReadLine()) {
if (!dialog) {
break;
}
const QByteArray line = chomped(process.readLine());
if (!line.size()) {
continue;
}
if (!dialog->withRevocations() && line.contains("reasons")) {
count++;
continue;
} else if (count) {
dialog->append (QLatin1Char(' ') +
i18nc("Count of revocations in a CRL",
"Entries:") + QStringLiteral("\t\t%1\n").arg(count));
count = 0;
}
dialog->append(stringFromGpgOutput(line));
}
}
void slotProcessReadyReadStandardError()
{
errorBuffer += process.readAllStandardError();
}
void slotUpdateRequested()
{
if (process.state() == QProcess::NotRunning) {
refreshView();
}
}
void slotDialogDestroyed()
{
dialog = nullptr;
if (process.state() != QProcess::NotRunning) {
q->cancel();
} else {
finished();
}
}
private:
DumpCrlCacheDialog *dialog;
KProcess process;
QByteArray errorBuffer;
bool canceled;
};
DumpCrlCacheCommand::Private *DumpCrlCacheCommand::d_func()
{
return static_cast<Private *>(d.get());
}
const DumpCrlCacheCommand::Private *DumpCrlCacheCommand::d_func() const
{
return static_cast<const Private *>(d.get());
}
#define d d_func()
#define q q_func()
DumpCrlCacheCommand::Private::Private(DumpCrlCacheCommand *qq, KeyListController *c)
: Command::Private(qq, c),
dialog(nullptr),
process(),
errorBuffer(),
canceled(false)
{
process.setOutputChannelMode(KProcess::SeparateChannels);
process.setReadChannel(KProcess::StandardOutput);
process << gpgSmPath() << QStringLiteral("--call-dirmngr") << QStringLiteral("listcrls");
}
DumpCrlCacheCommand::Private::~Private()
{
if (dialog && !dialog->isVisible()) {
delete dialog;
}
}
DumpCrlCacheCommand::DumpCrlCacheCommand(KeyListController *c)
: Command(new Private(this, c))
{
d->init();
}
DumpCrlCacheCommand::DumpCrlCacheCommand(QAbstractItemView *v, KeyListController *c)
: Command(v, new Private(this, c))
{
d->init();
}
void DumpCrlCacheCommand::Private::init()
{
connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)),
q, SLOT(slotProcessFinished(int,QProcess::ExitStatus)));
connect(&process, SIGNAL(readyReadStandardError()),
q, SLOT(slotProcessReadyReadStandardError()));
connect(&process, SIGNAL(readyReadStandardOutput()),
q, SLOT(slotProcessReadyReadStandardOutput()));
}
DumpCrlCacheCommand::~DumpCrlCacheCommand() {}
void DumpCrlCacheCommand::doStart()
{
d->dialog = new DumpCrlCacheDialog;
d->dialog->setAttribute(Qt::WA_DeleteOnClose);
d->dialog->setWindowTitle(i18nc("@title:window", "CRL Cache Dump"));
connect(d->dialog, SIGNAL(updateRequested()),
this, SLOT(slotUpdateRequested()));
connect(d->dialog, SIGNAL(destroyed()),
this, SLOT(slotDialogDestroyed()));
d->refreshView();
}
void DumpCrlCacheCommand::Private::refreshView()
{
dialog->clear();
process.start();
if (process.waitForStarted()) {
dialog->show();
} else {
KMessageBox::error(dialog ? static_cast<QWidget *>(dialog) : parentWidgetOrView(),
i18n("Unable to start process gpgsm. "
"Please check your installation."),
i18n("Dump CRL Cache Error"));
finished();
}
}
void DumpCrlCacheCommand::doCancel()
{
d->canceled = true;
if (d->process.state() != QProcess::NotRunning) {
d->process.terminate();
QTimer::singleShot(PROCESS_TERMINATE_TIMEOUT, &d->process, &QProcess::kill);
}
if (d->dialog) {
d->dialog->close();
}
d->dialog = nullptr;
}
void DumpCrlCacheCommand::Private::slotProcessFinished(int code, QProcess::ExitStatus status)
{
if (!canceled) {
if (status == QProcess::CrashExit)
KMessageBox::error(dialog,
i18n("The GpgSM process that tried to dump the CRL cache "
"ended prematurely because of an unexpected error. "
"Please check the output of gpgsm --call-dirmngr listcrls for details."),
i18n("Dump CRL Cache Error"));
else if (code)
KMessageBox::error(dialog,
i18n("An error occurred while trying to dump the CRL cache. "
"The output from GpgSM was:\n%1", errorString()),
i18n("Dump CRL Cache Error"));
}
}
#undef d
#undef q
#include "moc_dumpcrlcachecommand.cpp"
#include "dumpcrlcachecommand.moc"
diff --git a/src/conf/configuredialog.cpp b/src/conf/configuredialog.cpp
index 63b5bd7aa..1e5a5a2a1 100644
--- a/src/conf/configuredialog.cpp
+++ b/src/conf/configuredialog.cpp
@@ -1,70 +1,70 @@
/*
configuredialog.cpp
This file is part of kleopatra
SPDX-FileCopyrightText: 2000 Espen Sand <espen@kde.org>
SPDX-FileCopyrightText: 2001-2002 Marc Mutz <mutz@kde.org>
SPDX-FileCopyrightText: 2004, 2008 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2016 Bundesamt für Sicherheit in der Informationstechnik
SPDX-FileContributor: Intevation GmbH
SPDX-License-Identifier: GPL-2.0-only
*/
#include "configuredialog.h"
#include <KConfig>
#include <KLocalizedString>
#include <KConfigGroup>
#include <KSharedConfig>
#if HAVE_KCMUTILS
# include <KCMultiDialog>
#else
# include "kleopageconfigdialog.h"
#endif
ConfigureDialog::ConfigureDialog(QWidget *parent)
#if HAVE_KCMUTILS
: KCMultiDialog(parent)
#else
: KleoPageConfigDialog(parent)
#endif
{
setFaceType(KPageDialog::List);
setWindowTitle(i18nc("@title:window", "Configure"));
addModule(QStringLiteral("kleopatra_config_dirserv"));
addModule(QStringLiteral("kleopatra_config_appear"));
addModule(QStringLiteral("kleopatra_config_cryptooperations"));
addModule(QStringLiteral("kleopatra_config_smimevalidation"));
addModule(QStringLiteral("kleopatra_config_gnupgsystem"));
// We store the minimum size of the dialog on hide, because otherwise
// the KCMultiDialog starts with the size of the first kcm, not
// the largest one. This way at least after the first showing of
// the largest kcm the size is kept.
- const KConfigGroup geometry(KSharedConfig::openConfig(), "Geometry");
+ const KConfigGroup geometry(KSharedConfig::openStateConfig(), "Geometry");
const int width = geometry.readEntry("ConfigureDialogWidth", 0);
const int height = geometry.readEntry("ConfigureDialogHeight", 0);
if (width != 0 && height != 0) {
setMinimumSize(width, height);
}
}
void ConfigureDialog::hideEvent(QHideEvent *e)
{
const QSize minSize = minimumSizeHint();
- KConfigGroup geometry(KSharedConfig::openConfig(), "Geometry");
+ KConfigGroup geometry(KSharedConfig::openStateConfig(), "Geometry");
geometry.writeEntry("ConfigureDialogWidth", minSize.width());
geometry.writeEntry("ConfigureDialogHeight", minSize.height());
#if HAVE_KCMUTILS
KCMultiDialog::hideEvent(e);
#else
KleoPageConfigDialog::hideEvent(e);
#endif
}
ConfigureDialog::~ConfigureDialog()
{
}
diff --git a/src/conf/groupsconfigdialog.cpp b/src/conf/groupsconfigdialog.cpp
index ff8e3698c..cae15fe78 100644
--- a/src/conf/groupsconfigdialog.cpp
+++ b/src/conf/groupsconfigdialog.cpp
@@ -1,113 +1,113 @@
/*
conf/groupsconfigdialog.h
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2021 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-kleopatra.h>
#include "groupsconfigdialog.h"
#include "groupsconfigpage.h"
#include <KConfigGroup>
#include <KGuiItem>
#include <KLocalizedString>
#include <KSharedConfig>
#include <KStandardGuiItem>
#include <QDialogButtonBox>
#include <QPushButton>
class GroupsConfigDialog::Private
{
friend class ::GroupsConfigDialog;
GroupsConfigDialog *const q;
GroupsConfigPage *configPage = nullptr;
bool changed = false;
public:
Private(GroupsConfigDialog *qq)
: q(qq)
, configPage(new GroupsConfigPage(qq))
{
restoreLayout();
}
~Private()
{
saveLayout();
}
private:
void saveLayout()
{
- KConfigGroup configGroup(KSharedConfig::openConfig(), "GroupsConfigDialog");
+ KConfigGroup configGroup(KSharedConfig::openStateConfig(), "GroupsConfigDialog");
configGroup.writeEntry("Size", q->size());
configGroup.sync();
}
void restoreLayout(const QSize &defaultSize = QSize())
{
- const KConfigGroup configGroup(KSharedConfig::openConfig(), "GroupsConfigDialog");
+ const KConfigGroup configGroup(KSharedConfig::openStateConfig(), "GroupsConfigDialog");
const QSize size = configGroup.readEntry("Size", defaultSize);
if (size.isValid()) {
q->resize(size);
}
}
};
GroupsConfigDialog::GroupsConfigDialog(QWidget *parent)
: KConfigDialog(parent, GroupsConfigDialog::dialogName(), /*config=*/ nullptr)
, d(new Private(this))
{
setWindowTitle(i18nc("@title:window", "Configure Groups"));
setFaceType(KPageDialog::Plain);
addPage(d->configPage, i18n("Groups"), /*pixmapName=*/ QString(), /*header=*/ QString(), /*manage=*/ false);
// there are no defaults to restore
buttonBox()->removeButton(buttonBox()->button(QDialogButtonBox::RestoreDefaults));
QPushButton *resetButton = buttonBox()->addButton(QDialogButtonBox::Reset);
KGuiItem::assign(resetButton, KStandardGuiItem::reset());
resetButton->setEnabled(false);
connect(buttonBox()->button(QDialogButtonBox::Reset), &QAbstractButton::clicked,
this, &GroupsConfigDialog::updateWidgets);
connect(d->configPage, &GroupsConfigPage::changed, this, [this] (bool state) {
d->changed = state;
updateButtons();
if (QPushButton *button = buttonBox()->button(QDialogButtonBox::Reset)) {
button->setEnabled(d->changed);
}
});
}
GroupsConfigDialog::~GroupsConfigDialog() = default;
QString GroupsConfigDialog::dialogName()
{
return QStringLiteral("Group Settings");
}
void GroupsConfigDialog::updateSettings()
{
d->configPage->save();
}
void GroupsConfigDialog::updateWidgets()
{
d->configPage->load();
}
bool GroupsConfigDialog::hasChanged()
{
return d->changed;
}
diff --git a/src/crypto/createchecksumscontroller.cpp b/src/crypto/createchecksumscontroller.cpp
index 6df947642..c794415b9 100644
--- a/src/crypto/createchecksumscontroller.cpp
+++ b/src/crypto/createchecksumscontroller.cpp
@@ -1,719 +1,719 @@
/* -*- 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 <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 "kleopatra_debug.h"
#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()
{
writeConfig();
}
void readConfig()
{
- KConfigGroup dialog(KSharedConfig::openConfig(), "ResultDialog");
+ KConfigGroup dialog(KSharedConfig::openStateConfig(), "ResultDialog");
const QSize size = dialog.readEntry("Size", QSize(600, 400));
if (size.isValid()) {
resize(size);
}
}
void writeConfig()
{
- KConfigGroup dialog(KSharedConfig::openConfig(), "ResultDialog");
+ KConfigGroup dialog(KSharedConfig::openStateConfig(), "ResultDialog");
dialog.writeEntry("Size", size());
dialog.sync();
}
private:
QLabel createdLB;
QListWidget createdLW;
QLabel errorsLB;
QListWidget errorsLW;
QDialogButtonBox buttonBox;
QVBoxLayout vlay;
};
}
#ifdef Q_OS_UNIX
static const bool HAVE_UNIX = true;
#else
static const bool HAVE_UNIX = false;
#endif
static const Qt::CaseSensitivity fs_cs = HAVE_UNIX ? Qt::CaseSensitive : Qt::CaseInsensitive; // can we use QAbstractFileEngine::caseSensitive()?
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 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 result;
}
static QList<QRegExp> get_patterns(const std::vector< std::shared_ptr<ChecksumDefinition> > &checksumDefinitions)
{
QList<QRegExp> result;
for (const std::shared_ptr<ChecksumDefinition> &cd : checksumDefinitions)
if (cd) {
const auto patterns = cd->patterns();
for (const QString &pattern : patterns) {
result.push_back(QRegExp(pattern, fs_cs));
}
}
return result;
}
namespace
{
struct matches_any : std::unary_function<QString, bool> {
const QList<QRegExp> m_regexps;
explicit matches_any(const QList<QRegExp> ®exps) : m_regexps(regexps) {}
bool operator()(const QString &s) const
{
return std::any_of(m_regexps.cbegin(), m_regexps.cend(),
[s](const QRegExp &rx) { return rx.exactMatch(s); });
}
};
}
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
ResultDialog *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 QList<QRegExp> 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))) {
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 QList<QRegExp> &rxs)
{
QStringList::iterator end = l.end();
for (const QRegExp &rx : rxs) {
end = std::remove_if(l.begin(), end,
[rx](const QString &str) {
return rx.exactMatch(str);
});
}
l.erase(end, l.end());
return l;
}
namespace
{
struct File {
QString name;
QByteArray checksum;
bool binary;
};
}
static QString decode(const QString &encoded)
{
QString decoded;
decoded.reserve(encoded.size());
bool shift = false;
for (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)) {
QTextStream s(&f);
QRegExp rx(QLatin1String("(\\?)([a-f0-9A-F]+) ([ *])([^\n]+)\n*"));
while (!s.atEnd()) {
const QString line = s.readLine();
if (rx.exactMatch(line)) {
Q_ASSERT(!rx.cap(4).endsWith(QLatin1Char('\n')));
const File file = {
rx.cap(1) == QLatin1String("\\") ? decode(rx.cap(4)) : rx.cap(4),
rx.cap(2).toLatin1(),
rx.cap(3) == QLatin1String("*"),
};
files.push_back(file);
}
}
}
return files;
}
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::shared_ptr<ChecksumDefinition> filename2definition(const QString &fileName,
const std::vector< std::shared_ptr<ChecksumDefinition> > &checksumDefinitions)
{
for (const std::shared_ptr<ChecksumDefinition> &cd : checksumDefinitions) {
if (cd) {
const auto patterns = cd->patterns();
for (const QString &pattern : patterns) {
if (QRegExp(pattern, fs_cs).exactMatch(fileName)) {
return cd;
}
}
}
}
return std::shared_ptr<ChecksumDefinition>();
}
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 QList<QRegExp> patterns = 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());
QStringList oldInputFiles;
oldInputFiles.reserve(parsed.size());
std::transform(parsed.cbegin(), parsed.cend(), std::back_inserter(oldInputFiles),
std::mem_fn(&File::name));
inputFiles = fs_intersect(oldInputFiles, entries);
}
const Dir item = {
dir,
fi.fileName(),
inputFiles,
aggregate_size(dir, inputFiles),
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;
}
};
}
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 QList<QRegExp> patterns = 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 (std::map<QDir, QStringList, less_dir>::const_iterator 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 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/gui/decryptverifyfilesdialog.cpp b/src/crypto/gui/decryptverifyfilesdialog.cpp
index 82d45d44b..7ec5553cd 100644
--- a/src/crypto/gui/decryptverifyfilesdialog.cpp
+++ b/src/crypto/gui/decryptverifyfilesdialog.cpp
@@ -1,244 +1,244 @@
/* crypto/gui/decryptverifyfilesdialog.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2016 Bundesamt für Sicherheit in der Informationstechnik
SPDX-FileContributor: Intevation GmbH
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "decryptverifyfilesdialog.h"
#include "kleopatra_debug.h"
#include "crypto/taskcollection.h"
#include "crypto/decryptverifytask.h"
#include "crypto/gui/resultpage.h"
#include "crypto/gui/resultlistwidget.h"
#include <Libkleo/FileNameRequester>
#include <QWindow>
#include <QVBoxLayout>
#include <QProgressBar>
#include <QLabel>
#include <QPushButton>
#include <vector>
#include <KLocalizedString>
#include <KMessageBox>
#include <KConfigGroup>
#include <KSharedConfig>
#include <KWindowConfig>
using namespace Kleo;
using namespace Kleo::Crypto;
using namespace Kleo::Crypto::Gui;
DecryptVerifyFilesDialog::DecryptVerifyFilesDialog(const std::shared_ptr<TaskCollection> &coll, QWidget *parent)
: QDialog(parent), m_tasks(coll), m_buttonBox(new QDialogButtonBox)
{
readConfig();
auto vLay = new QVBoxLayout(this);
auto labels = new QWidget;
auto outputLayout = new QHBoxLayout;
m_outputLocationFNR = new FileNameRequester;
auto outLabel = new QLabel(i18n("&Output folder:"));
outLabel->setBuddy(m_outputLocationFNR);
outputLayout->addWidget(outLabel);
outputLayout->addWidget(m_outputLocationFNR);
m_outputLocationFNR->setFilter(QDir::Dirs);
vLay->addLayout(outputLayout);
m_progressLabelLayout = new QVBoxLayout(labels);
vLay->addWidget(labels);
m_progressBar = new QProgressBar;
vLay->addWidget(m_progressBar);
m_resultList = new ResultListWidget;
vLay->addWidget(m_resultList);
m_tasks = coll;
Q_ASSERT(m_tasks);
m_resultList->setTaskCollection(coll);
connect(m_tasks.get(), &TaskCollection::progress, this, &DecryptVerifyFilesDialog::progress);
connect(m_tasks.get(), &TaskCollection::done, this, &DecryptVerifyFilesDialog::allDone);
connect(m_tasks.get(), &TaskCollection::result, this, &DecryptVerifyFilesDialog::result);
connect(m_tasks.get(), &TaskCollection::started, this, &DecryptVerifyFilesDialog::started);
connect(m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
connect(m_buttonBox, &QDialogButtonBox::clicked, this, &DecryptVerifyFilesDialog::btnClicked);
layout()->addWidget(m_buttonBox);
bool hasOutputs = false;
for (const auto &t: coll->tasks()) {
if (!qobject_cast<VerifyDetachedTask *>(t.get())) {
hasOutputs = true;
break;
}
}
if (hasOutputs) {
setWindowTitle(i18nc("@title:window", "Decrypt/Verify Files"));
m_saveButton = QDialogButtonBox::SaveAll;
m_buttonBox->addButton(QDialogButtonBox::Discard);
connect(m_buttonBox, &QDialogButtonBox::accepted, this, &DecryptVerifyFilesDialog::checkAccept);
} else {
outLabel->setVisible(false);
m_outputLocationFNR->setVisible(false);
setWindowTitle(i18nc("@title:window", "Verify Files"));
m_buttonBox->addButton(QDialogButtonBox::Close);
connect(m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
}
if (m_saveButton) {
m_buttonBox->addButton(m_saveButton);
m_buttonBox->button(m_saveButton)->setEnabled(false);
}
}
DecryptVerifyFilesDialog::~DecryptVerifyFilesDialog()
{
qCDebug(KLEOPATRA_LOG);
writeConfig();
}
void DecryptVerifyFilesDialog::allDone()
{
qCDebug(KLEOPATRA_LOG) << "All done";
Q_ASSERT(m_tasks);
m_progressBar->setRange(0, 100);
m_progressBar->setValue(100);
for (const auto &i: m_progressLabelByTag.keys()) {
if (!i.isEmpty()) {
m_progressLabelByTag.value(i)->setText(i18n("%1: All operations completed.", i));
} else {
m_progressLabelByTag.value(i)->setText(i18n("All operations completed."));
}
}
if (m_tasks->allTasksHaveErrors()) {
return;
}
if (m_saveButton != QDialogButtonBox::NoButton) {
m_buttonBox->button(m_saveButton)->setEnabled(true);
} else {
m_buttonBox->removeButton(m_buttonBox->button(QDialogButtonBox::Close));
m_buttonBox->addButton(QDialogButtonBox::Ok);
}
}
void DecryptVerifyFilesDialog::started(const std::shared_ptr<Task> &task)
{
Q_ASSERT(task);
const auto tag = task->tag();
auto label = labelForTag(tag);
Q_ASSERT(label);
if (tag.isEmpty()) {
label->setText(i18nc("number, operation description", "Operation %1: %2", m_tasks->numberOfCompletedTasks() + 1, task->label()));
} else {
label->setText(i18nc("tag( \"OpenPGP\" or \"CMS\"), operation description", "%1: %2", tag, task->label()));
}
if (m_saveButton != QDialogButtonBox::NoButton) {
m_buttonBox->button(m_saveButton)->setEnabled(false);
} else if (m_buttonBox->button(QDialogButtonBox::Ok)) {
m_buttonBox->removeButton(m_buttonBox->button(QDialogButtonBox::Ok));
m_buttonBox->addButton(QDialogButtonBox::Close);
}
}
QLabel *DecryptVerifyFilesDialog::labelForTag(const QString &tag)
{
if (QLabel *const label = m_progressLabelByTag.value(tag)) {
return label;
}
auto label = new QLabel;
label->setTextFormat(Qt::RichText);
label->setWordWrap(true);
m_progressLabelLayout->addWidget(label);
m_progressLabelByTag.insert(tag, label);
return label;
}
void DecryptVerifyFilesDialog::progress(const QString &msg, int progress, int total)
{
Q_UNUSED(msg)
Q_ASSERT(progress >= 0);
Q_ASSERT(total >= 0);
m_progressBar->setRange(0, total);
m_progressBar->setValue(progress);
}
void DecryptVerifyFilesDialog::setOutputLocation(const QString &dir)
{
m_outputLocationFNR->setFileName(dir);
}
QString DecryptVerifyFilesDialog::outputLocation() const
{
return m_outputLocationFNR->fileName();
}
void DecryptVerifyFilesDialog::btnClicked(QAbstractButton *btn)
{
if (m_buttonBox->buttonRole(btn) == QDialogButtonBox::DestructiveRole) {
close();
}
}
void DecryptVerifyFilesDialog::checkAccept() {
const auto outLoc = outputLocation();
if (outLoc.isEmpty()) {
KMessageBox::information(this, i18n("Please select an output folder."),
i18n("No output folder."));
return;
}
const QFileInfo fi(outLoc);
if (fi.exists() && fi.isDir() && fi.isWritable()) {
accept();
return;
}
if (!fi.exists()) {
qCDebug(KLEOPATRA_LOG) << "Output dir does not exist. Trying to create.";
const QDir dir(outLoc);
if (!dir.mkdir(outLoc)) {
KMessageBox::information(this, i18n("Please select a different output folder."),
i18n("Failed to create output folder."));
return;
} else {
accept();
return;
}
}
KMessageBox::information(this, i18n("Please select a different output folder."),
i18n("Invalid output folder."));
}
void DecryptVerifyFilesDialog::readConfig()
{
winId(); // ensure there's a window created
// set default window size
windowHandle()->resize(640, 480);
// restore size from config file
- KConfigGroup cfgGroup(KSharedConfig::openConfig(), "DecryptVerifyFilesDialog");
+ KConfigGroup cfgGroup(KSharedConfig::openStateConfig(), "DecryptVerifyFilesDialog");
KWindowConfig::restoreWindowSize(windowHandle(), cfgGroup);
// NOTICE: QWindow::setGeometry() does NOT impact the backing QWidget geometry even if the platform
// window was created -> QTBUG-40584. We therefore copy the size here.
// TODO: remove once this was resolved in QWidget QPA
resize(windowHandle()->size());
}
void DecryptVerifyFilesDialog::writeConfig()
{
- KConfigGroup cfgGroup(KSharedConfig::openConfig(), "DecryptVerifyFilesDialog");
+ KConfigGroup cfgGroup(KSharedConfig::openStateConfig(), "DecryptVerifyFilesDialog");
KWindowConfig::saveWindowSize(windowHandle(), cfgGroup);
cfgGroup.sync();
}
diff --git a/src/dialogs/certificatedetailswidget.cpp b/src/dialogs/certificatedetailswidget.cpp
index 97511ce5a..0aca3f4a0 100644
--- a/src/dialogs/certificatedetailswidget.cpp
+++ b/src/dialogs/certificatedetailswidget.cpp
@@ -1,678 +1,678 @@
/* SPDX-FileCopyrightText: 2016 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2017 Intevation GmbH
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "certificatedetailswidget.h"
#include "ui_certificatedetailswidget.h"
#include "kleopatra_debug.h"
#include "exportdialog.h"
#include "trustchainwidget.h"
#include "subkeyswidget.h"
#include "weboftrustdialog.h"
#include "commands/changepassphrasecommand.h"
#include "commands/changeexpirycommand.h"
#include "commands/certifycertificatecommand.h"
#include "commands/revokecertificationcommand.h"
#include "commands/adduseridcommand.h"
#include "commands/genrevokecommand.h"
#include "commands/detailscommand.h"
#include "commands/dumpcertificatecommand.h"
#include "utils/tags.h"
#include <Libkleo/Formatting>
#include <Libkleo/Dn>
#include <Libkleo/KeyCache>
#include <gpgme++/context.h>
#include <gpgme++/key.h>
#include <gpgme++/keylistresult.h>
#include <gpgme++/tofuinfo.h>
#include <QGpgME/Protocol>
#include <QGpgME/KeyListJob>
#include <QDateTime>
#include <QDialogButtonBox>
#include <QMenu>
#include <KConfigGroup>
#include <KSharedConfig>
#include <QLocale>
#include <gpgme++/gpgmepp_version.h>
#if GPGMEPP_VERSION >= 0x10E00 // 1.14.0
# define GPGME_HAS_REMARKS
#endif
#if GPGMEPP_VERSION >= 0x10F00 // 1.15.0
# define GPGME_HAS_WITH_SECRET
# include <QGpgME/Debug>
#endif
#define HIDE_ROW(row) \
ui.row->setVisible(false); \
ui.row##Lbl->setVisible(false);
Q_DECLARE_METATYPE(GpgME::UserID)
using namespace Kleo;
class CertificateDetailsWidget::Private
{
public:
Private(CertificateDetailsWidget *parent)
: updateInProgress (false), q(parent)
{}
void setupCommonProperties();
void setupPGPProperties();
void setupSMIMEProperties();
void revokeUID(const GpgME::UserID &uid);
void genRevokeCert();
void certifyClicked();
void webOfTrustClicked();
void exportClicked();
void addUserID();
void changePassphrase();
void changeExpiration();
void keysMayHaveChanged();
void showTrustChainDialog();
void showMoreDetails();
void publishCertificate();
void userIDTableContextMenuRequested(const QPoint &p);
QString tofuTooltipString(const GpgME::UserID &uid) const;
void smimeLinkActivated(const QString &link);
void setUpdatedKey(const GpgME::Key &key);
void keyListDone(const GpgME::KeyListResult &,
const std::vector<GpgME::Key> &, const QString &,
const GpgME::Error &);
Ui::CertificateDetailsWidget ui;
GpgME::Key key;
bool updateInProgress;
private:
CertificateDetailsWidget *const q;
};
void CertificateDetailsWidget::Private::setupCommonProperties()
{
// TODO: Enable once implemented
HIDE_ROW(publishing)
const bool hasSecret = key.hasSecret();
const bool isOpenPGP = key.protocol() == GpgME::OpenPGP;
// TODO: Enable once implemented
const bool canRevokeUID = false; // isOpenPGP && hasSecret
ui.changePassphraseBtn->setVisible(hasSecret);
ui.genRevokeBtn->setVisible(isOpenPGP && hasSecret);
ui.certifyBtn->setVisible(isOpenPGP && !hasSecret);
ui.changeExpirationBtn->setVisible(isOpenPGP && hasSecret);
ui.addUserIDBtn->setVisible(hasSecret && isOpenPGP);
ui.webOfTrustBtn->setVisible(isOpenPGP);
ui.hboxLayout_1->addStretch(1);
ui.validFrom->setText(Kleo::Formatting::creationDateString(key));
const QString expiry = Kleo::Formatting::expirationDateString(key);
ui.expires->setText(expiry.isEmpty() ? i18nc("Expires", "never") : expiry);
ui.type->setText(Kleo::Formatting::type(key));
ui.fingerprint->setText(Formatting::prettyID(key.primaryFingerprint()));
if (Kleo::Formatting::complianceMode().isEmpty()) {
HIDE_ROW(compliance)
} else {
ui.complianceLbl->setText(Kleo::Formatting::complianceStringForKey(key));
}
ui.userIDTable->clear();
QStringList headers = { i18n("Email"), i18n("Name"), i18n("Trust Level"), i18n("Tags") };
if (canRevokeUID) {
headers << QString();
}
ui.userIDTable->setColumnCount(headers.count());
ui.userIDTable->setColumnWidth(0, 200);
ui.userIDTable->setColumnWidth(1, 200);
ui.userIDTable->setHeaderLabels(headers);
const auto uids = key.userIDs();
for (unsigned int i = 0; i < uids.size(); ++i) {
const auto &uid = uids[i];
auto item = new QTreeWidgetItem;
const QString toolTip = tofuTooltipString(uid);
item->setData(0, Qt::UserRole, QVariant::fromValue(uid));
auto pMail = Kleo::Formatting::prettyEMail(uid);
auto pName = Kleo::Formatting::prettyName(uid);
if (!isOpenPGP && pMail.isEmpty() && !pName.isEmpty()) {
// S/MIME UserIDs are sometimes split, with one userID
// containing the name another the Mail, we merge these
// UID's into a single item.
if (i + 1 < uids.size()) {
pMail = Kleo::Formatting::prettyEMail(uids[i + 1]);
// skip next uid
++i;
}
}
if (!isOpenPGP && pMail.isEmpty() && pName.isEmpty()) {
// S/MIME certificates sometimes contain urls where both
// name and mail is empty. In that case we print whatever
// the uid is as name.
//
// Can be ugly like (3:uri24:http://ca.intevation.org), but
// this is better then showing an empty entry.
pName = QString::fromLatin1(uid.id());
}
item->setData(0, Qt::DisplayRole, pMail);
item->setData(0, Qt::ToolTipRole, toolTip);
item->setData(1, Qt::DisplayRole, pName);
item->setData(1, Qt::ToolTipRole, toolTip);
QIcon trustIcon;
if (updateInProgress) {
trustIcon = QIcon::fromTheme(QStringLiteral("emblem-question"));
item->setData(2, Qt::DisplayRole, i18n("Updating..."));
} else {
switch (uid.validity()) {
case GpgME::UserID::Unknown:
case GpgME::UserID::Undefined:
trustIcon = QIcon::fromTheme(QStringLiteral("emblem-question"));
break;
case GpgME::UserID::Never:
trustIcon = QIcon::fromTheme(QStringLiteral("emblem-error"));
break;
case GpgME::UserID::Marginal:
trustIcon = QIcon::fromTheme(QStringLiteral("emblem-warning"));
break;
case GpgME::UserID::Full:
case GpgME::UserID::Ultimate:
trustIcon = QIcon::fromTheme(QStringLiteral("emblem-success"));
break;
}
item->setData(2, Qt::DisplayRole, Kleo::Formatting::validityShort(uid));
}
item->setData(2, Qt::DecorationRole, trustIcon);
item->setData(2, Qt::ToolTipRole, toolTip);
GpgME::Error err;
QStringList tagList;
#ifdef GPGME_HAS_REMARKS
for (const auto &tag: uid.remarks(Tags::tagKeys(), err)) {
if (err) {
qCWarning(KLEOPATRA_LOG) << "Getting remarks for user id" << uid.id() << "failed:" << err;
}
tagList << QString::fromStdString(tag);
}
qCDebug(KLEOPATRA_LOG) << "tagList:" << tagList;
#endif
const auto tags = tagList.join(QStringLiteral("; "));
item->setData(3, Qt::DisplayRole, tags);
item->setData(3, Qt::ToolTipRole, toolTip);
ui.userIDTable->addTopLevelItem(item);
if (canRevokeUID) {
auto button = new QPushButton;
button->setIcon(QIcon::fromTheme(QStringLiteral("entry-delete")));
button->setToolTip(i18n("Revoke this User ID"));
button->setMaximumWidth(32);
QObject::connect(button, &QPushButton::clicked,
q, [this, uid]() { revokeUID(uid); });
ui.userIDTable->setItemWidget(item, 4, button);
}
}
if (!Tags::tagsEnabled()) {
ui.userIDTable->hideColumn(3);
}
}
void CertificateDetailsWidget::Private::revokeUID(const GpgME::UserID &uid)
{
Q_UNUSED(uid)
qCWarning(KLEOPATRA_LOG) << "Revoking UserID is not implemented. How did you even get here?!?!";
}
void CertificateDetailsWidget::Private::changeExpiration()
{
auto cmd = new Kleo::Commands::ChangeExpiryCommand(key);
QObject::connect(cmd, &Kleo::Commands::ChangeExpiryCommand::finished,
q, [this]() {
ui.changeExpirationBtn->setEnabled(true);
});
ui.changeExpirationBtn->setEnabled(false);
cmd->start();
}
void CertificateDetailsWidget::Private::changePassphrase()
{
auto cmd = new Kleo::Commands::ChangePassphraseCommand(key);
QObject::connect(cmd, &Kleo::Commands::ChangePassphraseCommand::finished,
q, [this]() {
ui.changePassphraseBtn->setEnabled(true);
});
ui.changePassphraseBtn->setEnabled(false);
cmd->start();
}
void CertificateDetailsWidget::Private::genRevokeCert()
{
auto cmd = new Kleo::Commands::GenRevokeCommand(key);
QObject::connect(cmd, &Kleo::Commands::GenRevokeCommand::finished,
q, [this]() {
ui.genRevokeBtn->setEnabled(true);
});
ui.genRevokeBtn->setEnabled(false);
cmd->start();
}
void CertificateDetailsWidget::Private::certifyClicked()
{
auto cmd = new Kleo::Commands::CertifyCertificateCommand(key);
QObject::connect(cmd, &Kleo::Commands::CertifyCertificateCommand::finished,
q, [this]() {
ui.certifyBtn->setEnabled(true);
});
ui.certifyBtn->setEnabled(false);
cmd->start();
}
void CertificateDetailsWidget::Private::webOfTrustClicked()
{
QScopedPointer<WebOfTrustDialog> dlg(new WebOfTrustDialog(q));
dlg->setKey(key);
dlg->exec();
}
void CertificateDetailsWidget::Private::exportClicked()
{
QScopedPointer<ExportDialog> dlg(new ExportDialog(q));
dlg->setKey(key);
dlg->exec();
}
void CertificateDetailsWidget::Private::addUserID()
{
auto cmd = new Kleo::Commands::AddUserIDCommand(key);
QObject::connect(cmd, &Kleo::Commands::AddUserIDCommand::finished,
q, [this]() {
ui.addUserIDBtn->setEnabled(true);
key.update();
q->setKey(key);
});
ui.addUserIDBtn->setEnabled(false);
cmd->start();
}
void CertificateDetailsWidget::Private::keysMayHaveChanged()
{
auto newKey = Kleo::KeyCache::instance()->findByFingerprint(key.primaryFingerprint());
if (!newKey.isNull()) {
setUpdatedKey(newKey);
}
}
void CertificateDetailsWidget::Private::showTrustChainDialog()
{
QScopedPointer<TrustChainDialog> dlg(new TrustChainDialog(q));
dlg->setKey(key);
dlg->exec();
}
void CertificateDetailsWidget::Private::publishCertificate()
{
qCWarning(KLEOPATRA_LOG) << "publishCertificateis not implemented.";
//TODO
}
void CertificateDetailsWidget::Private::userIDTableContextMenuRequested(const QPoint &p)
{
auto item = ui.userIDTable->itemAt(p);
if (!item) {
return;
}
const auto userID = item->data(0, Qt::UserRole).value<GpgME::UserID>();
QMenu *menu = new QMenu(q);
menu->addAction(QIcon::fromTheme(QStringLiteral("view-certificate-sign")),
i18n("Certify..."),
q, [this, userID]() {
auto cmd = new Kleo::Commands::CertifyCertificateCommand(userID);
ui.userIDTable->setEnabled(false);
connect(cmd, &Kleo::Commands::CertifyCertificateCommand::finished,
q, [this]() {
ui.userIDTable->setEnabled(true);
// Trigger an update when done
q->setKey(key);
});
cmd->start();
});
if (Kleo::Commands::RevokeCertificationCommand::isSupported()) {
menu->addAction(QIcon::fromTheme(QStringLiteral("view-certificate-revoke")),
i18n("Revoke Certification..."),
q, [this, userID]() {
auto cmd = new Kleo::Commands::RevokeCertificationCommand(userID);
ui.userIDTable->setEnabled(false);
connect(cmd, &Kleo::Commands::RevokeCertificationCommand::finished,
q, [this]() {
ui.userIDTable->setEnabled(true);
// Trigger an update when done
q->setKey(key);
});
cmd->start();
});
}
connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater);
menu->popup(ui.userIDTable->viewport()->mapToGlobal(p));
}
void CertificateDetailsWidget::Private::showMoreDetails()
{
ui.moreDetailsBtn->setEnabled(false);
if (key.protocol() == GpgME::CMS) {
auto cmd = new Kleo::Commands::DumpCertificateCommand(key);
connect(cmd, &Kleo::Commands::DumpCertificateCommand::finished,
q, [this]() {
ui.moreDetailsBtn->setEnabled(true);
});
cmd->setUseDialog(true);
cmd->start();
} else {
QScopedPointer<SubKeysDialog> dlg(new SubKeysDialog(q));
dlg->setKey(key);
dlg->exec();
ui.moreDetailsBtn->setEnabled(true);
}
}
QString CertificateDetailsWidget::Private::tofuTooltipString(const GpgME::UserID &uid) const
{
const auto tofu = uid.tofuInfo();
if (tofu.isNull()) {
return QString();
}
QString html = QStringLiteral("<table border=\"0\" cell-padding=\"5\">");
const auto appendRow = [&html](const QString &lbl, const QString &val) {
html += QStringLiteral("<tr>"
"<th style=\"text-align: right; padding-right: 5px; white-space: nowrap;\">%1:</th>"
"<td style=\"white-space: nowrap;\">%2</td>"
"</tr>")
.arg(lbl, val);
};
const auto appendHeader = [this, &html](const QString &hdr) {
html += QStringLiteral("<tr><th colspan=\"2\" style=\"background-color: %1; color: %2\">%3</th></tr>")
.arg(q->palette().highlight().color().name(),
q->palette().highlightedText().color().name(),
hdr);
};
const auto dateTime = [](long ts) {
QLocale l;
return ts == 0 ? i18n("never") : l.toString(QDateTime::fromSecsSinceEpoch(ts), QLocale::ShortFormat);
};
appendHeader(i18n("Signing"));
appendRow(i18n("First message"), dateTime(tofu.signFirst()));
appendRow(i18n("Last message"), dateTime(tofu.signLast()));
appendRow(i18n("Message count"), QString::number(tofu.signCount()));
appendHeader(i18n("Encryption"));
appendRow(i18n("First message"), dateTime(tofu.encrFirst()));
appendRow(i18n("Last message"), dateTime(tofu.encrLast()));
appendRow(i18n("Message count"), QString::number(tofu.encrCount()));
html += QStringLiteral("</table>");
// Make sure the tooltip string is different for each UserID, even if the
// data are the same, otherwise the tooltip is not updated and moved when
// user moves mouse from one row to another.
html += QStringLiteral("<!-- %1 //-->").arg(QString::fromUtf8(uid.id()));
return html;
}
void CertificateDetailsWidget::Private::setupPGPProperties()
{
HIDE_ROW(smimeOwner)
HIDE_ROW(smimeIssuer)
ui.smimeRelatedAddresses->setVisible(false);
ui.trustChainDetailsBtn->setVisible(false);
ui.userIDTable->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui.userIDTable, &QAbstractItemView::customContextMenuRequested,
q, [this](const QPoint &p) { userIDTableContextMenuRequested(p); });
}
static QString formatDNToolTip(const Kleo::DN &dn)
{
QString html = QStringLiteral("<table border=\"0\" cell-spacing=15>");
const auto appendRow = [&html, dn](const QString &lbl, const QString &attr) {
const QString val = dn[attr];
if (!val.isEmpty()) {
html += QStringLiteral(
"<tr><th style=\"text-align: left; white-space: nowrap\">%1:</th>"
"<td style=\"white-space: nowrap\">%2</td>"
"</tr>").arg(lbl, val);
}
};
appendRow(i18n("Common Name"), QStringLiteral("CN"));
appendRow(i18n("Organization"), QStringLiteral("O"));
appendRow(i18n("Street"), QStringLiteral("STREET"));
appendRow(i18n("City"), QStringLiteral("L"));
appendRow(i18n("State"), QStringLiteral("ST"));
appendRow(i18n("Country"), QStringLiteral("C"));
html += QStringLiteral("</table>");
return html;
}
void CertificateDetailsWidget::Private::setupSMIMEProperties()
{
HIDE_ROW(publishing)
const auto ownerId = key.userID(0);
const Kleo::DN dn(ownerId.id());
const QString cn = dn[QStringLiteral("CN")];
const QString o = dn[QStringLiteral("O")];
const QString dnEmail = dn[QStringLiteral("EMAIL")];
const QString name = cn.isEmpty() ? dnEmail : cn;
QString owner;
if (name.isEmpty()) {
owner = dn.dn();
} else if (o.isEmpty()) {
owner = name;
} else {
owner = i18nc("<name> of <company>", "%1 of %2", name, o);
}
ui.smimeOwner->setText(owner);
ui.smimeOwner->setTextInteractionFlags(Qt::TextBrowserInteraction);
const Kleo::DN issuerDN(key.issuerName());
const QString issuerCN = issuerDN[QStringLiteral("CN")];
const QString issuer = issuerCN.isEmpty() ? QString::fromUtf8(key.issuerName()) : issuerCN;
ui.smimeIssuer->setText(QStringLiteral("<a href=\"#issuerDetails\">%1</a>").arg(issuer));
ui.smimeIssuer->setToolTip(formatDNToolTip(issuerDN));
ui.smimeOwner->setToolTip(formatDNToolTip(dn));
}
void CertificateDetailsWidget::Private::smimeLinkActivated(const QString &link)
{
if (link == QLatin1String("#issuerDetails")) {
const auto parentKey = KeyCache::instance()->findIssuers(key, KeyCache::NoOption);
if (!parentKey.size()) {
return;
}
auto cmd = new Kleo::Commands::DetailsCommand(parentKey[0], nullptr);
cmd->setParentWidget(q);
cmd->start();
return;
}
qCWarning(KLEOPATRA_LOG) << "Unknown link activated:" << link;
}
CertificateDetailsWidget::CertificateDetailsWidget(QWidget *parent)
: QWidget(parent)
, d(new Private(this))
{
d->ui.setupUi(this);
connect(d->ui.addUserIDBtn, &QPushButton::clicked,
this, [this]() { d->addUserID(); });
connect(d->ui.changePassphraseBtn, &QPushButton::clicked,
this, [this]() { d->changePassphrase(); });
connect(d->ui.genRevokeBtn, &QPushButton::clicked,
this, [this]() { d->genRevokeCert(); });
connect(d->ui.changeExpirationBtn, &QPushButton::clicked,
this, [this]() { d->changeExpiration(); });
connect(d->ui.smimeOwner, &QLabel::linkActivated,
this, [this](const QString &link) { d->smimeLinkActivated(link); });
connect(d->ui.smimeIssuer, &QLabel::linkActivated,
this, [this](const QString &link) { d->smimeLinkActivated(link); });
connect(d->ui.trustChainDetailsBtn, &QPushButton::pressed,
this, [this]() { d->showTrustChainDialog(); });
connect(d->ui.moreDetailsBtn, &QPushButton::pressed,
this, [this]() { d->showMoreDetails(); });
connect(d->ui.publishing, &QPushButton::pressed,
this, [this]() { d->publishCertificate(); });
connect(d->ui.certifyBtn, &QPushButton::clicked,
this, [this]() { d->certifyClicked(); });
connect(d->ui.webOfTrustBtn, &QPushButton::clicked,
this, [this]() { d->webOfTrustClicked(); });
connect(d->ui.exportBtn, &QPushButton::clicked,
this, [this]() { d->exportClicked(); });
connect(Kleo::KeyCache::instance().get(), &Kleo::KeyCache::keysMayHaveChanged,
this, [this]() { d->keysMayHaveChanged(); });
}
CertificateDetailsWidget::~CertificateDetailsWidget()
{
}
void CertificateDetailsWidget::Private::keyListDone(const GpgME::KeyListResult &,
const std::vector<GpgME::Key> &keys,
const QString &,
const GpgME::Error &) {
updateInProgress = false;
if (keys.size() != 1) {
qCWarning(KLEOPATRA_LOG) << "Invalid keylist result in update.";
return;
}
// As we listen for keysmayhavechanged we get the update
// after updating the keycache.
KeyCache::mutableInstance()->insert(keys);
}
void CertificateDetailsWidget::Private::setUpdatedKey(const GpgME::Key &k)
{
key = k;
setupCommonProperties();
if (key.protocol() == GpgME::OpenPGP) {
setupPGPProperties();
} else {
setupSMIMEProperties();
}
}
void CertificateDetailsWidget::setKey(const GpgME::Key &key)
{
if (key.protocol() == GpgME::CMS) {
// For everything but S/MIME this should be quick
// and we don't need to show another status.
d->updateInProgress = true;
}
d->setUpdatedKey(key);
// Run a keylistjob with full details (TOFU / Validate)
QGpgME::KeyListJob *job = key.protocol() == GpgME::OpenPGP ? QGpgME::openpgp()->keyListJob(false, true, true) :
QGpgME::smime()->keyListJob(false, true, true);
auto ctx = QGpgME::Job::context(job);
ctx->addKeyListMode(GpgME::WithTofu);
ctx->addKeyListMode(GpgME::SignatureNotations);
#ifdef GPGME_HAS_WITH_SECRET
if (key.hasSecret()) {
ctx->addKeyListMode(GpgME::WithSecret);
}
#endif
// Windows QGpgME new style connect problem makes this necessary.
connect(job, SIGNAL(result(GpgME::KeyListResult,std::vector<GpgME::Key>,QString,GpgME::Error)),
this, SLOT(keyListDone(GpgME::KeyListResult,std::vector<GpgME::Key>,QString,GpgME::Error)));
#ifdef GPGME_HAS_WITH_SECRET
job->start(QStringList() << QLatin1String(key.primaryFingerprint()));
#else
job->start(QStringList() << QLatin1String(key.primaryFingerprint()), key.hasSecret());
#endif
}
GpgME::Key CertificateDetailsWidget::key() const
{
return d->key;
}
CertificateDetailsDialog::CertificateDetailsDialog(QWidget *parent)
: QDialog(parent)
{
setWindowTitle(i18nc("@title:window", "Certificate Details"));
auto l = new QVBoxLayout(this);
l->addWidget(new CertificateDetailsWidget(this));
auto bbox = new QDialogButtonBox(this);
auto btn = bbox->addButton(QDialogButtonBox::Close);
connect(btn, &QPushButton::pressed, this, &QDialog::accept);
l->addWidget(bbox);
readConfig();
}
CertificateDetailsDialog::~CertificateDetailsDialog()
{
writeConfig();
}
void CertificateDetailsDialog::readConfig()
{
- KConfigGroup dialog(KSharedConfig::openConfig(), "CertificateDetailsDialog");
+ KConfigGroup dialog(KSharedConfig::openStateConfig(), "CertificateDetailsDialog");
const QSize size = dialog.readEntry("Size", QSize(730, 280));
if (size.isValid()) {
resize(size);
}
}
void CertificateDetailsDialog::writeConfig()
{
- KConfigGroup dialog(KSharedConfig::openConfig(), "CertificateDetailsDialog");
+ KConfigGroup dialog(KSharedConfig::openStateConfig(), "CertificateDetailsDialog");
dialog.writeEntry("Size", size());
dialog.sync();
}
void CertificateDetailsDialog::setKey(const GpgME::Key &key)
{
auto w = findChild<CertificateDetailsWidget*>();
Q_ASSERT(w);
w->setKey(key);
}
GpgME::Key CertificateDetailsDialog::key() const
{
auto w = findChild<CertificateDetailsWidget*>();
Q_ASSERT(w);
return w->key();
}
#include "moc_certificatedetailswidget.cpp"
diff --git a/src/dialogs/certifycertificatedialog.cpp b/src/dialogs/certifycertificatedialog.cpp
index cbb0d8001..142891109 100644
--- a/src/dialogs/certifycertificatedialog.cpp
+++ b/src/dialogs/certifycertificatedialog.cpp
@@ -1,150 +1,150 @@
/* -*- mode: c++; c-basic-offset:4 -*-
dialogs/signcertificatedialog.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2019 g10code GmbH
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-kleopatra.h>
#include "kleopatra_debug.h"
#include "certifycertificatedialog.h"
#include "certifywidget.h"
#include <Libkleo/Formatting>
#include <Libkleo/Stl_Util>
#include <KLocalizedString>
#include <KStandardGuiItem>
#include <KSharedConfig>
#include <KConfigGroup>
#include <KMessageBox>
#include <QVBoxLayout>
#include <QDialogButtonBox>
#include <QPushButton>
#include <gpg-error.h>
using namespace GpgME;
using namespace Kleo;
CertifyCertificateDialog::CertifyCertificateDialog(QWidget *p, Qt::WindowFlags f)
: QDialog(p, f)
{
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
// Setup GUI
auto mainLay = new QVBoxLayout(this);
mCertWidget = new CertifyWidget(this);
mainLay->addWidget(mCertWidget);
QDialogButtonBox *buttonBox = new QDialogButtonBox();
buttonBox->setStandardButtons(QDialogButtonBox::Cancel |
QDialogButtonBox::Ok);
KGuiItem::assign(buttonBox->button(QDialogButtonBox::Ok), KStandardGuiItem::ok());
KGuiItem::assign(buttonBox->button(QDialogButtonBox::Cancel), KStandardGuiItem::cancel());
buttonBox->button(QDialogButtonBox::Ok)->setText(i18n("Certify"));
connect(buttonBox->button(QDialogButtonBox::Ok), &QAbstractButton::clicked,
this, [this] () {
KConfigGroup conf(KSharedConfig::openConfig(), "CertifySettings");
const auto lastKey = mCertWidget->secKey();
// Do not accept if the keys are the same.
if (!lastKey.isNull() && !mCertWidget->target().isNull() &&
!strcmp(lastKey.primaryFingerprint(),
mCertWidget->target().primaryFingerprint())) {
KMessageBox::error(this, i18n("You cannot certify using the same key."),
i18n("Invalid Selection"), KMessageBox::Notify);
return;
}
if (!lastKey.isNull()) {
conf.writeEntry("LastKey", lastKey.primaryFingerprint());
}
conf.writeEntry("ExportCheckState", mCertWidget->exportableSelected());
conf.writeEntry("PublishCheckState", mCertWidget->publishSelected());
accept();
});
connect(buttonBox->button(QDialogButtonBox::Cancel), &QAbstractButton::clicked,
this, [this] () {
close();
});
mainLay->addWidget(buttonBox);
- KConfigGroup cfgGroup(KSharedConfig::openConfig(), "CertifyDialog");
+ KConfigGroup cfgGroup(KSharedConfig::openStateConfig(), "CertifyDialog");
const QByteArray geom = cfgGroup.readEntry("geometry", QByteArray());
if (!geom.isEmpty()) {
restoreGeometry(geom);
return;
}
resize(QSize(640, 480));
}
CertifyCertificateDialog::~CertifyCertificateDialog()
{
- KConfigGroup cfgGroup(KSharedConfig::openConfig(), "CertifyDialog");
+ KConfigGroup cfgGroup(KSharedConfig::openStateConfig(), "CertifyDialog");
cfgGroup.writeEntry("geometry", saveGeometry());
cfgGroup.sync();
}
void CertifyCertificateDialog::setCertificateToCertify(const Key &key)
{
setWindowTitle(i18nc("@title:window arg is name, email of certificate holder", "Certify Certificate: %1", Formatting::prettyName(key)));
mCertWidget->setTarget(key);
}
bool CertifyCertificateDialog::exportableCertificationSelected() const
{
return mCertWidget->exportableSelected();
}
bool CertifyCertificateDialog::trustCertificationSelected() const
{
return false;
}
bool CertifyCertificateDialog::nonRevocableCertificationSelected() const
{
return false;
}
Key CertifyCertificateDialog::selectedSecretKey() const
{
return mCertWidget->secKey();
}
bool CertifyCertificateDialog::sendToServer() const
{
return mCertWidget->publishSelected();
}
unsigned int CertifyCertificateDialog::selectedCheckLevel() const
{
//PENDING
#ifdef KLEO_SIGN_KEY_CERTLEVEL_SUPPORT
return d->selectCheckLevelPage->checkLevel();
#endif
return 0;
}
void CertifyCertificateDialog::setSelectedUserIDs(const std::vector<UserID> &uids)
{
mCertWidget->selectUserIDs(uids);
}
std::vector<unsigned int> CertifyCertificateDialog::selectedUserIDs() const
{
return mCertWidget->selectedUserIDs();
}
QString CertifyCertificateDialog::tags() const
{
return mCertWidget->tags();
}
diff --git a/src/dialogs/createcsrforcardkeydialog.cpp b/src/dialogs/createcsrforcardkeydialog.cpp
index 41d7087b7..447b573ce 100644
--- a/src/dialogs/createcsrforcardkeydialog.cpp
+++ b/src/dialogs/createcsrforcardkeydialog.cpp
@@ -1,114 +1,114 @@
/* -*- mode: c++; c-basic-offset:4 -*-
dialogs/createcsrforcardkeydialog.h
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2020 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "createcsrforcardkeydialog.h"
#include "certificatedetailsinputwidget.h"
#include <KConfigGroup>
#include <KSharedConfig>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QVBoxLayout>
using namespace Kleo;
using namespace Kleo::Dialogs;
class CreateCSRForCardKeyDialog::Private
{
friend class ::Kleo::Dialogs::CreateCSRForCardKeyDialog;
CreateCSRForCardKeyDialog *const q;
struct {
CertificateDetailsInputWidget *detailsWidget = nullptr;
QDialogButtonBox *buttonBox = nullptr;
} ui;
public:
Private(CreateCSRForCardKeyDialog *qq)
: q(qq)
{
auto mainLayout = new QVBoxLayout(q);
ui.detailsWidget = new CertificateDetailsInputWidget();
connect(ui.detailsWidget, &CertificateDetailsInputWidget::validityChanged,
q, [this] (bool valid) { onValidityChanged(valid); });
ui.buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(ui.buttonBox, &QDialogButtonBox::accepted, q, &QDialog::accept);
connect(ui.buttonBox, &QDialogButtonBox::rejected, q, &QDialog::reject);
mainLayout->addWidget(ui.detailsWidget);
mainLayout->addWidget(ui.buttonBox);
// increase default width by 50 % to get more space for line edits
const QSize sizeHint = q->sizeHint();
const QSize defaultSize = QSize(sizeHint.width() * 15 / 10, sizeHint.height());
restoreGeometry(defaultSize);
}
~Private()
{
saveGeometry();
}
void onValidityChanged(bool valid)
{
ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid);
}
private:
void saveGeometry()
{
- KConfigGroup cfgGroup(KSharedConfig::openConfig(), "CreateCSRForCardKeyDialog");
+ KConfigGroup cfgGroup(KSharedConfig::openStateConfig(), "CreateCSRForCardKeyDialog");
cfgGroup.writeEntry("Size", q->size());
cfgGroup.sync();
}
void restoreGeometry(const QSize &defaultSize)
{
- KConfigGroup cfgGroup(KSharedConfig::openConfig(), "CreateCSRForCardKeyDialog");
+ KConfigGroup cfgGroup(KSharedConfig::openStateConfig(), "CreateCSRForCardKeyDialog");
const QSize size = cfgGroup.readEntry("Size", defaultSize);
if (size.isValid()) {
q->resize(size);
}
}
};
CreateCSRForCardKeyDialog::CreateCSRForCardKeyDialog(QWidget *parent)
: QDialog(parent)
, d(new Private(this))
{
}
CreateCSRForCardKeyDialog::~CreateCSRForCardKeyDialog()
{
}
void CreateCSRForCardKeyDialog::setName(const QString &name)
{
d->ui.detailsWidget->setName(name);
}
void CreateCSRForCardKeyDialog::setEmail(const QString &email)
{
d->ui.detailsWidget->setEmail(email);
}
QString CreateCSRForCardKeyDialog::email() const
{
return d->ui.detailsWidget->email();
}
QString CreateCSRForCardKeyDialog::dn() const
{
return d->ui.detailsWidget->dn();
}
diff --git a/src/dialogs/deletecertificatesdialog.cpp b/src/dialogs/deletecertificatesdialog.cpp
index b1752e1de..cb9fb5229 100644
--- a/src/dialogs/deletecertificatesdialog.cpp
+++ b/src/dialogs/deletecertificatesdialog.cpp
@@ -1,232 +1,232 @@
/* -*- mode: c++; c-basic-offset:4 -*-
dialogs/deletecertificatesdialog.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2009 Klarälvdalens Datakonsult AB
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-kleopatra.h>
#include "deletecertificatesdialog.h"
#include <view/keytreeview.h>
#include <Libkleo/KeyListModel>
#include <Libkleo/Stl_Util>
#include <KLocalizedString>
#include <KMessageBox>
#include <KStandardGuiItem>
#include "kleopatra_debug.h"
#include <KConfigGroup>
#include <KSharedConfig>
#include <QLabel>
#include <QDialogButtonBox>
#include <QVBoxLayout>
#include <QWhatsThis>
#include <QCursor>
#include <QPushButton>
#include <QTreeView>
#include <gpgme++/key.h>
using namespace Kleo;
using namespace Kleo::Dialogs;
using namespace GpgME;
class DeleteCertificatesDialog::Private
{
friend class ::Kleo::Dialogs::DeleteCertificatesDialog;
DeleteCertificatesDialog *const q;
public:
explicit Private(DeleteCertificatesDialog *qq)
: q(qq),
ui(q)
{
}
void slotWhatsThisRequested()
{
qCDebug(KLEOPATRA_LOG);
if (QWidget *const widget = qobject_cast<QWidget *>(q->sender()))
if (!widget->whatsThis().isEmpty()) {
QWhatsThis::showText(QCursor::pos(), widget->whatsThis());
}
}
void readConfig()
{
- KConfigGroup dialog(KSharedConfig::openConfig(), "DeleteCertificatesDialog");
+ KConfigGroup dialog(KSharedConfig::openStateConfig(), "DeleteCertificatesDialog");
ui.selectedKTV.restoreLayout(dialog);
ui.unselectedKTV.restoreLayout(dialog);
const QSize size = dialog.readEntry("Size", QSize(600, 400));
if (size.isValid()) {
q->resize(size);
}
}
void writeConfig()
{
- KConfigGroup dialog(KSharedConfig::openConfig(), "DeleteCertificatesDialog");
+ KConfigGroup dialog(KSharedConfig::openStateConfig(), "DeleteCertificatesDialog");
ui.selectedKTV.saveLayout(dialog);
dialog.writeEntry("Size", q->size());
dialog.sync();
}
private:
struct UI {
QLabel selectedLB;
KeyTreeView selectedKTV;
QLabel unselectedLB;
KeyTreeView unselectedKTV;
QDialogButtonBox buttonBox;
QVBoxLayout vlay;
explicit UI(DeleteCertificatesDialog *qq)
: selectedLB(i18n("These are the certificates you have selected for deletion:"), qq),
selectedKTV(qq),
unselectedLB(i18n("These certificates will be deleted even though you did <b>not</b> "
"explicitly select them (<a href=\"whatsthis://\">Why?</a>):"), qq),
unselectedKTV(qq),
buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel),
vlay(qq)
{
KDAB_SET_OBJECT_NAME(selectedLB);
KDAB_SET_OBJECT_NAME(selectedKTV);
KDAB_SET_OBJECT_NAME(unselectedLB);
KDAB_SET_OBJECT_NAME(unselectedKTV);
KDAB_SET_OBJECT_NAME(buttonBox);
KDAB_SET_OBJECT_NAME(vlay);
vlay.addWidget(&selectedLB);
vlay.addWidget(&selectedKTV, 1);
vlay.addWidget(&unselectedLB);
vlay.addWidget(&unselectedKTV, 1);
vlay.addWidget(&buttonBox);
const QString unselectedWhatsThis
= xi18nc("@info:whatsthis",
"<title>Why do you want to delete more certificates than I selected?</title>"
"<para>When you delete CA certificates (both root CAs and intermediate CAs), "
"the certificates issued by them will also be deleted.</para>"
"<para>This can be nicely seen in <application>Kleopatra</application>'s "
"hierarchical view mode: In this mode, if you delete a certificate that has "
"children, those children will also be deleted. Think of CA certificates as "
"folders containing other certificates: When you delete the folder, you "
"delete its contents, too.</para>");
unselectedLB.setContextMenuPolicy(Qt::NoContextMenu);
unselectedLB.setWhatsThis(unselectedWhatsThis);
unselectedKTV.setWhatsThis(unselectedWhatsThis);
buttonBox.button(QDialogButtonBox::Ok)->setText(i18nc("@action:button", "Delete"));
connect(&unselectedLB, SIGNAL(linkActivated(QString)), qq, SLOT(slotWhatsThisRequested()));
selectedKTV.setFlatModel(AbstractKeyListModel::createFlatKeyListModel(&selectedKTV));
unselectedKTV.setFlatModel(AbstractKeyListModel::createFlatKeyListModel(&unselectedKTV));
selectedKTV.setHierarchicalView(false);
selectedKTV.view()->setSelectionMode(QAbstractItemView::NoSelection);
unselectedKTV.setHierarchicalView(false);
unselectedKTV.view()->setSelectionMode(QAbstractItemView::NoSelection);
connect(&buttonBox, SIGNAL(accepted()), qq, SLOT(accept()));
connect(&buttonBox, &QDialogButtonBox::rejected, qq, &QDialog::reject);
}
} ui;
};
DeleteCertificatesDialog::DeleteCertificatesDialog(QWidget *p)
: QDialog(p), d(new Private(this))
{
d->readConfig();
}
DeleteCertificatesDialog::~DeleteCertificatesDialog()
{
d->writeConfig();
}
void DeleteCertificatesDialog::setSelectedKeys(const std::vector<Key> &keys)
{
d->ui.selectedKTV.setKeys(keys);
}
void DeleteCertificatesDialog::setUnselectedKeys(const std::vector<Key> &keys)
{
d->ui.unselectedLB .setVisible(!keys.empty());
d->ui.unselectedKTV.setVisible(!keys.empty());
d->ui.unselectedKTV.setKeys(keys);
}
std::vector<Key> DeleteCertificatesDialog::keys() const
{
const std::vector<Key> sel = d->ui.selectedKTV.keys();
const std::vector<Key> uns = d->ui.unselectedKTV.keys();
std::vector<Key> result;
result.reserve(sel.size() + uns.size());
result.insert(result.end(), sel.begin(), sel.end());
result.insert(result.end(), uns.begin(), uns.end());
return result;
}
void DeleteCertificatesDialog::accept()
{
const std::vector<Key> sel = d->ui.selectedKTV.keys();
const std::vector<Key> uns = d->ui.unselectedKTV.keys();
const uint secret = std::count_if(sel.cbegin(), sel.cend(), std::mem_fn(&Key::hasSecret))
+ std::count_if(uns.cbegin(), uns.cend(), std::mem_fn(&Key::hasSecret));
const uint total = sel.size() + uns.size();
int ret = KMessageBox::Continue;
if (secret)
ret = KMessageBox::warningContinueCancel(this,
secret == total
? i18np("The certificate to be deleted is your own. "
"It contains private key material, "
"which is needed to decrypt past communication "
"encrypted to the certificate, and should therefore "
"not be deleted.",
"All of the certificates to be deleted "
"are your own. "
"They contain private key material, "
"which is needed to decrypt past communication "
"encrypted to the certificate, and should therefore "
"not be deleted.",
secret)
: i18np("One of the certificates to be deleted "
"is your own. "
"It contains private key material, "
"which is needed to decrypt past communication "
"encrypted to the certificate, and should therefore "
"not be deleted.",
"Some of the certificates to be deleted "
"are your own. "
"They contain private key material, "
"which is needed to decrypt past communication "
"encrypted to the certificate, and should therefore "
"not be deleted.",
secret),
i18n("Secret Key Deletion"),
KStandardGuiItem::guiItem(KStandardGuiItem::Delete),
KStandardGuiItem::cancel(), QString(), KMessageBox::Notify | KMessageBox::Dangerous);
if (ret == KMessageBox::Continue) {
QDialog::accept();
} else {
QDialog::reject();
}
}
#include "moc_deletecertificatesdialog.cpp"
diff --git a/src/dialogs/exportdialog.cpp b/src/dialogs/exportdialog.cpp
index ad82f1e74..f2abd7bc2 100644
--- a/src/dialogs/exportdialog.cpp
+++ b/src/dialogs/exportdialog.cpp
@@ -1,227 +1,227 @@
/* SPDX-FileCopyrightText: 2017 Intevation GmbH
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "exportdialog.h"
#include "kleopatra_debug.h"
#include "view/waitwidget.h"
#include <QDialogButtonBox>
#include <QPushButton>
#include <QTextEdit>
#include <QVBoxLayout>
#include <gpgme++/key.h>
#include <QGpgME/Protocol>
#include <QGpgME/ExportJob>
#include <KLocalizedString>
#include <KSharedConfig>
#include <KConfigGroup>
#include <Libkleo/Formatting>
#include <gpgme++/gpgmepp_version.h>
#if GPGMEPP_VERSION >= 0x10E00 // 1.14.0
# define GPGME_HAS_EXPORT_FLAGS
#endif
using namespace Kleo;
class ExportWidget::Private
{
public:
Private(ExportWidget *qq)
: q(qq)
{}
void setupUi();
GpgME::Key key;
GpgME::Subkey subkey;
QTextEdit *textEdit;
WaitWidget *waitWidget;
unsigned int flags;
private:
ExportWidget *const q;
};
void ExportWidget::Private::setupUi()
{
auto vlay = new QVBoxLayout(q);
vlay->setContentsMargins(0, 0, 0, 0);
textEdit = new QTextEdit;
textEdit->setVisible(false);
textEdit->setReadOnly(true);
auto fixedFont = QFont(QStringLiteral("Monospace"));
fixedFont.setStyleHint(QFont::TypeWriter);
textEdit->setFont(fixedFont);
textEdit->setReadOnly(true);
vlay->addWidget(textEdit);
waitWidget = new WaitWidget;
waitWidget->setText(i18n("Exporting ..."));
vlay->addWidget(waitWidget);
}
ExportWidget::ExportWidget(QWidget *parent)
: QWidget(parent)
, d(new Private(this))
{
d->setupUi();
}
ExportWidget::~ExportWidget()
{
}
static QString injectComments(const GpgME::Key &key, const QByteArray &data)
{
QString ret = QString::fromUtf8(data);
if (key.protocol() != GpgME::OpenPGP) {
return ret;
}
auto overView = Formatting::toolTip(key, Formatting::Fingerprint |
Formatting::UserIDs |
Formatting::Issuer |
Formatting::Subject |
Formatting::ExpiryDates |
Formatting::CertificateType |
Formatting::CertificateUsage);
// Fixup the HTML coming from the toolTip for our own format.
overView.remove(QLatin1String("<tr><th>"));
overView.replace(QLatin1String("</th><td>"), QLatin1String("\t"));
overView.replace(QLatin1String("</td></tr>"), QLatin1String("\n"));
overView.remove(QLatin1String("<table border=\"0\">"));
overView.remove(QLatin1String("\n</table>"));
overView.replace(QLatin1String("<"), QLatin1String("<"));
overView.replace(QLatin1String(">"), QLatin1String(">"));
auto overViewLines = overView.split(QLatin1Char('\n'));
// Format comments so that they fit for RFC 4880
auto comments = QStringLiteral("Comment: ");
comments += overViewLines.join(QLatin1String("\nComment: ")) + QLatin1Char('\n');
ret.insert(37 /* -----BEGIN PGP PUBLIC KEY BLOCK-----\n */, comments);
return ret;
}
void ExportWidget::exportResult(const GpgME::Error &err, const QByteArray &data)
{
d->waitWidget->setVisible(false);
d->textEdit->setVisible(true);
if (err) {
/* Should not happen. But well,.. */
d->textEdit->setText(i18nc("%1 is error message", "Failed to export: '%1'", QString::fromLatin1(err.asString())));
}
if (!d->flags) {
d->textEdit->setText(injectComments(d->key, data));
} else {
d->textEdit->setText(QString::fromUtf8(data));
}
}
void ExportWidget::setKey(const GpgME::Subkey &key, unsigned int flags)
{
d->waitWidget->setVisible(true);
d->textEdit->setVisible(false);
d->key = key.parent();
d->subkey = key;
d->flags = flags;
auto protocol = d->key.protocol() == GpgME::CMS ?
QGpgME::smime() : QGpgME::openpgp();
auto job = protocol->publicKeyExportJob(true);
connect(job, &QGpgME::ExportJob::result,
this, &ExportWidget::exportResult);
#ifdef GPGME_HAS_EXPORT_FLAGS
job->setExportFlags(flags);
#endif
job->start(QStringList() << QLatin1String(key.fingerprint()) + QLatin1Char('!'));
}
void ExportWidget::setKey(const GpgME::Key &key, unsigned int flags)
{
d->waitWidget->setVisible(true);
d->textEdit->setVisible(false);
d->key = key;
d->flags = flags;
auto protocol = key.protocol() == GpgME::CMS ?
QGpgME::smime() : QGpgME::openpgp();
auto job = protocol->publicKeyExportJob(true);
connect(job, &QGpgME::ExportJob::result,
this, &ExportWidget::exportResult);
#ifdef GPGME_HAS_EXPORT_FLAGS
job->setExportFlags(flags);
#endif
job->start(QStringList() << QLatin1String(key.primaryFingerprint()));
}
GpgME::Key ExportWidget::key() const
{
return d->key;
}
ExportDialog::ExportDialog(QWidget *parent)
: QDialog(parent),
mWidget(new ExportWidget(this))
{
- KConfigGroup dialog(KSharedConfig::openConfig(), "ExportDialog");
+ KConfigGroup dialog(KSharedConfig::openStateConfig(), "ExportDialog");
const auto size = dialog.readEntry("Size", QSize(600, 800));
if (size.isValid()) {
resize(size);
}
setWindowTitle(i18nc("@title:window", "Export"));
auto l = new QVBoxLayout(this);
l->addWidget(mWidget);
auto bbox = new QDialogButtonBox(this);
auto btn = bbox->addButton(QDialogButtonBox::Close);
connect(btn, &QPushButton::pressed, this, &QDialog::accept);
l->addWidget(bbox);
}
ExportDialog::~ExportDialog()
{
- KConfigGroup dialog(KSharedConfig::openConfig(), "ExportDialog");
+ KConfigGroup dialog(KSharedConfig::openStateConfig(), "ExportDialog");
dialog.writeEntry("Size", size());
dialog.sync();
}
void ExportDialog::setKey(const GpgME::Key &key, unsigned int flags)
{
mWidget->setKey(key, flags);
}
void ExportDialog::setKey(const GpgME::Subkey &key, unsigned int flags)
{
mWidget->setKey(key, flags);
}
GpgME::Key ExportDialog::key() const
{
return mWidget->key();
}
diff --git a/src/dialogs/groupdetailsdialog.cpp b/src/dialogs/groupdetailsdialog.cpp
index a786a4575..d0d3e155b 100644
--- a/src/dialogs/groupdetailsdialog.cpp
+++ b/src/dialogs/groupdetailsdialog.cpp
@@ -1,156 +1,156 @@
/*
dialogs/groupdetailsdialog.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2021 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "groupdetailsdialog.h"
#include "commands/detailscommand.h"
#include "view/keytreeview.h"
#include <Libkleo/KeyGroup>
#include <Libkleo/KeyListModel>
#include <KConfigGroup>
#include <KGuiItem>
#include <KLocalizedString>
#include <KSharedConfig>
#include <KStandardGuiItem>
#include <QDialogButtonBox>
#include <QLabel>
#include <QPushButton>
#include <QTreeView>
#include <QVBoxLayout>
#include "kleopatra_debug.h"
using namespace Kleo;
using namespace Kleo::Commands;
using namespace Kleo::Dialogs;
Q_DECLARE_METATYPE(GpgME::Key)
class GroupDetailsDialog::Private
{
friend class ::Kleo::Dialogs::GroupDetailsDialog;
GroupDetailsDialog *const q;
struct {
QLabel *groupNameLabel = nullptr;
QLabel *groupCommentLabel = nullptr;
KeyTreeView *treeView = nullptr;
QDialogButtonBox *buttonBox = nullptr;
} ui;
KeyGroup group;
public:
Private(GroupDetailsDialog *qq)
: q(qq)
{
auto mainLayout = new QVBoxLayout(q);
ui.groupNameLabel = new QLabel();
ui.groupNameLabel->setWordWrap(true);
mainLayout->addWidget(ui.groupNameLabel);
ui.groupCommentLabel = new QLabel();
ui.groupCommentLabel->setWordWrap(true);
ui.groupCommentLabel->setVisible(false);
mainLayout->addWidget(ui.groupCommentLabel);
ui.treeView = new KeyTreeView(q);
ui.treeView->view()->setRootIsDecorated(false);
ui.treeView->view()->setSelectionMode(QAbstractItemView::SingleSelection);
ui.treeView->setFlatModel(AbstractKeyListModel::createFlatKeyListModel(ui.treeView));
ui.treeView->setHierarchicalView(false);
connect(ui.treeView->view(), &QAbstractItemView::doubleClicked,
q, [this] (const QModelIndex &index) { showKeyDetails(index); });
mainLayout->addWidget(ui.treeView);
ui.buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
KGuiItem::assign(ui.buttonBox->button(QDialogButtonBox::Close), KStandardGuiItem::close());
connect(ui.buttonBox, &QDialogButtonBox::rejected, q, &QDialog::close);
mainLayout->addWidget(ui.buttonBox);
// calculate default size with enough space for the key list
const auto fm = ui.treeView->fontMetrics();
const QSize sizeHint = q->sizeHint();
const QSize defaultSize = QSize(qMax(sizeHint.width(), 150 * fm.horizontalAdvance(QLatin1Char('x'))),
sizeHint.height() - ui.treeView->sizeHint().height() + 20 * fm.lineSpacing());
restoreLayout(defaultSize);
}
~Private()
{
saveLayout();
}
private:
void saveLayout()
{
- KConfigGroup configGroup(KSharedConfig::openConfig(), "GroupDetailsDialog");
+ KConfigGroup configGroup(KSharedConfig::openStateConfig(), "GroupDetailsDialog");
ui.treeView->saveLayout(configGroup);
configGroup.writeEntry("Size", q->size());
configGroup.sync();
}
void restoreLayout(const QSize &defaultSize)
{
- const KConfigGroup configGroup(KSharedConfig::openConfig(), "GroupDetailsDialog");
+ const KConfigGroup configGroup(KSharedConfig::openStateConfig(), "GroupDetailsDialog");
ui.treeView->restoreLayout(configGroup);
const QSize size = configGroup.readEntry("Size", defaultSize);
if (size.isValid()) {
q->resize(size);
}
}
void showKeyDetails(const QModelIndex &index)
{
const GpgME::Key key = ui.treeView->view()->model()->data(index, KeyList::KeyRole).value<GpgME::Key>();
if (!key.isNull()) {
auto cmd = new DetailsCommand(key, nullptr);
cmd->setParentWidget(q);
cmd->start();
}
}
};
GroupDetailsDialog::GroupDetailsDialog(QWidget *parent)
: QDialog(parent)
, d(new Private(this))
{
setWindowTitle(i18nc("@title:window", "Group Details"));
}
GroupDetailsDialog::~GroupDetailsDialog()
{
}
namespace
{
QString groupComment(const KeyGroup &group)
{
switch (group.source()) {
case KeyGroup::GnuPGConfig:
return i18n("Note: This group is defined in the configuration files of gpg.");
default:
return QString();
}
}
}
void GroupDetailsDialog::setGroup(const KeyGroup &group)
{
d->group = group;
d->ui.groupNameLabel->setText(group.name());
d->ui.groupCommentLabel->setText(groupComment(group));
d->ui.groupCommentLabel->setVisible(!d->ui.groupCommentLabel->text().isEmpty());
const KeyGroup::Keys &keys = group.keys();
d->ui.treeView->setKeys(std::vector<GpgME::Key>(keys.cbegin(), keys.cend()));
}
diff --git a/src/dialogs/revokecertificationdialog.cpp b/src/dialogs/revokecertificationdialog.cpp
index a49e75535..65850b18b 100644
--- a/src/dialogs/revokecertificationdialog.cpp
+++ b/src/dialogs/revokecertificationdialog.cpp
@@ -1,143 +1,143 @@
/* -*- mode: c++; c-basic-offset:4 -*-
dialogs/revokecertificationdialog.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2020 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-kleopatra.h>
#include "revokecertificationdialog.h"
#include "revokecertificationwidget.h"
#include <Libkleo/Formatting>
#include <KConfigGroup>
#include <KGuiItem>
#include <KLocalizedString>
#include <KSharedConfig>
#include <KStandardGuiItem>
#include <QAbstractButton>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QVBoxLayout>
#include "kleopatra_debug.h"
using namespace GpgME;
using namespace Kleo;
class RevokeCertificationDialog::Private
{
friend class ::Kleo::RevokeCertificationDialog;
RevokeCertificationDialog *const q;
public:
explicit Private(RevokeCertificationDialog *qq);
~Private();
private:
void saveGeometry();
void restoreGeometry(const QSize &defaultSize);
private:
RevokeCertificationWidget *mainWidget = nullptr;
};
RevokeCertificationDialog::Private::Private(RevokeCertificationDialog *qq)
: q(qq)
{
}
RevokeCertificationDialog::Private::~Private()
{
}
void RevokeCertificationDialog::Private::saveGeometry()
{
- KConfigGroup cfgGroup(KSharedConfig::openConfig(), "RevokeCertificationDialog");
+ KConfigGroup cfgGroup(KSharedConfig::openStateConfig(), "RevokeCertificationDialog");
cfgGroup.writeEntry("geometry", q->saveGeometry());
cfgGroup.sync();
}
void RevokeCertificationDialog::Private::restoreGeometry(const QSize &defaultSize)
{
- KConfigGroup cfgGroup(KSharedConfig::openConfig(), "RevokeCertificationDialog");
+ KConfigGroup cfgGroup(KSharedConfig::openStateConfig(), "RevokeCertificationDialog");
const QByteArray geometry = cfgGroup.readEntry("geometry", QByteArray());
if (!geometry.isEmpty()) {
q->restoreGeometry(geometry);
} else {
q->resize(defaultSize);
}
}
RevokeCertificationDialog::RevokeCertificationDialog(QWidget *p, Qt::WindowFlags f)
: QDialog(p, f)
, d(new Private(this))
{
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
auto mainLay = new QVBoxLayout(this);
d->mainWidget = new RevokeCertificationWidget(this);
mainLay->addWidget(d->mainWidget);
QDialogButtonBox *buttonBox = new QDialogButtonBox();
mainLay->addWidget(buttonBox);
buttonBox->setStandardButtons(QDialogButtonBox::Cancel |
QDialogButtonBox::Ok);
KGuiItem::assign(buttonBox->button(QDialogButtonBox::Ok), KStandardGuiItem::ok());
KGuiItem::assign(buttonBox->button(QDialogButtonBox::Cancel), KStandardGuiItem::cancel());
buttonBox->button(QDialogButtonBox::Ok)->setText(i18n("Revoke Certification"));
connect(buttonBox->button(QDialogButtonBox::Ok), &QAbstractButton::clicked,
this, [this] () {
d->mainWidget->saveConfig();
accept();
});
connect(buttonBox->button(QDialogButtonBox::Cancel), &QAbstractButton::clicked,
this, [this] () { close(); });
d->restoreGeometry(QSize(640, 480));
}
RevokeCertificationDialog::~RevokeCertificationDialog()
{
d->saveGeometry();
}
void RevokeCertificationDialog::setCertificateToRevoke(const Key &key)
{
setWindowTitle(i18nc("@title:window arg is name, email of certificate holder",
"Revoke Certification: %1", Formatting::prettyName(key)));
d->mainWidget->setTarget(key);
}
void RevokeCertificationDialog::setSelectedUserIDs(const std::vector<UserID> &uids)
{
d->mainWidget->setSelectUserIDs(uids);
}
std::vector<GpgME::UserID> RevokeCertificationDialog::selectedUserIDs() const
{
return d->mainWidget->selectedUserIDs();
}
void Kleo::RevokeCertificationDialog::setSelectedCertificationKey(const GpgME::Key &key)
{
d->mainWidget->setCertificationKey(key);
}
Key RevokeCertificationDialog::selectedCertificationKey() const
{
return d->mainWidget->certificationKey();
}
bool RevokeCertificationDialog::sendToServer() const
{
return d->mainWidget->publishSelected();
}
diff --git a/src/dialogs/subkeyswidget.cpp b/src/dialogs/subkeyswidget.cpp
index b3ecb5baa..9b3e4c183 100644
--- a/src/dialogs/subkeyswidget.cpp
+++ b/src/dialogs/subkeyswidget.cpp
@@ -1,255 +1,255 @@
/* SPDX-FileCopyrightText: 2016 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2017 Bundesamt für Sicherheit in der Informationstechnik
SPDX-FileContributor: Intevation GmbH
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "subkeyswidget.h"
#include "ui_subkeyswidget.h"
#include "commands/changeexpirycommand.h"
#include "commands/keytocardcommand.h"
#include "commands/importpaperkeycommand.h"
#include "exportdialog.h"
#include <gpgme++/key.h>
#include <gpgme++/context.h>
#include <KConfigGroup>
#include <KSharedConfig>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QTreeWidgetItem>
#include <QMenu>
#include <gpgme++/gpgmepp_version.h>
#if GPGMEPP_VERSION >= 0x10E00 // 1.14.0
# define GPGME_HAS_EXPORT_FLAGS
#endif
#if GPGMEPP_VERSION >= 0x10E01 // 1.14.1
# define CHANGEEXPIRYJOB_SUPPORTS_SUBKEYS
#endif
#include <Libkleo/Formatting>
Q_DECLARE_METATYPE(GpgME::Subkey)
using namespace Kleo;
using namespace Kleo::Commands;
class SubKeysWidget::Private
{
public:
Private(SubKeysWidget *q)
: q(q)
{
ui.setupUi(q);
ui.subkeysTree->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui.subkeysTree, &QAbstractItemView::customContextMenuRequested,
q, [this](const QPoint &p) { tableContextMenuRequested(p); });
}
GpgME::Key key;
Ui::SubKeysWidget ui;
void tableContextMenuRequested(const QPoint &p);
private:
SubKeysWidget *const q;
};
void SubKeysWidget::Private::tableContextMenuRequested(const QPoint &p)
{
auto item = ui.subkeysTree->itemAt(p);
if (!item) {
return;
}
const auto subkey = item->data(0, Qt::UserRole).value<GpgME::Subkey>();
QMenu *menu = new QMenu(q);
connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater);
bool hasActions = false;
#ifdef CHANGEEXPIRYJOB_SUPPORTS_SUBKEYS
if (subkey.parent().protocol() == GpgME::OpenPGP && subkey.parent().hasSecret()) {
hasActions = true;
menu->addAction(i18n("Change Expiry Date..."), q,
[this, subkey]() {
auto cmd = new ChangeExpiryCommand(subkey.parent());
if (subkey.keyID() != key.keyID()) {
// do not set the primary key as subkey
cmd->setSubkey(subkey);
}
ui.subkeysTree->setEnabled(false);
connect(cmd, &ChangeExpiryCommand::finished,
q, [this]() {
ui.subkeysTree->setEnabled(true);
key.update();
q->setKey(key);
});
cmd->setParentWidget(q);
cmd->start();
}
);
}
#endif // CHANGEEXPIRYJOB_SUPPORTS_SUBKEYS
#ifdef GPGME_HAS_EXPORT_FLAGS
if (subkey.parent().protocol() == GpgME::OpenPGP && subkey.canAuthenticate()) {
hasActions = true;
menu->addAction(QIcon::fromTheme(QStringLiteral("view-certificate-export")),
i18n("Export OpenSSH key"),
q, [this, subkey]() {
QScopedPointer<ExportDialog> dlg(new ExportDialog(q));
dlg->setKey(subkey, static_cast<unsigned int> (GpgME::Context::ExportSSH));
dlg->exec();
});
}
#endif // GPGME_HAS_EXPORT_FLAGS
if (!subkey.isSecret()) {
hasActions = true;
menu->addAction(QIcon::fromTheme(QStringLiteral("view-certificate-import")),
i18n("Restore printed backup"),
q, [this, subkey] () {
auto cmd = new ImportPaperKeyCommand(subkey.parent());
ui.subkeysTree->setEnabled(false);
connect(cmd, &ImportPaperKeyCommand::finished,
q, [this]() { ui.subkeysTree->setEnabled(true); });
cmd->setParentWidget(q);
cmd->start();
});
}
if (subkey.isSecret()) {
hasActions = true;
auto action = menu->addAction(QIcon::fromTheme(QStringLiteral("send-to-symbolic")),
i18n("Transfer to smartcard"),
q, [this, subkey]() {
auto cmd = new KeyToCardCommand(subkey);
ui.subkeysTree->setEnabled(false);
connect(cmd, &KeyToCardCommand::finished,
q, [this]() { ui.subkeysTree->setEnabled(true); });
cmd->setParentWidget(q);
cmd->start();
});
action->setEnabled(!KeyToCardCommand::getSuitableCards(subkey).empty());
}
if (hasActions) {
menu->popup(ui.subkeysTree->viewport()->mapToGlobal(p));
} else {
delete menu;
}
}
SubKeysWidget::SubKeysWidget(QWidget *parent)
: QWidget(parent)
, d(new Private(this))
{
}
SubKeysWidget::~SubKeysWidget()
{
}
void SubKeysWidget::setKey(const GpgME::Key &key)
{
d->key = key;
const auto currentItem = d->ui.subkeysTree->currentItem();
const QByteArray selectedKeyFingerprint = currentItem ?
QByteArray(currentItem->data(0, Qt::UserRole).value<GpgME::Subkey>().fingerprint()) : QByteArray();
d->ui.subkeysTree->clear();
for (const auto &subkey : key.subkeys()) {
auto item = new QTreeWidgetItem();
item->setData(0, Qt::DisplayRole, Formatting::prettyID(subkey.keyID()));
item->setData(0, Qt::UserRole, QVariant::fromValue(subkey));
item->setData(1, Qt::DisplayRole, Kleo::Formatting::type(subkey));
item->setData(2, Qt::DisplayRole, Kleo::Formatting::creationDateString(subkey));
item->setData(3, Qt::DisplayRole, Kleo::Formatting::expirationDateString(subkey));
item->setData(4, Qt::DisplayRole, Kleo::Formatting::validityShort(subkey));
switch (subkey.publicKeyAlgorithm()) {
case GpgME::Subkey::AlgoECDSA:
case GpgME::Subkey::AlgoEDDSA:
case GpgME::Subkey::AlgoECDH:
item->setData(5, Qt::DisplayRole, QString::fromStdString(subkey.algoName()));
break;
default:
item->setData(5, Qt::DisplayRole, QString::number(subkey.length()));
}
item->setData(6, Qt::DisplayRole, Kleo::Formatting::usageString(subkey));
item->setData(7, Qt::DisplayRole, subkey.keyID() == key.keyID() ? QStringLiteral("✓") : QString());
d->ui.subkeysTree->addTopLevelItem(item);
if (subkey.fingerprint() == selectedKeyFingerprint) {
d->ui.subkeysTree->setCurrentItem(item);
}
}
const auto subkey = key.subkey(0);
if (const char *card = subkey.cardSerialNumber()) {
d->ui.stored->setText(i18nc("stored...", "on SmartCard with serial no. %1", QString::fromUtf8(card)));
} else {
d->ui.stored->setText(i18nc("stored...", "on this computer"));
}
d->ui.subkeysTree->resizeColumnToContents(0);
}
GpgME::Key SubKeysWidget::key() const
{
return d->key;
}
SubKeysDialog::SubKeysDialog(QWidget *parent)
: QDialog(parent)
{
setWindowTitle(i18nc("@title:window", "Subkeys Details"));
auto l = new QVBoxLayout(this);
l->addWidget(new SubKeysWidget(this));
auto bbox = new QDialogButtonBox(this);
auto btn = bbox->addButton(QDialogButtonBox::Close);
connect(btn, &QPushButton::clicked, this, &QDialog::accept);
l->addWidget(bbox);
readConfig();
}
SubKeysDialog::~SubKeysDialog()
{
writeConfig();
}
void SubKeysDialog::readConfig()
{
- KConfigGroup dialog(KSharedConfig::openConfig(), "SubKeysDialog");
+ KConfigGroup dialog(KSharedConfig::openStateConfig(), "SubKeysDialog");
const QSize size = dialog.readEntry("Size", QSize(820, 280));
if (size.isValid()) {
resize(size);
}
}
void SubKeysDialog::writeConfig()
{
- KConfigGroup dialog(KSharedConfig::openConfig(), "SubKeysDialog");
+ KConfigGroup dialog(KSharedConfig::openStateConfig(), "SubKeysDialog");
dialog.writeEntry("Size", size());
dialog.sync();
}
void SubKeysDialog::setKey(const GpgME::Key &key)
{
auto w = findChild<SubKeysWidget*>();
Q_ASSERT(w);
w->setKey(key);
}
GpgME::Key SubKeysDialog::key() const
{
auto w = findChild<SubKeysWidget*>();
Q_ASSERT(w);
return w->key();
}
diff --git a/src/dialogs/weboftrustdialog.cpp b/src/dialogs/weboftrustdialog.cpp
index 7adfcdd33..ba777d422 100644
--- a/src/dialogs/weboftrustdialog.cpp
+++ b/src/dialogs/weboftrustdialog.cpp
@@ -1,56 +1,56 @@
/* SPDX-FileCopyrightText: 2017 Intevation GmbH
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "weboftrustdialog.h"
#include "weboftrustwidget.h"
#include <QDialogButtonBox>
#include <QPushButton>
#include <QVBoxLayout>
#include <gpgme++/key.h>
#include <KLocalizedString>
#include <KSharedConfig>
#include <KConfigGroup>
using namespace Kleo;
WebOfTrustDialog::WebOfTrustDialog(QWidget *parent)
: QDialog(parent)
{
- KConfigGroup dialog(KSharedConfig::openConfig(), "WebOfTrustDialog");
+ KConfigGroup dialog(KSharedConfig::openStateConfig(), "WebOfTrustDialog");
const QSize size = dialog.readEntry("Size", QSize(900, 400));
if (size.isValid()) {
resize(size);
}
setWindowTitle(i18nc("@title:window", "Certifications"));
mWidget = new WebOfTrustWidget(this);
auto l = new QVBoxLayout(this);
l->addWidget(mWidget);
auto bbox = new QDialogButtonBox(this);
auto btn = bbox->addButton(QDialogButtonBox::Close);
connect(btn, &QPushButton::pressed, this, &QDialog::accept);
l->addWidget(bbox);
}
void WebOfTrustDialog::setKey(const GpgME::Key &key)
{
mWidget->setKey(key);
}
GpgME::Key WebOfTrustDialog::key() const
{
return mWidget->key();
}
WebOfTrustDialog::~WebOfTrustDialog()
{
- KConfigGroup dialog(KSharedConfig::openConfig(), "WebOfTrustDialog");
+ KConfigGroup dialog(KSharedConfig::openStateConfig(), "WebOfTrustDialog");
dialog.writeEntry("Size", size());
dialog.sync();
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Feb 26, 7:03 PM (1 d, 12 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
43/ed/65988c7eb4519f83c625b6a0dcb3
Attached To
rKLEOPATRA Kleopatra
Event Timeline
Log In to Comment