Page MenuHome GnuPG

cryptoconfigmodule.cpp
No OneTemporary

cryptoconfigmodule.cpp

/*
cryptoconfigmodule.cpp
This file is part of kgpgcertmanager
SPDX-FileCopyrightText: 2004 Klarälvdalens Datakonsult AB
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-libkleo.h>
#include "cryptoconfigmodule.h"
#include "cryptoconfigentryreaderport_p.h"
#include "cryptoconfigmodule_p.h"
#include "directoryserviceswidget.h"
#include "filenamerequester.h"
#include <libkleo/compliance.h>
#include <libkleo/formatting.h>
#include <libkleo/gnupg.h>
#include <libkleo/keyserverconfig.h>
#include <kleo_ui_debug.h>
#include <KLazyLocalizedString>
#include <KLineEdit>
#include <KLocalizedString>
#include <KMessageBox>
#include <KSeparator>
#include <QGpgME/CryptoConfig>
#include <QCheckBox>
#include <QComboBox>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QIcon>
#include <QLabel>
#include <QLayout>
#include <QPushButton>
#include <QRegularExpression>
#include <QScreen>
#include <QScrollArea>
#include <QSpinBox>
#include <QStyle>
#include <QVBoxLayout>
#include <gpgme.h>
#include <array>
#include <limits>
#include <memory>
#include <set>
using namespace Kleo;
inline QIcon loadIcon(const QString &s)
{
QString ss = s;
const static QRegularExpression reg(QRegularExpression(QLatin1StringView("[^a-zA-Z0-9_]")));
return QIcon::fromTheme(ss.replace(reg, QStringLiteral("-")));
}
Kleo::CryptoConfigModule::CryptoConfigModule(QGpgME::CryptoConfig *config, QWidget *parent)
: QTabWidget(parent)
, mConfig(config)
{
init();
}
void Kleo::CryptoConfigModule::init()
{
if (layout()) {
layout()->setContentsMargins(0, 0, 0, 0);
}
setDocumentMode(true);
QGpgME::CryptoConfig *const config = mConfig;
const QStringList components = sortComponentList(config->componentList());
for (QStringList::const_iterator it = components.begin(); it != components.end(); ++it) {
// qCDebug(KLEO_UI_LOG) <<"Component" << (*it).toLocal8Bit() <<":";
QGpgME::CryptoConfigComponent *comp = config->component(*it);
Q_ASSERT(comp);
if (comp->groupList().empty()) {
continue;
}
std::unique_ptr<CryptoConfigComponentGUI> compGUI(new CryptoConfigComponentGUI(this, comp));
compGUI->setObjectName(*it);
mComponentGUIs.append(compGUI.get());
auto scrollArea = new QScrollArea(this);
scrollArea->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
scrollArea->setWidgetResizable(true);
addTab(scrollArea, comp->description());
scrollArea->setWidget(compGUI.release());
}
if (mComponentGUIs.empty()) {
const QString msg = i18n(
"The gpgconf tool used to provide the information "
"for this dialog does not seem to be installed "
"properly. It did not return any components. "
"Try running \"%1\" on the command line for more "
"information.",
components.empty() ? QLatin1StringView("gpgconf --list-components") : QLatin1String("gpgconf --list-options gpg"));
auto layout = new QVBoxLayout;
setLayout(layout);
auto label = new QLabel(msg, this);
label->setWordWrap(true);
label->setMinimumHeight(fontMetrics().lineSpacing() * 5);
layout->addWidget(label);
}
}
namespace
{
template<typename Iterator>
QStringList sortConfigEntries(const Iterator orderBegin, const Iterator orderEnd, const QStringList &entries)
{
// components sorting algorithm:
// 1. components with predefined order (provided via orderBegin / orderEnd)
// 2. other components sorted alphabetically
QStringList result;
QStringList others;
for (auto it = orderBegin; it != orderEnd; ++it) {
if (entries.contains(*it)) {
result.append(*it);
}
}
for (const auto &item : entries) {
if (!result.contains(item)) {
others.append(item);
}
}
others.sort();
result.append(others);
return result;
}
} // namespace
QStringList Kleo::CryptoConfigModule::sortComponentList(const QStringList &components)
{
static const std::array<QString, 6> order = {
QStringLiteral("gpg"),
QStringLiteral("gpgsm"),
QStringLiteral("gpg-agent"),
QStringLiteral("dirmngr"),
QStringLiteral("pinentry"),
QStringLiteral("scdaemon"),
};
return sortConfigEntries(order.begin(), order.end(), components);
}
QStringList Kleo::CryptoConfigModule::sortGroupList(const QString &moduleName, const QStringList &groups)
{
if (moduleName == QStringLiteral("gpg")) {
static const std::array<QString, 4> order = {
QStringLiteral("Keyserver"),
QStringLiteral("Configuration"),
QStringLiteral("Monitor"),
QStringLiteral("Debug"),
};
return sortConfigEntries(order.begin(), order.end(), groups);
} else if (moduleName == QStringLiteral("gpgsm")) {
static const std::array<QString, 4> order = {
QStringLiteral("Security"),
QStringLiteral("Configuration"),
QStringLiteral("Monitor"),
QStringLiteral("Debug"),
};
return sortConfigEntries(order.begin(), order.end(), groups);
} else if (moduleName == QStringLiteral("gpg-agent")) {
static const std::array<QString, 5> order = {
QStringLiteral("Security"),
QStringLiteral("Passphrase policy"),
QStringLiteral("Configuration"),
QStringLiteral("Monitor"),
QStringLiteral("Debug"),
};
return sortConfigEntries(order.begin(), order.end(), groups);
} else if (moduleName == QStringLiteral("dirmngr")) {
static const std::array<QString, 10> order = {
QStringLiteral("Keyserver"),
QStringLiteral("HTTP"),
QStringLiteral("LDAP"),
QStringLiteral("OCSP"),
QStringLiteral("Tor"),
QStringLiteral("Enforcement"),
QStringLiteral("Configuration"),
QStringLiteral("Format"),
QStringLiteral("Monitor"),
QStringLiteral("Debug"),
};
return sortConfigEntries(order.begin(), order.end(), groups);
} else if (moduleName == QStringLiteral("scdaemon")) {
static const std::array<QString, 4> order = {
QStringLiteral("Monitor"),
QStringLiteral("Configuration"),
QStringLiteral("Security"),
QStringLiteral("Debug"),
};
return sortConfigEntries(order.begin(), order.end(), groups);
} else {
qCDebug(KLEO_UI_LOG) << "Configuration groups order is not defined for " << moduleName;
QStringList result(groups);
result.sort();
return result;
}
}
bool Kleo::CryptoConfigModule::hasError() const
{
return mComponentGUIs.empty();
}
void Kleo::CryptoConfigModule::save()
{
bool changed = false;
QList<CryptoConfigComponentGUI *>::Iterator it = mComponentGUIs.begin();
for (; it != mComponentGUIs.end(); ++it) {
if ((*it)->save()) {
changed = true;
}
}
if (changed) {
mConfig->sync(true /*runtime*/);
}
}
void Kleo::CryptoConfigModule::reset()
{
QList<CryptoConfigComponentGUI *>::Iterator it = mComponentGUIs.begin();
for (; it != mComponentGUIs.end(); ++it) {
(*it)->load();
}
}
void Kleo::CryptoConfigModule::defaults()
{
QList<CryptoConfigComponentGUI *>::Iterator it = mComponentGUIs.begin();
for (; it != mComponentGUIs.end(); ++it) {
(*it)->defaults();
}
}
void Kleo::CryptoConfigModule::cancel()
{
mConfig->clear();
}
////
namespace
{
bool offerEntryForConfiguration(QGpgME::CryptoConfigEntry *entry)
{
static const QRegularExpression entryPathGroupSegmentRegexp{QStringLiteral("/.*/")};
static std::set<QString> entriesToExclude;
if (entriesToExclude.empty()) {
entriesToExclude.insert(QStringLiteral("gpg/keyserver"));
if (engineIsVersion(2, 3, 5, GpgME::GpgConfEngine)
|| (engineIsVersion(2, 2, 34, GpgME::GpgConfEngine) && !engineIsVersion(2, 3, 0, GpgME::GpgConfEngine))) {
// exclude for 2.2.{34,...} and 2.3.5+
entriesToExclude.insert(QStringLiteral("gpgsm/keyserver"));
}
}
const bool de_vs = DeVSCompliance::isActive();
// Skip "dangerous" expert options if we are running in CO_DE_VS.
// Otherwise, skip any options beyond "invisible" (== expert + 1) level.
const auto maxEntryLevel = de_vs ? QGpgME::CryptoConfigEntry::Level_Advanced //
: QGpgME::CryptoConfigEntry::Level_Expert + 1;
// we ignore the group when looking up entries to exclude because entries
// are uniquely identified by their name and their component
const auto entryId = entry->path().replace(entryPathGroupSegmentRegexp, QLatin1StringView{"/"}).toLower();
return (entry->level() <= maxEntryLevel) && (entriesToExclude.find(entryId) == entriesToExclude.end());
}
auto getGroupEntriesToOfferForConfiguration(QGpgME::CryptoConfigGroup *group)
{
std::vector<QGpgME::CryptoConfigEntry *> result;
const auto entryNames = group->entryList();
for (const auto &entryName : entryNames) {
auto *const entry = group->entry(entryName);
Q_ASSERT(entry);
if (offerEntryForConfiguration(entry)) {
result.push_back(entry);
} else {
qCDebug(KLEO_UI_LOG) << "entry" << entry->path() << "too advanced or excluded explicitly, skipping";
}
}
return result;
}
}
Kleo::CryptoConfigComponentGUI::CryptoConfigComponentGUI(CryptoConfigModule *module, QGpgME::CryptoConfigComponent *component, QWidget *parent)
: QWidget(parent)
, mComponent(component)
{
auto glay = new QGridLayout(this);
const QStringList groups = module->sortGroupList(mComponent->name(), mComponent->groupList());
if (groups.size() > 1) {
glay->setColumnMinimumWidth(0, 30);
for (QStringList::const_iterator it = groups.begin(), end = groups.end(); it != end; ++it) {
QGpgME::CryptoConfigGroup *group = mComponent->group(*it);
Q_ASSERT(group);
if (!group) {
continue;
}
auto groupEntries = getGroupEntriesToOfferForConfiguration(group);
if (groupEntries.size() == 0) {
// skip groups without entries to be offered in the UI
continue;
}
const QString title = group->description();
auto hbox = new QHBoxLayout;
hbox->addWidget(new QLabel{title.isEmpty() ? *it : title, this});
hbox->addWidget(new KSeparator{Qt::Horizontal, this}, 1);
const int row = glay->rowCount();
glay->addLayout(hbox, row, 0, 1, 3);
mGroupGUIs.append(new CryptoConfigGroupGUI(module, group, groupEntries, glay, this));
}
} else if (!groups.empty()) {
auto *const group = mComponent->group(groups.front());
auto groupEntries = getGroupEntriesToOfferForConfiguration(group);
if (groupEntries.size() > 0) {
mGroupGUIs.append(new CryptoConfigGroupGUI(module, group, groupEntries, glay, this));
}
}
glay->setRowStretch(glay->rowCount(), 1);
}
bool Kleo::CryptoConfigComponentGUI::save()
{
bool changed = false;
QList<CryptoConfigGroupGUI *>::Iterator it = mGroupGUIs.begin();
for (; it != mGroupGUIs.end(); ++it) {
if ((*it)->save()) {
changed = true;
}
}
return changed;
}
void Kleo::CryptoConfigComponentGUI::load()
{
QList<CryptoConfigGroupGUI *>::Iterator it = mGroupGUIs.begin();
for (; it != mGroupGUIs.end(); ++it) {
(*it)->load();
}
}
void Kleo::CryptoConfigComponentGUI::defaults()
{
QList<CryptoConfigGroupGUI *>::Iterator it = mGroupGUIs.begin();
for (; it != mGroupGUIs.end(); ++it) {
(*it)->defaults();
}
}
////
Kleo::CryptoConfigGroupGUI::CryptoConfigGroupGUI(CryptoConfigModule *module,
QGpgME::CryptoConfigGroup *group,
const std::vector<QGpgME::CryptoConfigEntry *> &entries,
QGridLayout *glay,
QWidget *widget)
: QObject(module)
{
const int startRow = glay->rowCount();
for (auto entry : entries) {
CryptoConfigEntryGUI *entryGUI = CryptoConfigEntryGUIFactory::createEntryGUI(module, entry, entry->name(), glay, widget);
if (entryGUI) {
mEntryGUIs.append(entryGUI);
entryGUI->load();
}
}
const int endRow = glay->rowCount() - 1;
if (endRow < startRow) {
return;
}
const QString iconName = group->iconName();
if (iconName.isEmpty()) {
return;
}
QLabel *l = new QLabel(widget);
l->setPixmap(loadIcon(iconName).pixmap(32, 32));
glay->addWidget(l, startRow, 0, endRow - startRow + 1, 1, Qt::AlignTop);
}
bool Kleo::CryptoConfigGroupGUI::save()
{
bool changed = false;
QList<CryptoConfigEntryGUI *>::Iterator it = mEntryGUIs.begin();
for (; it != mEntryGUIs.end(); ++it) {
if ((*it)->isChanged()) {
(*it)->save();
changed = true;
}
}
return changed;
}
void Kleo::CryptoConfigGroupGUI::load()
{
QList<CryptoConfigEntryGUI *>::Iterator it = mEntryGUIs.begin();
for (; it != mEntryGUIs.end(); ++it) {
(*it)->load();
}
}
void Kleo::CryptoConfigGroupGUI::defaults()
{
QList<CryptoConfigEntryGUI *>::Iterator it = mEntryGUIs.begin();
for (; it != mEntryGUIs.end(); ++it) {
(*it)->resetToDefault();
}
}
////
using constructor = CryptoConfigEntryGUI *(*)(CryptoConfigModule *, QGpgME::CryptoConfigEntry *, const QString &, QGridLayout *, QWidget *);
namespace
{
template<typename T_Widget>
CryptoConfigEntryGUI *_create(CryptoConfigModule *m, QGpgME::CryptoConfigEntry *e, const QString &n, QGridLayout *l, QWidget *p)
{
return new T_Widget(m, e, n, l, p);
}
}
static const struct WidgetsByEntryName {
const char *entryGlob;
constructor create;
} widgetsByEntryName[] = {
{"*/*/debug-level", &_create<CryptoConfigEntryDebugLevel>},
{"scdaemon/*/reader-port", &_create<CryptoConfigEntryReaderPort>},
};
static const unsigned int numWidgetsByEntryName = sizeof widgetsByEntryName / sizeof *widgetsByEntryName;
static const constructor listWidgets[QGpgME::CryptoConfigEntry::NumArgType] = {
// None: A list of options with no arguments (e.g. -v -v -v) is shown as a spinbox
&_create<CryptoConfigEntrySpinBox>,
nullptr, // String
// Int/UInt: Let people type list of numbers (1,2,3....). Untested.
&_create<CryptoConfigEntryLineEdit>,
&_create<CryptoConfigEntryLineEdit>,
nullptr, // Path
nullptr, // Formerly URL
&_create<CryptoConfigEntryLDAPURL>,
nullptr, // DirPath
};
static const constructor scalarWidgets[QGpgME::CryptoConfigEntry::NumArgType] = {
// clang-format off
&_create<CryptoConfigEntryCheckBox>, // None
&_create<CryptoConfigEntryLineEdit>, // String
&_create<CryptoConfigEntrySpinBox>, // Int
&_create<CryptoConfigEntrySpinBox>, // UInt
&_create<CryptoConfigEntryPath>, // Path
nullptr, // Formerly URL
nullptr, // LDAPURL
&_create<CryptoConfigEntryDirPath>, // DirPath
// clang-format on
};
CryptoConfigEntryGUI *Kleo::CryptoConfigEntryGUIFactory::createEntryGUI(CryptoConfigModule *module,
QGpgME::CryptoConfigEntry *entry,
const QString &entryName,
QGridLayout *glay,
QWidget *widget)
{
Q_ASSERT(entry);
// try to lookup by path:
const QString path = entry->path();
for (unsigned int i = 0; i < numWidgetsByEntryName; ++i) {
if (QRegularExpression::fromWildcard(QString::fromLatin1(widgetsByEntryName[i].entryGlob), Qt::CaseSensitive).match(path).hasMatch()) {
return widgetsByEntryName[i].create(module, entry, entryName, glay, widget);
}
}
// none found, so look up by type:
const unsigned int argType = entry->argType();
Q_ASSERT(argType < QGpgME::CryptoConfigEntry::NumArgType);
if (entry->isList()) {
if (const constructor create = listWidgets[argType]) {
return create(module, entry, entryName, glay, widget);
} else {
qCWarning(KLEO_UI_LOG) << "No widget implemented for list of type" << entry->argType();
}
} else if (const constructor create = scalarWidgets[argType]) {
return create(module, entry, entryName, glay, widget);
} else {
qCWarning(KLEO_UI_LOG) << "No widget implemented for type" << entry->argType();
}
return nullptr;
}
////
Kleo::CryptoConfigEntryGUI::CryptoConfigEntryGUI(CryptoConfigModule *module, QGpgME::CryptoConfigEntry *entry, const QString &entryName)
: QObject(module)
, mEntry(entry)
, mName(entryName)
, mChanged(false)
{
connect(this, &CryptoConfigEntryGUI::changed, module, &CryptoConfigModule::changed);
}
QString Kleo::CryptoConfigEntryGUI::description() const
{
QString descr = mEntry->description();
if (descr.isEmpty()) { // happens for expert options
// String does not need to be translated because the options itself
// are also not translated
return QStringLiteral("\"%1\"").arg(mName);
}
if (i18nc("Translate this to 'yes' or 'no' (use the English words!) "
"depending on whether your language uses "
"Sentence style capitalization in GUI labels (yes) or not (no). "
"Context: We get some backend strings in that have the wrong "
"capitalization (in English, at least) so we need to force the "
"first character to upper-case. It is this behaviour you can "
"control for your language with this translation.",
"yes")
== QLatin1StringView("yes")) {
descr[0] = descr[0].toUpper();
}
return descr;
}
void Kleo::CryptoConfigEntryGUI::resetToDefault()
{
mEntry->resetToDefault();
load();
}
////
Kleo::CryptoConfigEntryLineEdit::CryptoConfigEntryLineEdit(CryptoConfigModule *module,
QGpgME::CryptoConfigEntry *entry,
const QString &entryName,
QGridLayout *glay,
QWidget *widget)
: CryptoConfigEntryGUI(module, entry, entryName)
{
const int row = glay->rowCount();
mLineEdit = new KLineEdit(widget);
QLabel *label = new QLabel(description(), widget);
label->setBuddy(mLineEdit);
glay->addWidget(label, row, 1);
glay->addWidget(mLineEdit, row, 2);
if (entry->isReadOnly()) {
label->setEnabled(false);
mLineEdit->setEnabled(false);
} else {
connect(mLineEdit, &KLineEdit::textChanged, this, &CryptoConfigEntryLineEdit::slotChanged);
}
}
void Kleo::CryptoConfigEntryLineEdit::doSave()
{
mEntry->setStringValue(mLineEdit->text());
}
void Kleo::CryptoConfigEntryLineEdit::doLoad()
{
mLineEdit->setText(mEntry->stringValue());
}
////
/* Note: Do not use "guru" as debug level but use the value 10. The
former also enables the creation of hash dump files and thus leaves
traces of plaintext on the disk. */
static const struct {
const KLazyLocalizedString label;
const char *name;
} debugLevels[] = {
{kli18n("0 - None"), "none"},
{kli18n("1 - Basic"), "basic"},
{kli18n("2 - Verbose"), "advanced"},
{kli18n("3 - More Verbose"), "expert"},
{kli18n("4 - All"), "10"},
};
static const unsigned int numDebugLevels = sizeof debugLevels / sizeof *debugLevels;
Kleo::CryptoConfigEntryDebugLevel::CryptoConfigEntryDebugLevel(CryptoConfigModule *module,
QGpgME::CryptoConfigEntry *entry,
const QString &entryName,
QGridLayout *glay,
QWidget *widget)
: CryptoConfigEntryGUI(module, entry, entryName)
, mComboBox(new QComboBox(widget))
{
QLabel *label = new QLabel(i18nc("@label:textbox", "Set the debugging level to"), widget);
label->setBuddy(mComboBox);
for (unsigned int i = 0; i < numDebugLevels; ++i) {
mComboBox->addItem(KLocalizedString(debugLevels[i].label).toString());
}
if (entry->isReadOnly()) {
label->setEnabled(false);
mComboBox->setEnabled(false);
} else {
connect(mComboBox, &QComboBox::currentIndexChanged, this, &CryptoConfigEntryDebugLevel::slotChanged);
}
const int row = glay->rowCount();
glay->addWidget(label, row, 1);
glay->addWidget(mComboBox, row, 2);
}
void Kleo::CryptoConfigEntryDebugLevel::doSave()
{
const unsigned int idx = mComboBox->currentIndex();
if (idx < numDebugLevels) {
mEntry->setStringValue(QLatin1StringView(debugLevels[idx].name));
} else {
mEntry->setStringValue(QString());
}
}
void Kleo::CryptoConfigEntryDebugLevel::doLoad()
{
const QString str = mEntry->stringValue();
for (unsigned int i = 0; i < numDebugLevels; ++i) {
if (str == QLatin1StringView(debugLevels[i].name)) {
mComboBox->setCurrentIndex(i);
return;
}
}
mComboBox->setCurrentIndex(0);
}
////
Kleo::CryptoConfigEntryPath::CryptoConfigEntryPath(CryptoConfigModule *module,
QGpgME::CryptoConfigEntry *entry,
const QString &entryName,
QGridLayout *glay,
QWidget *widget)
: CryptoConfigEntryGUI(module, entry, entryName)
, mFileNameRequester(nullptr)
{
const int row = glay->rowCount();
mFileNameRequester = new FileNameRequester(widget);
mFileNameRequester->setExistingOnly(false);
mFileNameRequester->setFilter(QDir::Files);
QLabel *label = new QLabel(description(), widget);
label->setBuddy(mFileNameRequester);
glay->addWidget(label, row, 1);
glay->addWidget(mFileNameRequester, row, 2);
if (entry->isReadOnly()) {
label->setEnabled(false);
mFileNameRequester->setEnabled(false);
} else {
connect(mFileNameRequester, &FileNameRequester::fileNameChanged, this, &CryptoConfigEntryPath::slotChanged);
}
}
void Kleo::CryptoConfigEntryPath::doSave()
{
mEntry->setURLValue(QUrl::fromLocalFile(mFileNameRequester->fileName()));
}
void Kleo::CryptoConfigEntryPath::doLoad()
{
if (mEntry->urlValue().isLocalFile()) {
mFileNameRequester->setFileName(mEntry->urlValue().toLocalFile());
} else {
mFileNameRequester->setFileName(mEntry->urlValue().toString());
}
}
////
Kleo::CryptoConfigEntryDirPath::CryptoConfigEntryDirPath(CryptoConfigModule *module,
QGpgME::CryptoConfigEntry *entry,
const QString &entryName,
QGridLayout *glay,
QWidget *widget)
: CryptoConfigEntryGUI(module, entry, entryName)
, mFileNameRequester(nullptr)
{
const int row = glay->rowCount();
mFileNameRequester = new FileNameRequester(widget);
mFileNameRequester->setExistingOnly(false);
mFileNameRequester->setFilter(QDir::Dirs);
QLabel *label = new QLabel(description(), widget);
label->setBuddy(mFileNameRequester);
glay->addWidget(label, row, 1);
glay->addWidget(mFileNameRequester, row, 2);
if (entry->isReadOnly()) {
label->setEnabled(false);
mFileNameRequester->setEnabled(false);
} else {
connect(mFileNameRequester, &FileNameRequester::fileNameChanged, this, &CryptoConfigEntryDirPath::slotChanged);
}
}
void Kleo::CryptoConfigEntryDirPath::doSave()
{
mEntry->setURLValue(QUrl::fromLocalFile(mFileNameRequester->fileName()));
}
void Kleo::CryptoConfigEntryDirPath::doLoad()
{
mFileNameRequester->setFileName(mEntry->urlValue().toLocalFile());
}
////
Kleo::CryptoConfigEntrySpinBox::CryptoConfigEntrySpinBox(CryptoConfigModule *module,
QGpgME::CryptoConfigEntry *entry,
const QString &entryName,
QGridLayout *glay,
QWidget *widget)
: CryptoConfigEntryGUI(module, entry, entryName)
{
if (entry->argType() == QGpgME::CryptoConfigEntry::ArgType_None && entry->isList()) {
mKind = ListOfNone;
} else if (entry->argType() == QGpgME::CryptoConfigEntry::ArgType_UInt) {
mKind = UInt;
} else {
Q_ASSERT(entry->argType() == QGpgME::CryptoConfigEntry::ArgType_Int);
mKind = Int;
}
const int row = glay->rowCount();
mNumInput = new QSpinBox(widget);
QLabel *label = new QLabel(description(), widget);
label->setBuddy(mNumInput);
glay->addWidget(label, row, 1);
glay->addWidget(mNumInput, row, 2);
if (entry->isReadOnly()) {
label->setEnabled(false);
mNumInput->setEnabled(false);
} else {
mNumInput->setMinimum(mKind == Int ? std::numeric_limits<int>::min() : 0);
mNumInput->setMaximum(std::numeric_limits<int>::max());
connect(mNumInput, &QSpinBox::valueChanged, this, &CryptoConfigEntrySpinBox::slotChanged);
}
}
void Kleo::CryptoConfigEntrySpinBox::doSave()
{
int value = mNumInput->value();
switch (mKind) {
case ListOfNone:
mEntry->setNumberOfTimesSet(value);
break;
case UInt:
mEntry->setUIntValue(value);
break;
case Int:
mEntry->setIntValue(value);
break;
}
}
void Kleo::CryptoConfigEntrySpinBox::doLoad()
{
int value = 0;
switch (mKind) {
case ListOfNone:
value = mEntry->numberOfTimesSet();
break;
case UInt:
value = mEntry->uintValue();
break;
case Int:
value = mEntry->intValue();
break;
}
mNumInput->setValue(value);
}
////
Kleo::CryptoConfigEntryCheckBox::CryptoConfigEntryCheckBox(CryptoConfigModule *module,
QGpgME::CryptoConfigEntry *entry,
const QString &entryName,
QGridLayout *glay,
QWidget *widget)
: CryptoConfigEntryGUI(module, entry, entryName)
{
const int row = glay->rowCount();
mCheckBox = new QCheckBox(widget);
glay->addWidget(mCheckBox, row, 1, 1, 2);
mCheckBox->setText(description());
if (entry->isReadOnly()) {
mCheckBox->setEnabled(false);
} else {
connect(mCheckBox, &QCheckBox::toggled, this, &CryptoConfigEntryCheckBox::slotChanged);
}
}
void Kleo::CryptoConfigEntryCheckBox::doSave()
{
mEntry->setBoolValue(mCheckBox->isChecked());
}
void Kleo::CryptoConfigEntryCheckBox::doLoad()
{
mCheckBox->setChecked(mEntry->boolValue());
}
Kleo::CryptoConfigEntryLDAPURL::CryptoConfigEntryLDAPURL(CryptoConfigModule *module,
QGpgME::CryptoConfigEntry *entry,
const QString &entryName,
QGridLayout *glay,
QWidget *widget)
: CryptoConfigEntryGUI(module, entry, entryName)
{
mLabel = new QLabel(widget);
mPushButton = new QPushButton(entry->isReadOnly() ? i18n("Show...") : i18n("Edit..."), widget);
const int row = glay->rowCount();
QLabel *label = new QLabel(description(), widget);
label->setBuddy(mPushButton);
glay->addWidget(label, row, 1);
auto hlay = new QHBoxLayout;
glay->addLayout(hlay, row, 2);
hlay->addWidget(mLabel, 1);
hlay->addWidget(mPushButton);
if (entry->isReadOnly()) {
mLabel->setEnabled(false);
}
connect(mPushButton, &QPushButton::clicked, this, &CryptoConfigEntryLDAPURL::slotOpenDialog);
}
void Kleo::CryptoConfigEntryLDAPURL::doLoad()
{
setURLList(mEntry->urlValueList());
}
void Kleo::CryptoConfigEntryLDAPURL::doSave()
{
mEntry->setURLValueList(mURLList);
}
void prepareURLCfgDialog(QDialog *dialog, DirectoryServicesWidget *dirserv, bool readOnly)
{
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok, dialog);
if (!readOnly) {
buttonBox->addButton(QDialogButtonBox::Cancel);
buttonBox->addButton(QDialogButtonBox::RestoreDefaults);
QPushButton *defaultsBtn = buttonBox->button(QDialogButtonBox::RestoreDefaults);
QObject::connect(defaultsBtn, &QPushButton::clicked, dirserv, &DirectoryServicesWidget::clear);
QObject::connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject);
}
QObject::connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept);
auto layout = new QVBoxLayout;
layout->addWidget(dirserv);
layout->addWidget(buttonBox);
dialog->setLayout(layout);
}
void Kleo::CryptoConfigEntryLDAPURL::slotOpenDialog()
{
if (!gpgme_check_version("1.16.0")) {
KMessageBox::error(mPushButton->parentWidget(),
i18n("Configuration of directory services is not possible "
"because the used gpgme libraries are too old."),
i18nc("@title:window", "Sorry"));
return;
}
// I'm a bad boy and I do it all on the stack. Enough classes already :)
// This is just a simple dialog around the directory-services-widget
QDialog dialog(mPushButton->parentWidget());
dialog.setWindowTitle(i18nc("@title:window", "Configure Directory Services"));
auto dirserv = new DirectoryServicesWidget(&dialog);
prepareURLCfgDialog(&dialog, dirserv, mEntry->isReadOnly());
dirserv->setReadOnly(mEntry->isReadOnly());
std::vector<KeyserverConfig> servers;
std::transform(std::cbegin(mURLList), std::cend(mURLList), std::back_inserter(servers), [](const auto &url) {
return KeyserverConfig::fromUrl(url);
});
dirserv->setKeyservers(servers);
if (dialog.exec()) {
QList<QUrl> urls;
const auto servers = dirserv->keyservers();
std::transform(std::begin(servers), std::end(servers), std::back_inserter(urls), [](const auto &server) {
return server.toUrl();
});
setURLList(urls);
slotChanged();
}
}
void Kleo::CryptoConfigEntryLDAPURL::setURLList(const QList<QUrl> &urlList)
{
mURLList = urlList;
if (mURLList.isEmpty()) {
mLabel->setText(i18n("None configured"));
} else {
mLabel->setText(i18np("1 server configured", "%1 servers configured", mURLList.count()));
}
}
#include "moc_cryptoconfigmodule_p.cpp"
#include "moc_cryptoconfigmodule.cpp"

File Metadata

Mime Type
text/x-c++
Expires
Sun, Feb 1, 7:37 PM (1 d, 6 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
5f/21/1cd06de595d5535b6190200c119a

Event Timeline