diff --git a/src/conf/CMakeLists.txt b/src/conf/CMakeLists.txt index bf9185bb3..4e7d47dfa 100644 --- a/src/conf/CMakeLists.txt +++ b/src/conf/CMakeLists.txt @@ -1,78 +1,80 @@ include_directories(${kleopatra_SOURCE_DIR}/src) if(BUILD_libkleopatraclient) set(_kcm_kleopatra_libkleopatraclient_extra_SRCS smimevalidationconfigurationwidget.cpp smimevalidationconfigurationpage.cpp cryptooperationsconfigwidget.cpp cryptooperationsconfigpage.cpp smimevalidationconfigurationwidget.h smimevalidationconfigurationpage.h cryptooperationsconfigwidget.h cryptooperationsconfigpage.h ) ki18n_wrap_ui(_kcm_kleopatra_libkleopatraclient_extra_SRCS smimevalidationconfigurationwidget.ui ) kconfig_add_kcfg_files(_kcm_kleopatra_libkleopatraclient_extra_SRCS ${kleopatra_SOURCE_DIR}/src/kcfg/smimevalidationpreferences.kcfgc ) set(_kcm_kleopatra_libkleopatraclient_extra_LIBS kleopatraclientgui) else() set(_kcm_kleopatra_libkleopatraclient_extra_SRCS) set(_kcm_kleopatra_libkleopatraclient_extra_LIBS) endif() set(kcm_kleopatra_PART_SRCS dirservconfigpage.cpp appearanceconfigpage.cpp appearanceconfigwidget.cpp gnupgsystemconfigurationpage.cpp dirservconfigpage.h appearanceconfigpage.h appearanceconfigwidget.h gnupgsystemconfigurationpage.h + labelledwidget.cpp + labelledwidget.cpp ${kleopatra_BINARY_DIR}/src/kleopatra_debug.cpp ${_kcm_kleopatra_libkleopatraclient_extra_SRCS} ) ki18n_wrap_ui(kcm_kleopatra_PART_SRCS appearanceconfigwidget.ui smimevalidationconfigurationwidget.ui ) kconfig_add_kcfg_files(kcm_kleopatra_PART_SRCS ${kleopatra_SOURCE_DIR}/src/kcfg/tooltippreferences.kcfgc ${kleopatra_SOURCE_DIR}/src/kcfg/emailoperationspreferences.kcfgc ${kleopatra_SOURCE_DIR}/src/kcfg/fileoperationspreferences.kcfgc ${kleopatra_SOURCE_DIR}/src/kcfg/tagspreferences.kcfgc ${kleopatra_SOURCE_DIR}/src/kcfg/settings.kcfgc ) add_library(kcm_kleopatra_static STATIC ${kcm_kleopatra_PART_SRCS}) target_link_libraries(kcm_kleopatra_static KF5::Libkleo KF5::IconThemes KF5::I18n KF5::WidgetsAddons KF5::ConfigWidgets ${_kcm_kleopatra_extra_libs} ${_kleopatra_dbusaddons_libs} ${_kcm_kleopatra_libkleopatraclient_extra_LIBS} ) add_library(kleopatra_config_gnupgsystem MODULE kcm_gnupgsystemconfigurationpage.cpp) kcoreaddons_desktop_to_json(kleopatra_config_gnupgsystem kleopatra_config_gnupgsystem.desktop) target_link_libraries(kleopatra_config_gnupgsystem kcm_kleopatra_static KF5::CoreAddons) install(FILES kleopatra_config_gnupgsystem.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) install(TARGETS kleopatra_config_gnupgsystem DESTINATION ${KDE_INSTALL_PLUGINDIR}/pim/kcms/kleopatra) diff --git a/src/conf/dirservconfigpage.cpp b/src/conf/dirservconfigpage.cpp index a2e19d770..5ba77f88a 100644 --- a/src/conf/dirservconfigpage.cpp +++ b/src/conf/dirservconfigpage.cpp @@ -1,443 +1,441 @@ /* -*- mode: c++; c-basic-offset:4 -*- conf/dirservconfigpage.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2004, 2008 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "dirservconfigpage.h" +#include "labelledwidget.h" + #include #include #include #include #include #include #include #include "kleopatra_debug.h" #include #include #include #include #include #include #include #include #include #include #include using namespace Kleo; using namespace QGpgME; #if 0 // disabled, since it is apparently confusing // For sync'ing kabldaprc class KABSynchronizer { public: KABSynchronizer() : mConfig("kabldaprc") { mConfig.setGroup("LDAP"); } KUrl::List readCurrentList() const { KUrl::List lst; // stolen from kabc/ldapclient.cpp const uint numHosts = mConfig.readEntry("NumSelectedHosts"); for (uint j = 0; j < numHosts; j++) { const QString num = QString::number(j); KUrl url; url.setProtocol("ldap"); url.setPath("/"); // workaround KUrl parsing bug const QString host = mConfig.readEntry(QString("SelectedHost") + num).trimmed(); url.setHost(host); const int port = mConfig.readEntry(QString("SelectedPort") + num); if (port != 0) { url.setPort(port); } const QString base = mConfig.readEntry(QString("SelectedBase") + num).trimmed(); url.setQuery(base); const QString bindDN = mConfig.readEntry(QString("SelectedBind") + num).trimmed(); url.setUser(bindDN); const QString pwdBindDN = mConfig.readEntry(QString("SelectedPwdBind") + num).trimmed(); url.setPass(pwdBindDN); lst.append(url); } return lst; } void writeList(const KUrl::List &lst) { mConfig.writeEntry("NumSelectedHosts", lst.count()); KUrl::List::const_iterator it = lst.begin(); KUrl::List::const_iterator end = lst.end(); unsigned j = 0; for (; it != end; ++it, ++j) { const QString num = QString::number(j); KUrl url = *it; Q_ASSERT(url.scheme() == "ldap"); mConfig.writeEntry(QString("SelectedHost") + num, url.host()); mConfig.writeEntry(QString("SelectedPort") + num, url.port()); // KUrl automatically encoded the query (e.g. for spaces inside it), // so decode it before writing it out const QString base = KUrl::decode_string(url.query().mid(1)); mConfig.writeEntry(QString("SelectedBase") + num, base); mConfig.writeEntry(QString("SelectedBind") + num, url.user()); mConfig.writeEntry(QString("SelectedPwdBind") + num, url.pass()); } mConfig.sync(); } private: KConfig mConfig; }; #endif static const char s_x509services_componentName[] = "gpgsm"; static const char s_x509services_entryName[] = "keyserver"; static const char s_x509services_legacy_componentName[] = "dirmngr"; static const char s_x509services_legacy_entryName[] = "LDAP Server"; static const char s_pgpservice_componentName[] = "dirmngr"; static const char s_pgpservice_entryName[] = "keyserver"; // legacy config entry used until GnuPG 2.2 static const char s_pgpservice_legacy_componentName[] = "gpg"; static const char s_pgpservice_legacy_entryName[] = "keyserver"; static const char s_timeout_componentName[] = "dirmngr"; static const char s_timeout_entryName[] = "ldaptimeout"; static const char s_maxitems_componentName[] = "dirmngr"; static const char s_maxitems_entryName[] = "max-replies"; #ifdef NOT_USEFUL_CURRENTLY static const char s_addnewservers_componentName[] = "dirmngr"; static const char s_addnewservers_entryName[] = "add-servers"; #endif DirectoryServicesConfigurationPage::DirectoryServicesConfigurationPage(QWidget *parent, const QVariantList &args) : KCModule(parent, args) { mConfig = QGpgME::cryptoConfig(); auto glay = new QGridLayout(this); glay->setContentsMargins(0, 0, 0, 0); // OpenPGP keyserver int row = 0; { auto l = new QHBoxLayout{}; l->setContentsMargins(0, 0, 0, 0); - l->addWidget(new QLabel{i18n("OpenPGP keyserver:"), this}); - mOpenPGPKeyserverEdit = new QLineEdit{this}; - - l->addWidget(mOpenPGPKeyserverEdit); + mOpenPGPKeyserverEdit.createWidgets(this); + mOpenPGPKeyserverEdit.label()->setText(i18n("OpenPGP keyserver:")); + l->addWidget(mOpenPGPKeyserverEdit.label()); + l->addWidget(mOpenPGPKeyserverEdit.widget()); glay->addLayout(l, row, 0, 1, 3); - connect(mOpenPGPKeyserverEdit, &QLineEdit::textEdited, this, [this]() { Q_EMIT changed(true); }); + connect(mOpenPGPKeyserverEdit.widget(), &QLineEdit::textEdited, this, [this]() { Q_EMIT changed(true); }); } // X.509 servers if (Settings{}.cmsEnabled()) { ++row; auto groupBox = new QGroupBox{i18n("X.509 Directory Services"), this}; auto groupBoxLayout = new QVBoxLayout{groupBox}; if (gpgme_check_version("1.16.0")) { mDirectoryServices = new Kleo::DirectoryServicesWidget(this); if (QLayout *l = mDirectoryServices->layout()) { l->setContentsMargins(0, 0, 0, 0); } groupBoxLayout->addWidget(mDirectoryServices); connect(mDirectoryServices, SIGNAL(changed()), this, SLOT(changed())); } else { // QGpgME does not properly support keyserver flags for X.509 keyservers (added in GnuPG 2.2.28); // disable the configuration to prevent the configuration from being corrupted groupBoxLayout->addWidget(new QLabel{i18n("Configuration of directory services is not possible " "because the used gpgme libraries are too old."), this}); } glay->addWidget(groupBox, row, 0, 1, 3); } // LDAP timeout ++row; - auto label = new QLabel(i18n("LDAP &timeout (minutes:seconds):"), this); - mTimeout = new QTimeEdit(this); - mTimeout->setDisplayFormat(QStringLiteral("mm:ss")); - connect(mTimeout, SIGNAL(timeChanged(QTime)), this, SLOT(changed())); - label->setBuddy(mTimeout); - glay->addWidget(label, row, 0); - glay->addWidget(mTimeout, row, 1); + mTimeout.createWidgets(this); + mTimeout.label()->setText(i18n("LDAP &timeout (minutes:seconds):")); + mTimeout.widget()->setDisplayFormat(QStringLiteral("mm:ss")); + connect(mTimeout.widget(), SIGNAL(timeChanged(QTime)), this, SLOT(changed())); + glay->addWidget(mTimeout.label(), row, 0); + glay->addWidget(mTimeout.widget(), row, 1); // Max number of items returned by queries ++row; - mMaxItemsLabel = new QLabel(i18n("&Maximum number of items returned by query:"), this); - mMaxItems = new QSpinBox(this); - mMaxItems->setMinimum(0); - mMaxItemsLabel->setBuddy(mMaxItems); - connect(mMaxItems, SIGNAL(valueChanged(int)), this, SLOT(changed())); - glay->addWidget(mMaxItemsLabel, row, 0); - glay->addWidget(mMaxItems, row, 1); + mMaxItems.createWidgets(this); + mMaxItems.label()->setText(i18n("&Maximum number of items returned by query:")); + mMaxItems.widget()->setMinimum(0); + connect(mMaxItems.widget(), SIGNAL(valueChanged(int)), this, SLOT(changed())); + glay->addWidget(mMaxItems.label(), row, 0); + glay->addWidget(mMaxItems.widget(), row, 1); #ifdef NOT_USEFUL_CURRENTLY ++row mAddNewServersCB = new QCheckBox(i18n("Automatically add &new servers discovered in CRL distribution points"), this); connect(mAddNewServersCB, SIGNAL(clicked()), this, SLOT(changed())); glay->addWidget(mAddNewServersCB, row, 0, 1, 3); #endif glay->setRowStretch(++row, 1); glay->setColumnStretch(2, 1); load(); } void DirectoryServicesConfigurationPage::load() { if (mDirectoryServices) { mDirectoryServices->clear(); // gpgsm's keyserver option is not provided by very old gpgconf versions mX509ServicesEntry = configEntry(s_x509services_componentName, s_x509services_entryName, CryptoConfigEntry::ArgType_LDAPURL, ListValue, DoNotShowError); if (!mX509ServicesEntry) { mX509ServicesEntry = configEntry(s_x509services_legacy_componentName, s_x509services_legacy_entryName, CryptoConfigEntry::ArgType_LDAPURL, ListValue, DoShowError); } if (mX509ServicesEntry) { std::vector servers; const auto urls = mX509ServicesEntry->urlValueList(); servers.reserve(urls.size()); std::transform(std::begin(urls), std::end(urls), std::back_inserter(servers), [](const auto &url) { return KeyserverConfig::fromUrl(url); }); mDirectoryServices->setKeyservers(servers); mDirectoryServices->setReadOnly(mX509ServicesEntry->isReadOnly()); } else { mDirectoryServices->setDisabled(true); } } { // gpg prefers the deprecated keyserver option in gpg.conf over the keyserver option in dirmngr.conf; // therefore, we use the deprecated keyserver option if it is set or if the new option doesn't exist (gpg < 2.1.9) auto const newEntry = configEntry(s_pgpservice_componentName, s_pgpservice_entryName, CryptoConfigEntry::ArgType_String, SingleValue, DoNotShowError); auto const legacyEntry = configEntry(s_pgpservice_legacy_componentName, s_pgpservice_legacy_entryName, CryptoConfigEntry::ArgType_String, SingleValue, DoNotShowError); mOpenPGPServiceEntry = ((legacyEntry && legacyEntry->isSet()) || !newEntry) ? legacyEntry : newEntry; if (!mOpenPGPServiceEntry) { qCWarning(KLEOPATRA_LOG) << "Unknown or wrong typed config entries" << s_pgpservice_componentName << "/" << s_pgpservice_entryName << "and" << s_pgpservice_legacy_componentName << "/" << s_pgpservice_legacy_entryName; } else if (mOpenPGPServiceEntry == legacyEntry) { qCDebug(KLEOPATRA_LOG) << "Using config entry" << s_pgpservice_legacy_componentName << "/" << s_pgpservice_legacy_entryName; } else { qCDebug(KLEOPATRA_LOG) << "Using config entry" << s_pgpservice_componentName << "/" << s_pgpservice_entryName; } - mOpenPGPKeyserverEdit->setText(mOpenPGPServiceEntry && mOpenPGPServiceEntry->isSet() ? mOpenPGPServiceEntry->stringValue() : QString()); - mOpenPGPKeyserverEdit->setEnabled(mOpenPGPServiceEntry && !mOpenPGPServiceEntry->isReadOnly()); + mOpenPGPKeyserverEdit.widget()->setText(mOpenPGPServiceEntry && mOpenPGPServiceEntry->isSet() ? mOpenPGPServiceEntry->stringValue() : QString()); + mOpenPGPKeyserverEdit.setEnabled(mOpenPGPServiceEntry && !mOpenPGPServiceEntry->isReadOnly()); #ifdef QGPGME_CRYPTOCONFIGENTRY_HAS_DEFAULT_VALUE if (newEntry && !newEntry->defaultValue().isNull()) { - mOpenPGPKeyserverEdit->setPlaceholderText(newEntry->defaultValue().toString()); + mOpenPGPKeyserverEdit.widget()->setPlaceholderText(newEntry->defaultValue().toString()); } else #endif { if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.1.16") { - mOpenPGPKeyserverEdit->setPlaceholderText(QStringLiteral("hkp://keys.gnupg.net")); + mOpenPGPKeyserverEdit.widget()->setPlaceholderText(QStringLiteral("hkp://keys.gnupg.net")); } else { - mOpenPGPKeyserverEdit->setPlaceholderText(QStringLiteral("hkps://hkps.pool.sks-keyservers.net")); + mOpenPGPKeyserverEdit.widget()->setPlaceholderText(QStringLiteral("hkps://hkps.pool.sks-keyservers.net")); } } } // read LDAP timeout // first try to read the config entry as int (GnuPG 2.3) mTimeoutConfigEntry = configEntry(s_timeout_componentName, s_timeout_entryName, CryptoConfigEntry::ArgType_Int, SingleValue, DoNotShowError); if (!mTimeoutConfigEntry) { // if this fails, then try to read the config entry as unsigned int (GnuPG <= 2.2) mTimeoutConfigEntry = configEntry(s_timeout_componentName, s_timeout_entryName, CryptoConfigEntry::ArgType_UInt, SingleValue, DoShowError); } if (mTimeoutConfigEntry) { const int ldapTimeout = mTimeoutConfigEntry->argType() == CryptoConfigEntry::ArgType_Int ? mTimeoutConfigEntry->intValue() : static_cast(mTimeoutConfigEntry->uintValue()); const QTime time = QTime(0, 0, 0, 0).addSecs(ldapTimeout); //qCDebug(KLEOPATRA_LOG) <<"timeout:" << mTimeoutConfigEntry->uintValue() <<" ->" << time; - mTimeout->setTime(time); + mTimeout.widget()->setTime(time); } - mTimeout->setEnabled(mTimeoutConfigEntry && !mTimeoutConfigEntry->isReadOnly()); + mTimeout.setEnabled(mTimeoutConfigEntry && !mTimeoutConfigEntry->isReadOnly()); // read max-replies config entry // first try to read the config entry as int (GnuPG 2.3) mMaxItemsConfigEntry = configEntry(s_maxitems_componentName, s_maxitems_entryName, CryptoConfigEntry::ArgType_Int, SingleValue, DoNotShowError); if (!mMaxItemsConfigEntry) { // if this fails, then try to read the config entry as unsigned int (GnuPG <= 2.2) mMaxItemsConfigEntry = configEntry(s_maxitems_componentName, s_maxitems_entryName, CryptoConfigEntry::ArgType_UInt, SingleValue, DoShowError); } if (mMaxItemsConfigEntry) { const int value = mMaxItemsConfigEntry->argType() == CryptoConfigEntry::ArgType_Int ? mMaxItemsConfigEntry->intValue() : static_cast(mMaxItemsConfigEntry->uintValue()); - mMaxItems->blockSignals(true); // KNumInput emits valueChanged from setValue! - mMaxItems->setValue(value); - mMaxItems->blockSignals(false); + mMaxItems.widget()->blockSignals(true); // KNumInput emits valueChanged from setValue! + mMaxItems.widget()->setValue(value); + mMaxItems.widget()->blockSignals(false); } - const bool maxItemsEnabled = mMaxItemsConfigEntry && !mMaxItemsConfigEntry->isReadOnly(); - mMaxItems->setEnabled(maxItemsEnabled); - mMaxItemsLabel->setEnabled(maxItemsEnabled); + mMaxItems.setEnabled(mMaxItemsConfigEntry && !mMaxItemsConfigEntry->isReadOnly()); #ifdef NOT_USEFUL_CURRENTLY mAddNewServersConfigEntry = configEntry(s_addnewservers_componentName, s_addnewservers_groupName, s_addnewservers_entryName, CryptoConfigEntry::ArgType_None, SingleValue, DoShowError); if (mAddNewServersConfigEntry) { mAddNewServersCB->setChecked(mAddNewServersConfigEntry->boolValue()); } #endif } namespace { void updateIntegerConfigEntry(QGpgME::CryptoConfigEntry *configEntry, int value) { if (!configEntry) { return; } if (configEntry->argType() == CryptoConfigEntry::ArgType_Int) { if (configEntry->intValue() != value) { configEntry->setIntValue(value); } } else { const auto newValue = static_cast(value); if (configEntry->uintValue() != newValue) { configEntry->setUIntValue(newValue); } } } } void DirectoryServicesConfigurationPage::save() { if (mX509ServicesEntry && mDirectoryServices) { QList urls; const auto servers = mDirectoryServices->keyservers(); urls.reserve(servers.size()); std::transform(std::begin(servers), std::end(servers), std::back_inserter(urls), [](const auto &server) { return server.toUrl(); }); mX509ServicesEntry->setURLValueList(urls); } if (mOpenPGPServiceEntry) { - const auto keyserver = mOpenPGPKeyserverEdit->text().trimmed(); + const auto keyserver = mOpenPGPKeyserverEdit.widget()->text().trimmed(); if (keyserver.isEmpty()) { mOpenPGPServiceEntry->resetToDefault(); } else { const auto keyserverUrl = keyserver.contains(QLatin1String{"://"}) ? keyserver : (QLatin1String{"hkps://"} + keyserver); mOpenPGPServiceEntry->setStringValue(keyserverUrl); } } - const QTime time{mTimeout->time()}; + const QTime time{mTimeout.widget()->time()}; updateIntegerConfigEntry(mTimeoutConfigEntry, time.minute() * 60 + time.second()); - updateIntegerConfigEntry(mMaxItemsConfigEntry, mMaxItems->value()); + updateIntegerConfigEntry(mMaxItemsConfigEntry, mMaxItems.widget()->value()); #ifdef NOT_USEFUL_CURRENTLY if (mAddNewServersConfigEntry && mAddNewServersConfigEntry->boolValue() != mAddNewServersCB->isChecked()) { mAddNewServersConfigEntry->setBoolValue(mAddNewServersCB->isChecked()); } #endif mConfig->sync(true); #if 0 // Also write the LDAP URLs to kabldaprc so that they are used by kaddressbook KABSynchronizer sync; const KUrl::List toAdd = mDirectoryServices->urlList(); KUrl::List currentList = sync.readCurrentList(); KUrl::List::const_iterator it = toAdd.begin(); KUrl::List::const_iterator end = toAdd.end(); for (; it != end; ++it) { // check if the URL is already in currentList if (currentList.find(*it) == currentList.end()) // if not, add it { currentList.append(*it); } } sync.writeList(currentList); #endif } void DirectoryServicesConfigurationPage::defaults() { // these guys don't have a default, to clear them: if (mX509ServicesEntry) { mX509ServicesEntry->setURLValueList(QList()); } if (mOpenPGPServiceEntry) { mOpenPGPServiceEntry->setStringValue(QString()); } // these presumably have a default, use that one: if (mTimeoutConfigEntry) { mTimeoutConfigEntry->resetToDefault(); } if (mMaxItemsConfigEntry) { mMaxItemsConfigEntry->resetToDefault(); } #ifdef NOT_USEFUL_CURRENTLY if (mAddNewServersConfigEntry) { mAddNewServersConfigEntry->resetToDefault(); } #endif load(); } // Find config entry for ldap servers. Implements runtime checks on the configuration option. CryptoConfigEntry *DirectoryServicesConfigurationPage::configEntry(const char *componentName, const char *entryName, CryptoConfigEntry::ArgType argType, EntryMultiplicity multiplicity, ShowError showError) { CryptoConfigEntry *const entry = Kleo::getCryptoConfigEntry(mConfig, componentName, entryName); if (!entry) { if (showError == DoShowError) { KMessageBox::error(this, i18n("Backend error: gpgconf does not seem to know the entry for %1/%2", QLatin1String(componentName), QLatin1String(entryName))); } return nullptr; } if (entry->argType() != argType || entry->isList() != bool(multiplicity)) { if (showError == DoShowError) { KMessageBox::error(this, i18n("Backend error: gpgconf has wrong type for %1/%2: %3 %4", QLatin1String(componentName), QLatin1String(entryName), entry->argType(), entry->isList())); } return nullptr; } return entry; } diff --git a/src/conf/dirservconfigpage.h b/src/conf/dirservconfigpage.h index be5fa49a6..7385f930d 100644 --- a/src/conf/dirservconfigpage.h +++ b/src/conf/dirservconfigpage.h @@ -1,72 +1,74 @@ /* -*- mode: c++; c-basic-offset:4 -*- conf/dirservconfigpage.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2004, 2008 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once +#include + #include #include class QCheckBox; class QLabel; class QLineEdit; class QTimeEdit; class QSpinBox; + namespace Kleo { class DirectoryServicesWidget; } /** * "Directory Services" configuration page for kleopatra's configuration dialog * The user can configure LDAP servers in this page, to be used for listing/fetching * remote certificates in kleopatra. */ class DirectoryServicesConfigurationPage : public KCModule { Q_OBJECT public: explicit DirectoryServicesConfigurationPage(QWidget *parent = nullptr, const QVariantList &args = QVariantList()); void load() override; void save() override; void defaults() override; private: enum EntryMultiplicity { SingleValue, ListValue }; enum ShowError { DoNotShowError, DoShowError }; QGpgME::CryptoConfigEntry *configEntry(const char *componentName, const char *entryName, QGpgME::CryptoConfigEntry::ArgType argType, EntryMultiplicity multiplicity, ShowError showError); private: - QLineEdit *mOpenPGPKeyserverEdit = nullptr; + Kleo::LabelledWidget mOpenPGPKeyserverEdit; Kleo::DirectoryServicesWidget *mDirectoryServices = nullptr; - QTimeEdit *mTimeout = nullptr; - QSpinBox *mMaxItems = nullptr; - QLabel *mMaxItemsLabel = nullptr; + Kleo::LabelledWidget mTimeout; + Kleo::LabelledWidget mMaxItems; QCheckBox *mAddNewServersCB = nullptr; QGpgME::CryptoConfigEntry *mX509ServicesEntry = nullptr; QGpgME::CryptoConfigEntry *mOpenPGPServiceEntry = nullptr; QGpgME::CryptoConfigEntry *mTimeoutConfigEntry = nullptr; QGpgME::CryptoConfigEntry *mMaxItemsConfigEntry = nullptr; QGpgME::CryptoConfigEntry *mAddNewServersConfigEntry = nullptr; QGpgME::CryptoConfig *mConfig = nullptr; }; diff --git a/src/conf/labelledwidget.cpp b/src/conf/labelledwidget.cpp new file mode 100644 index 000000000..cb2dafe9f --- /dev/null +++ b/src/conf/labelledwidget.cpp @@ -0,0 +1,44 @@ +/* conf/labelledwidget.cpp + + This file is part of Kleopatra, the KDE keymanager + SPDX-FileCopyrightText: 2022 g10 Code GmbH + SPDX-FileContributor: Ingo Klöcker + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "labelledwidget.h" + +namespace Kleo::_detail +{ + +QWidget *LabelledWidgetBase::widget() const +{ + return mWidget; +} + +QLabel *LabelledWidgetBase::label() const +{ + return mLabel; +} + +void LabelledWidgetBase::setWidgets(QWidget *widget, QLabel *label) +{ + mWidget = widget; + mLabel = label; + if (mLabel) { + mLabel->setBuddy(mWidget); + } +} + +void LabelledWidgetBase::setEnabled(bool enabled) +{ + if (mLabel) { + mLabel->setEnabled(enabled); + } + if (mWidget) { + mWidget->setEnabled(enabled); + } +} + +} diff --git a/src/conf/labelledwidget.h b/src/conf/labelledwidget.h new file mode 100644 index 000000000..e7748cfaa --- /dev/null +++ b/src/conf/labelledwidget.h @@ -0,0 +1,62 @@ +/* conf/labelledwidget.h + + This file is part of Kleopatra, the KDE keymanager + SPDX-FileCopyrightText: 2022 g10 Code GmbH + SPDX-FileContributor: Ingo Klöcker + + SPDX-License-Identifier: GPL-2.0-or-later +*/ +#pragma once + +#include +#include + +namespace Kleo +{ + +namespace _detail +{ +class LabelledWidgetBase +{ +protected: + LabelledWidgetBase() = default; + + QWidget *widget() const; + +public: + QLabel *label() const; + + void setWidgets(QWidget *widget, QLabel *label); + + void setEnabled(bool enabled); + +private: + QPointer mLabel; + QPointer mWidget; +}; +} + +/** + * LabelledWidget is a small value-like class for simplifying the management + * of a QWidget with associated QLabel. + */ +template +class LabelledWidget : public _detail::LabelledWidgetBase +{ +public: + LabelledWidget() + : _detail::LabelledWidgetBase{} + {} + + void createWidgets(QWidget *parent) + { + setWidgets(new Widget{parent}, new QLabel{parent}); + } + + Widget *widget() const + { + return dynamic_cast(_detail::LabelledWidgetBase::widget()); + } +}; + +} diff --git a/src/conf/smimevalidationconfigurationwidget.cpp b/src/conf/smimevalidationconfigurationwidget.cpp index abde92f54..9b2a1ab87 100644 --- a/src/conf/smimevalidationconfigurationwidget.cpp +++ b/src/conf/smimevalidationconfigurationwidget.cpp @@ -1,397 +1,403 @@ /* -*- mode: c++; c-basic-offset:4 -*- conf/smimevalidationconfigurationwidget.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 #include "smimevalidationconfigurationwidget.h" #include "ui_smimevalidationconfigurationwidget.h" +#include "labelledwidget.h" + #include "smimevalidationpreferences.h" #include #include #include #include #include "kleopatra_debug.h" #if HAVE_QDBUS # include #endif using namespace Kleo; using namespace Kleo::Config; using namespace QGpgME; class SMimeValidationConfigurationWidget::Private { friend class ::Kleo::Config::SMimeValidationConfigurationWidget; SMimeValidationConfigurationWidget *const q; public: explicit Private(SMimeValidationConfigurationWidget *qq) : q(qq), customHTTPProxyWritable(false), ui(q) { #if HAVE_QDBUS QDBusConnection::sessionBus().connect(QString(), QString(), QStringLiteral("org.kde.kleo.CryptoConfig"), QStringLiteral("changed"), q, SLOT(load())); #endif } bool customHTTPProxyWritable; private: void enableDisableActions() { ui.customHTTPProxy->setEnabled(ui.useCustomHTTPProxyRB->isChecked() && !ui.disableHTTPCB->isChecked() && customHTTPProxyWritable); } private: struct UI : Ui_SMimeValidationConfigurationWidget { + LabelledWidget labelledOCSPResponderSignature; + LabelledWidget labelledOCSPResponderURL; + explicit UI(SMimeValidationConfigurationWidget *q) : Ui_SMimeValidationConfigurationWidget() { setupUi(q); + labelledOCSPResponderURL.setWidgets(OCSPResponderURL, OCSPResponderURLLabel); + labelledOCSPResponderSignature.setWidgets(OCSPResponderSignature, OCSPResponderSignatureLabel); + if (QLayout *l = q->layout()) { l->setContentsMargins(0, 0, 0, 0); } const struct { QObject *object; const char *signal; } sources[] = { { intervalRefreshCB, SIGNAL(toggled(bool)) }, { intervalRefreshSB, SIGNAL(valueChanged(int)) }, { OCSPCB, SIGNAL(toggled(bool)) }, { OCSPResponderURL, SIGNAL(textChanged(QString)) }, { OCSPResponderSignature, SIGNAL(selectedCertificatesChanged(QStringList)) }, { doNotCheckCertPolicyCB, SIGNAL(toggled(bool)) }, { neverConsultCB, SIGNAL(toggled(bool)) }, { allowMarkTrustedCB, SIGNAL(toggled(bool)) }, { fetchMissingCB, SIGNAL(toggled(bool)) }, { ignoreServiceURLCB, SIGNAL(toggled(bool)) }, { ignoreHTTPDPCB, SIGNAL(toggled(bool)) }, { disableHTTPCB, SIGNAL(toggled(bool)) }, { honorHTTPProxyRB, SIGNAL(toggled(bool)) }, { useCustomHTTPProxyRB, SIGNAL(toggled(bool)) }, { customHTTPProxy, SIGNAL(textChanged(QString)) }, { ignoreLDAPDPCB, SIGNAL(toggled(bool)) }, { disableLDAPCB, SIGNAL(toggled(bool)) }, { customLDAPProxy, SIGNAL(textChanged(QString)) }, }; for (unsigned int i = 0; i < sizeof sources / sizeof * sources; ++i) { connect(sources[i].object, sources[i].signal, q, SIGNAL(changed())); } connect(useCustomHTTPProxyRB, SIGNAL(toggled(bool)), q, SLOT(enableDisableActions())); connect(disableHTTPCB, SIGNAL(toggled(bool)), q, SLOT(enableDisableActions())); OCSPResponderSignature->setOnlyX509CertificatesAllowed(true); OCSPResponderSignature->setOnlySigningCertificatesAllowed(true); OCSPResponderSignature->setMultipleCertificatesAllowed(false); //OCSPResponderSignature->setAllowedKeys( KeySelectionDialog::TrustedKeys|KeySelectionDialog::ValidKeys ); } } ui; }; SMimeValidationConfigurationWidget::SMimeValidationConfigurationWidget(QWidget *p, Qt::WindowFlags f) : QWidget(p, f), d(new Private(this)) { } SMimeValidationConfigurationWidget::~SMimeValidationConfigurationWidget() {} static void disableDirmngrWidget(QWidget *w) { w->setEnabled(false); w->setWhatsThis(i18n("This option requires dirmngr >= 0.9.0")); } static void initializeDirmngrCheckbox(QCheckBox *cb, CryptoConfigEntry *entry) { if (entry) { cb->setChecked(entry->boolValue()); } if (!entry || entry->isReadOnly()) { disableDirmngrWidget(cb); } } struct SMIMECryptoConfigEntries { enum ShowError { DoNotShowError, DoShowError }; SMIMECryptoConfigEntries(CryptoConfig *config) : mConfig(config), // Checkboxes mCheckUsingOCSPConfigEntry(configEntry("gpgsm", "enable-ocsp", CryptoConfigEntry::ArgType_None)), mEnableOCSPsendingConfigEntry(configEntry("dirmngr", "allow-ocsp", CryptoConfigEntry::ArgType_None)), mDoNotCheckCertPolicyConfigEntry(configEntry("gpgsm", "disable-policy-checks", CryptoConfigEntry::ArgType_None)), mNeverConsultConfigEntry(configEntry("gpgsm", "disable-crl-checks", CryptoConfigEntry::ArgType_None)), mAllowMarkTrustedConfigEntry(configEntry("gpg-agent", "allow-mark-trusted", CryptoConfigEntry::ArgType_None, DoNotShowError)), // legacy entry -> ignore error mFetchMissingConfigEntry(configEntry("gpgsm", "auto-issuer-key-retrieve", CryptoConfigEntry::ArgType_None)), mNoAllowMarkTrustedConfigEntry(configEntry("gpg-agent", "no-allow-mark-trusted", CryptoConfigEntry::ArgType_None)), // dirmngr-0.9.0 options mIgnoreServiceURLEntry(configEntry("dirmngr", "ignore-ocsp-service-url", CryptoConfigEntry::ArgType_None)), mIgnoreHTTPDPEntry(configEntry("dirmngr", "ignore-http-dp", CryptoConfigEntry::ArgType_None)), mDisableHTTPEntry(configEntry("dirmngr", "disable-http", CryptoConfigEntry::ArgType_None)), mHonorHTTPProxy(configEntry("dirmngr", "honor-http-proxy", CryptoConfigEntry::ArgType_None)), mIgnoreLDAPDPEntry(configEntry("dirmngr", "ignore-ldap-dp", CryptoConfigEntry::ArgType_None)), mDisableLDAPEntry(configEntry("dirmngr", "disable-ldap", CryptoConfigEntry::ArgType_None)), // Other widgets mOCSPResponderURLConfigEntry(configEntry("dirmngr", "ocsp-responder", CryptoConfigEntry::ArgType_String)), mOCSPResponderSignature(configEntry("dirmngr", "ocsp-signer", CryptoConfigEntry::ArgType_String)), mCustomHTTPProxy(configEntry("dirmngr", "http-proxy", CryptoConfigEntry::ArgType_String)), mCustomLDAPProxy(configEntry("dirmngr", "ldap-proxy", CryptoConfigEntry::ArgType_String)) { } CryptoConfigEntry *configEntry(const char *componentName, const char *entryName, int argType, ShowError showError=DoShowError); CryptoConfig *const mConfig; // Checkboxes CryptoConfigEntry *const mCheckUsingOCSPConfigEntry; CryptoConfigEntry *const mEnableOCSPsendingConfigEntry; CryptoConfigEntry *const mDoNotCheckCertPolicyConfigEntry; CryptoConfigEntry *const mNeverConsultConfigEntry; CryptoConfigEntry *const mAllowMarkTrustedConfigEntry; CryptoConfigEntry *const mFetchMissingConfigEntry; // gnupg 2.0.17+ option that should inhibit allow-mark-trusted display CryptoConfigEntry *const mNoAllowMarkTrustedConfigEntry; // dirmngr-0.9.0 options CryptoConfigEntry *const mIgnoreServiceURLEntry; CryptoConfigEntry *const mIgnoreHTTPDPEntry; CryptoConfigEntry *const mDisableHTTPEntry; CryptoConfigEntry *const mHonorHTTPProxy; CryptoConfigEntry *const mIgnoreLDAPDPEntry; CryptoConfigEntry *const mDisableLDAPEntry; // Other widgets CryptoConfigEntry *const mOCSPResponderURLConfigEntry; CryptoConfigEntry *const mOCSPResponderSignature; CryptoConfigEntry *const mCustomHTTPProxy; CryptoConfigEntry *const mCustomLDAPProxy; }; void SMimeValidationConfigurationWidget::defaults() { qCDebug(KLEOPATRA_LOG) << "not implemented"; } void SMimeValidationConfigurationWidget::load() { const SMimeValidationPreferences preferences; const unsigned int refreshInterval = preferences.refreshInterval(); d->ui.intervalRefreshCB->setChecked(refreshInterval > 0); d->ui.intervalRefreshSB->setValue(refreshInterval); CryptoConfig *const config = QGpgME::cryptoConfig(); if (!config) { setEnabled(false); return; } #if 0 // crashes other pages' save() by nuking the CryptoConfigEntries under their feet. // This was probably not a problem in KMail, where this code comes // from. But here, it's fatal. // Force re-parsing gpgconf data, in case e.g. kleopatra or "configure backend" was used // (which ends up calling us via D-Bus) config->clear(); #endif // Create config entries // Don't keep them around, they'll get deleted by clear(), which could be // done by the "configure backend" button even before we save(). const SMIMECryptoConfigEntries e(config); // Initialize GUI items from the config entries if (e.mCheckUsingOCSPConfigEntry) { d->ui.OCSPCB->setChecked(e.mCheckUsingOCSPConfigEntry->boolValue()); } d->ui.OCSPCB->setEnabled(e.mCheckUsingOCSPConfigEntry && !e.mCheckUsingOCSPConfigEntry->isReadOnly()); d->ui.OCSPGroupBox->setEnabled(d->ui.OCSPCB->isChecked()); if (e.mDoNotCheckCertPolicyConfigEntry) { d->ui.doNotCheckCertPolicyCB->setChecked(e.mDoNotCheckCertPolicyConfigEntry->boolValue()); } d->ui.doNotCheckCertPolicyCB->setEnabled(e.mDoNotCheckCertPolicyConfigEntry && !e.mDoNotCheckCertPolicyConfigEntry->isReadOnly()); if (e.mNeverConsultConfigEntry) { d->ui.neverConsultCB->setChecked(e.mNeverConsultConfigEntry->boolValue()); } d->ui.neverConsultCB->setEnabled(e.mNeverConsultConfigEntry && !e.mNeverConsultConfigEntry->isReadOnly()); if (e.mNoAllowMarkTrustedConfigEntry) { d->ui.allowMarkTrustedCB->hide(); // this option was only here to _enable_ allow-mark-trusted, and makes no sense if it's already default on } if (e.mAllowMarkTrustedConfigEntry) { d->ui.allowMarkTrustedCB->setChecked(e.mAllowMarkTrustedConfigEntry->boolValue()); } d->ui.allowMarkTrustedCB->setEnabled(e.mAllowMarkTrustedConfigEntry && !e.mAllowMarkTrustedConfigEntry->isReadOnly()); if (e.mFetchMissingConfigEntry) { d->ui.fetchMissingCB->setChecked(e.mFetchMissingConfigEntry->boolValue()); } d->ui.fetchMissingCB->setEnabled(e.mFetchMissingConfigEntry && !e.mFetchMissingConfigEntry->isReadOnly()); if (e.mOCSPResponderURLConfigEntry) { d->ui.OCSPResponderURL->setText(e.mOCSPResponderURLConfigEntry->stringValue()); } - d->ui.OCSPResponderURL->setEnabled(e.mOCSPResponderURLConfigEntry && !e.mOCSPResponderURLConfigEntry->isReadOnly()); - d->ui.OCSPResponderURLLabel->setEnabled(e.mOCSPResponderURLConfigEntry && !e.mOCSPResponderURLConfigEntry->isReadOnly()); + d->ui.labelledOCSPResponderURL.setEnabled(e.mOCSPResponderURLConfigEntry && !e.mOCSPResponderURLConfigEntry->isReadOnly()); if (e.mOCSPResponderSignature) { d->ui.OCSPResponderSignature->setSelectedCertificate(e.mOCSPResponderSignature->stringValue()); } - d->ui.OCSPResponderSignature->setEnabled(e.mOCSPResponderSignature && !e.mOCSPResponderSignature->isReadOnly()); - d->ui.OCSPResponderSignatureLabel->setEnabled(e.mOCSPResponderSignature && !e.mOCSPResponderSignature->isReadOnly()); + d->ui.labelledOCSPResponderSignature.setEnabled(e.mOCSPResponderSignature && !e.mOCSPResponderSignature->isReadOnly()); // dirmngr-0.9.0 options initializeDirmngrCheckbox(d->ui.ignoreServiceURLCB, e.mIgnoreServiceURLEntry); initializeDirmngrCheckbox(d->ui.ignoreHTTPDPCB, e.mIgnoreHTTPDPEntry); initializeDirmngrCheckbox(d->ui.disableHTTPCB, e.mDisableHTTPEntry); initializeDirmngrCheckbox(d->ui.ignoreLDAPDPCB, e.mIgnoreLDAPDPEntry); initializeDirmngrCheckbox(d->ui.disableLDAPCB, e.mDisableLDAPEntry); if (e.mCustomHTTPProxy) { QString systemProxy = QString::fromLocal8Bit(qgetenv("http_proxy")); if (systemProxy.isEmpty()) { systemProxy = i18n("no proxy"); } d->ui.systemHTTPProxy->setText(i18n("(Current system setting: %1)", systemProxy)); const bool honor = e.mHonorHTTPProxy && e.mHonorHTTPProxy->boolValue(); d->ui.honorHTTPProxyRB->setChecked(honor); d->ui.useCustomHTTPProxyRB->setChecked(!honor); d->ui.customHTTPProxy->setText(e.mCustomHTTPProxy->stringValue()); } d->customHTTPProxyWritable = e.mCustomHTTPProxy && !e.mCustomHTTPProxy->isReadOnly(); if (!d->customHTTPProxyWritable) { disableDirmngrWidget(d->ui.honorHTTPProxyRB); disableDirmngrWidget(d->ui.useCustomHTTPProxyRB); disableDirmngrWidget(d->ui.systemHTTPProxy); disableDirmngrWidget(d->ui.customHTTPProxy); } if (e.mCustomLDAPProxy) { d->ui.customLDAPProxy->setText(e.mCustomLDAPProxy->stringValue()); } if (!e.mCustomLDAPProxy || e.mCustomLDAPProxy->isReadOnly()) { disableDirmngrWidget(d->ui.customLDAPProxy); disableDirmngrWidget(d->ui.customLDAPLabel); } d->enableDisableActions(); } static void saveCheckBoxToKleoEntry(QCheckBox *cb, CryptoConfigEntry *entry) { const bool b = cb->isChecked(); if (entry && entry->boolValue() != b) { entry->setBoolValue(b); } } void SMimeValidationConfigurationWidget::save() const { CryptoConfig *const config = QGpgME::cryptoConfig(); if (!config) { return; } { SMimeValidationPreferences preferences; preferences.setRefreshInterval(d->ui.intervalRefreshCB->isChecked() ? d->ui.intervalRefreshSB->value() : 0); preferences.save(); } // Create config entries // Don't keep them around, they'll get deleted by clear(), which could be done by the // "configure backend" button. const SMIMECryptoConfigEntries e(config); const bool b = d->ui.OCSPCB->isChecked(); if (e.mCheckUsingOCSPConfigEntry && e.mCheckUsingOCSPConfigEntry->boolValue() != b) { e.mCheckUsingOCSPConfigEntry->setBoolValue(b); } // Set allow-ocsp together with enable-ocsp if (e.mEnableOCSPsendingConfigEntry && e.mEnableOCSPsendingConfigEntry->boolValue() != b) { e.mEnableOCSPsendingConfigEntry->setBoolValue(b); } saveCheckBoxToKleoEntry(d->ui.doNotCheckCertPolicyCB, e.mDoNotCheckCertPolicyConfigEntry); saveCheckBoxToKleoEntry(d->ui.neverConsultCB, e.mNeverConsultConfigEntry); saveCheckBoxToKleoEntry(d->ui.allowMarkTrustedCB, e.mAllowMarkTrustedConfigEntry); saveCheckBoxToKleoEntry(d->ui.fetchMissingCB, e.mFetchMissingConfigEntry); QString txt = d->ui.OCSPResponderURL->text(); if (e.mOCSPResponderURLConfigEntry && e.mOCSPResponderURLConfigEntry->stringValue() != txt) { e.mOCSPResponderURLConfigEntry->setStringValue(txt); } txt = d->ui.OCSPResponderSignature->selectedCertificate(); if (e.mOCSPResponderSignature && e.mOCSPResponderSignature->stringValue() != txt) { e.mOCSPResponderSignature->setStringValue(txt); } //dirmngr-0.9.0 options saveCheckBoxToKleoEntry(d->ui.ignoreServiceURLCB, e.mIgnoreServiceURLEntry); saveCheckBoxToKleoEntry(d->ui.ignoreHTTPDPCB, e.mIgnoreHTTPDPEntry); saveCheckBoxToKleoEntry(d->ui.disableHTTPCB, e.mDisableHTTPEntry); saveCheckBoxToKleoEntry(d->ui.ignoreLDAPDPCB, e.mIgnoreLDAPDPEntry); saveCheckBoxToKleoEntry(d->ui.disableLDAPCB, e.mDisableLDAPEntry); if (e.mCustomHTTPProxy) { const bool honor = d->ui.honorHTTPProxyRB->isChecked(); if (e.mHonorHTTPProxy && e.mHonorHTTPProxy->boolValue() != honor) { e.mHonorHTTPProxy->setBoolValue(honor); } const QString chosenProxy = d->ui.customHTTPProxy->text(); if (chosenProxy != e.mCustomHTTPProxy->stringValue()) { e.mCustomHTTPProxy->setStringValue(chosenProxy); } } txt = d->ui.customLDAPProxy->text(); if (e.mCustomLDAPProxy && e.mCustomLDAPProxy->stringValue() != txt) { e.mCustomLDAPProxy->setStringValue(d->ui.customLDAPProxy->text()); } config->sync(true); } CryptoConfigEntry *SMIMECryptoConfigEntries::configEntry(const char *componentName, const char *entryName, int /*CryptoConfigEntry::ArgType*/ argType, ShowError showError) { CryptoConfigEntry *const entry = getCryptoConfigEntry(mConfig, componentName, entryName); if (!entry) { if (showError == DoShowError) { qCWarning(KLEOPATRA_LOG) << QStringLiteral("Backend error: gpgconf doesn't seem to know the entry for %1/%2").arg(QLatin1String(componentName), QLatin1String(entryName)); } return nullptr; } if (entry->argType() != argType || entry->isList()) { if (showError == DoShowError) { qCWarning(KLEOPATRA_LOG) << QStringLiteral("Backend error: gpgconf has wrong type for %1/%2: %3 %4").arg(QLatin1String(componentName), QLatin1String(entryName)).arg(entry->argType()).arg(entry->isList()); } return nullptr; } return entry; } #include "moc_smimevalidationconfigurationwidget.cpp"