Page MenuHome GnuPG

directoryserviceswidget.cpp
No OneTemporary

directoryserviceswidget.cpp

/*
ui/directoryserviceswidget.cpp
This file is part of libkleopatra, the KDE keymanagement library
SPDX-FileCopyrightText: 2001, 2002, 2004 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2017 Bundesamnt für Sicherheit in der Informationstechnik
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-libkleo.h>
#include "directoryserviceswidget.h"
#include "editdirectoryservicedialog.h"
#include <libkleo/gnupg.h>
#include <libkleo/keyserverconfig.h>
#include <kleo_ui_debug.h>
#include <KLocalizedString>
#include <QListView>
#include <QMenu>
#include <QPointer>
#include <QPushButton>
#include <QToolButton>
#include <QVBoxLayout>
using namespace Kleo;
namespace
{
bool activeDirectoryIsSupported()
{
return engineIsVersion(2, 2, 28, GpgME::GpgSMEngine);
}
bool isStandardActiveDirectory(const KeyserverConfig &keyserver)
{
return (keyserver.authentication() == KeyserverAuthentication::ActiveDirectory) && keyserver.host().isEmpty();
}
bool keyserverIsEditable(const KeyserverConfig &keyserver)
{
// standard AD is not editable
return !isStandardActiveDirectory(keyserver);
}
class KeyserverModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit KeyserverModel(QObject *parent = nullptr)
: QAbstractListModel{parent}
{
}
void setKeyservers(const std::vector<KeyserverConfig> &servers)
{
clear();
beginInsertRows(QModelIndex(), 0, servers.size() - 1);
m_items = servers;
endInsertRows();
}
void addKeyserver(const KeyserverConfig &keyserver)
{
const auto row = m_items.size();
beginInsertRows(QModelIndex(), row, row);
m_items.push_back(keyserver);
endInsertRows();
}
KeyserverConfig getKeyserver(unsigned int id)
{
if (id >= m_items.size()) {
qCDebug(KLEO_UI_LOG) << __func__ << "invalid keyserver id:" << id;
return {};
}
return m_items[id];
}
void updateKeyserver(unsigned int id, const KeyserverConfig &keyserver)
{
if (id >= m_items.size()) {
qCDebug(KLEO_UI_LOG) << __func__ << "invalid keyserver id:" << id;
return;
}
m_items[id] = keyserver;
Q_EMIT dataChanged(index(id), index(id));
}
void deleteKeyserver(unsigned int id)
{
if (id >= m_items.size()) {
qCDebug(KLEO_UI_LOG) << __func__ << "invalid keyserver id:" << id;
return;
}
beginRemoveRows(QModelIndex(), id, id);
m_items.erase(m_items.begin() + id);
endRemoveRows();
}
void clear()
{
if (m_items.empty()) {
return;
}
beginRemoveRows(QModelIndex(), 0, m_items.size() - 1);
m_items.clear();
endRemoveRows();
}
int rowCount(const QModelIndex & = QModelIndex()) const override
{
return m_items.size();
}
QVariant data(const QModelIndex &index, int role) const override
{
if (!index.isValid()) {
return {};
}
switch (role) {
case Qt::DisplayRole:
case Qt::EditRole: {
const auto keyserver = m_items[index.row()];
return isStandardActiveDirectory(keyserver) ? i18n("Active Directory") : keyserver.host();
}
}
return {};
}
bool hasActiveDirectory()
{
// check whether any of the model items represents an Active Directory keyserver
return std::any_of(std::cbegin(m_items), std::cend(m_items), isStandardActiveDirectory);
}
private:
using QAbstractListModel::setData;
private:
std::vector<KeyserverConfig> m_items;
};
}
class DirectoryServicesWidget::Private
{
DirectoryServicesWidget *const q;
struct {
QListView *keyserverList = nullptr;
QToolButton *newButton = nullptr;
QAction *addActiveDirectoryAction = nullptr;
QAction *addLdapServerAction = nullptr;
QPushButton *editButton = nullptr;
QPushButton *deleteButton = nullptr;
} ui;
KeyserverModel *keyserverModel = nullptr;
bool readOnly = false;
public:
Private(DirectoryServicesWidget *qq)
: q(qq)
{
auto mainLayout = new QVBoxLayout{q};
auto gridLayout = new QGridLayout{};
gridLayout->setColumnStretch(0, 1);
gridLayout->setRowStretch(1, 1);
keyserverModel = new KeyserverModel{q};
ui.keyserverList = new QListView();
ui.keyserverList->setModel(keyserverModel);
ui.keyserverList->setModelColumn(0);
ui.keyserverList->setSelectionBehavior(QAbstractItemView::SelectRows);
ui.keyserverList->setSelectionMode(QAbstractItemView::SingleSelection);
ui.keyserverList->setWhatsThis(i18nc("@info:whatsthis", "This is a list of all directory services that are configured for use with X.509."));
gridLayout->addWidget(ui.keyserverList, 1, 0);
auto groupsButtonLayout = new QVBoxLayout();
auto menu = new QMenu{q};
ui.addActiveDirectoryAction = menu->addAction(i18n("Active Directory"), [this]() {
addActiveDirectory();
});
ui.addActiveDirectoryAction->setToolTip(i18nc("@info:tooltip",
"Click to use a directory service running on your Active Directory. "
"This works only on Windows and requires GnuPG 2.2.28 or later."));
ui.addActiveDirectoryAction->setEnabled(activeDirectoryIsSupported());
ui.addLdapServerAction = menu->addAction(i18n("LDAP Server"), [this]() {
addLdapServer();
});
ui.addLdapServerAction->setToolTip(i18nc("@info:tooltip", "Click to add a directory service provided by an LDAP server."));
ui.newButton = new QToolButton{q};
ui.newButton->setText(i18n("Add"));
ui.newButton->setToolTip(i18nc("@info:tooltip", "Click to add a directory service."));
ui.newButton->setWhatsThis(i18nc("@info:whatsthis",
"Click this button to add a directory service to the list of services. "
"The change will only take effect once you acknowledge the configuration dialog."));
ui.newButton->setToolButtonStyle(Qt::ToolButtonTextOnly);
ui.newButton->setPopupMode(QToolButton::InstantPopup);
ui.newButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); // expand horizontally like the QPushButtons
ui.newButton->setMenu(menu);
groupsButtonLayout->addWidget(ui.newButton);
ui.editButton = new QPushButton(i18n("Edit"));
ui.editButton->setToolTip(i18nc("@info:tooltip", "Click to edit the selected service."));
ui.editButton->setWhatsThis(i18nc("@info:whatsthis",
"Click this button to edit the settings of the currently selected directory service. "
"The changes will only take effect once you acknowledge the configuration dialog."));
ui.editButton->setEnabled(false);
groupsButtonLayout->addWidget(ui.editButton);
ui.deleteButton = new QPushButton(i18n("Delete"));
ui.deleteButton->setToolTip(i18nc("@info:tooltip", "Click to remove the selected service."));
ui.deleteButton->setWhatsThis(i18nc("@info:whatsthis",
"Click this button to remove the currently selected directory service. "
"The change will only take effect once you acknowledge the configuration dialog."));
ui.deleteButton->setEnabled(false);
groupsButtonLayout->addWidget(ui.deleteButton);
groupsButtonLayout->addStretch(1);
gridLayout->addLayout(groupsButtonLayout, 1, 1);
mainLayout->addLayout(gridLayout, /*stretch=*/1);
connect(keyserverModel, &QAbstractItemModel::dataChanged, q, [this]() {
modelChanged();
});
connect(keyserverModel, &QAbstractItemModel::rowsInserted, q, [this]() {
modelChanged();
});
connect(keyserverModel, &QAbstractItemModel::rowsRemoved, q, [this]() {
modelChanged();
});
connect(ui.keyserverList->selectionModel(), &QItemSelectionModel::selectionChanged, q, [this]() {
selectionChanged();
});
connect(ui.keyserverList, &QListView::doubleClicked, q, [this](const QModelIndex &index) {
if (!readOnly) {
editKeyserver(index);
}
});
connect(ui.editButton, &QPushButton::clicked, q, [this]() {
editKeyserver();
});
connect(ui.deleteButton, &QPushButton::clicked, q, [this]() {
deleteKeyserver();
});
}
void setReadOnly(bool ro)
{
readOnly = ro;
updateActions();
}
void setKeyservers(const std::vector<KeyserverConfig> &servers)
{
keyserverModel->setKeyservers(servers);
}
std::vector<KeyserverConfig> keyservers() const
{
std::vector<KeyserverConfig> result;
result.reserve(keyserverModel->rowCount());
for (int row = 0; row < keyserverModel->rowCount(); ++row) {
result.push_back(keyserverModel->getKeyserver(row));
}
return result;
}
void clear()
{
if (keyserverModel->rowCount() == 0) {
return;
}
keyserverModel->clear();
}
private:
auto selectedIndex()
{
const auto indexes = ui.keyserverList->selectionModel()->selectedRows();
return indexes.empty() ? QModelIndex() : indexes[0];
}
void modelChanged()
{
updateActions();
Q_EMIT q->changed();
}
void selectionChanged()
{
updateActions();
}
void updateActions()
{
const auto index = selectedIndex();
ui.newButton->setEnabled(!readOnly);
ui.addActiveDirectoryAction->setEnabled(activeDirectoryIsSupported() && !keyserverModel->hasActiveDirectory());
ui.editButton->setEnabled(!readOnly && index.isValid() && keyserverIsEditable(keyserverModel->getKeyserver(index.row())));
ui.deleteButton->setEnabled(!readOnly && index.isValid());
}
void handleEditKeyserverDialogResult(const int id, const EditDirectoryServiceDialog *dialog)
{
if (id >= 0) {
keyserverModel->updateKeyserver(id, dialog->keyserver());
} else {
keyserverModel->addKeyserver(dialog->keyserver());
}
}
void showEditKeyserverDialog(const int id, const KeyserverConfig &keyserver, const QString &windowTitle)
{
QPointer<EditDirectoryServiceDialog> dialog{new EditDirectoryServiceDialog{q}};
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->setWindowModality(Qt::WindowModal);
dialog->setWindowTitle(windowTitle);
dialog->setKeyserver(keyserver);
connect(dialog, &QDialog::accepted, q, [dialog, id, this] {
handleEditKeyserverDialogResult(id, dialog);
});
dialog->show();
}
void addActiveDirectory()
{
KeyserverConfig keyserver;
keyserver.setAuthentication(KeyserverAuthentication::ActiveDirectory);
keyserverModel->addKeyserver(keyserver);
}
void addLdapServer()
{
showEditKeyserverDialog(-1, {}, i18nc("@title:window", "LDAP Directory Service"));
}
void editKeyserver(const QModelIndex &index = {})
{
const auto serverIndex = index.isValid() ? index : selectedIndex();
if (!serverIndex.isValid()) {
qCDebug(KLEO_UI_LOG) << __func__ << "selection is empty";
return;
}
const auto id = serverIndex.row();
const KeyserverConfig keyserver = keyserverModel->getKeyserver(id);
if (!keyserverIsEditable(keyserver)) {
qCDebug(KLEO_UI_LOG) << __func__ << "selected keyserver (id:" << id << ") cannot be modified";
return;
}
showEditKeyserverDialog(id, keyserver, i18nc("@title:window", "LDAP Directory Service"));
}
void deleteKeyserver()
{
const QModelIndex serverIndex = selectedIndex();
if (!serverIndex.isValid()) {
qCDebug(KLEO_UI_LOG) << __func__ << "selection is empty";
return;
}
keyserverModel->deleteKeyserver(serverIndex.row());
}
};
DirectoryServicesWidget::DirectoryServicesWidget(QWidget *parent)
: QWidget{parent}
, d{std::make_unique<Private>(this)}
{
}
DirectoryServicesWidget::~DirectoryServicesWidget() = default;
void DirectoryServicesWidget::setKeyservers(const std::vector<KeyserverConfig> &servers)
{
d->setKeyservers(servers);
}
std::vector<KeyserverConfig> DirectoryServicesWidget::keyservers() const
{
return d->keyservers();
}
void DirectoryServicesWidget::setReadOnly(bool readOnly)
{
d->setReadOnly(readOnly);
}
void DirectoryServicesWidget::clear()
{
d->clear();
}
#include "directoryserviceswidget.moc"
#include "moc_directoryserviceswidget.cpp"

File Metadata

Mime Type
text/x-c++
Expires
Mon, Aug 25, 11:03 PM (5 h, 28 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
65/1c/dafc2dd367415f4bf9a6a0c8cb28

Event Timeline