11#include <config-libkleo.h> 
   13#include "editdirectoryservicedialog.h" 
   15#include <libkleo/algorithm.h> 
   16#include <libkleo/gnupg.h> 
   17#include <libkleo/keyserverconfig.h> 
   19#include <KCollapsibleGroupBox> 
   20#include <KColorScheme> 
   21#include <KConfigGroup> 
   23#include <KLocalizedString> 
   24#include <KPasswordLineEdit> 
   25#include <KSharedConfig> 
   26#include <KStandardGuiItem> 
   28#include <QButtonGroup> 
   30#include <QDialogButtonBox> 
   36#include <QRadioButton> 
   44int defaultPort(KeyserverConnection connection)
 
   46    return connection == KeyserverConnection::TunnelThroughTLS ? 636 : 389;
 
   50class EditDirectoryServiceDialog::Private
 
   52    EditDirectoryServiceDialog *
const q;
 
   55        QLineEdit *hostEdit = 
nullptr;
 
   56        QSpinBox *portSpinBox = 
nullptr;
 
   57        QCheckBox *useDefaultPortCheckBox = 
nullptr;
 
   58        QButtonGroup *authenticationGroup = 
nullptr;
 
   59        QLineEdit *userEdit = 
nullptr;
 
   60        KPasswordLineEdit *passwordEdit = 
nullptr;
 
   61        QButtonGroup *connectionGroup = 
nullptr;
 
   62        KCollapsibleGroupBox *advancedSettings = 
nullptr;
 
   63        QLineEdit *baseDnEdit = 
nullptr;
 
   64        QLineEdit *additionalFlagsEdit = 
nullptr;
 
   65        QDialogButtonBox *buttonBox = 
nullptr;
 
   66        QLabel *invalidHostLabel = 
nullptr;
 
   69            : hostEdit{new QLineEdit{
parent}}
 
   70            , portSpinBox{new QSpinBox{
parent}}
 
   71            , useDefaultPortCheckBox{new QCheckBox{
parent}}
 
   72            , authenticationGroup{new QButtonGroup{
parent}}
 
   73            , userEdit{new QLineEdit{
parent}}
 
   74            , passwordEdit{new KPasswordLineEdit{
parent}}
 
   75            , connectionGroup{new QButtonGroup{
parent}}
 
   76            , advancedSettings{new KCollapsibleGroupBox{
parent}}
 
   77            , baseDnEdit{new QLineEdit{
parent}}
 
   78            , additionalFlagsEdit{new QLineEdit{
parent}}
 
   79            , buttonBox{new QDialogButtonBox{
parent}}
 
   80            , invalidHostLabel{new QLabel{
parent}}
 
   82#define SET_OBJECT_NAME(x) x->setObjectName(QStringLiteral(#x)); 
   83            SET_OBJECT_NAME(hostEdit)
 
   84            SET_OBJECT_NAME(portSpinBox)
 
   85            SET_OBJECT_NAME(useDefaultPortCheckBox)
 
   86            SET_OBJECT_NAME(authenticationGroup)
 
   87            SET_OBJECT_NAME(userEdit)
 
   88            SET_OBJECT_NAME(passwordEdit)
 
   89            SET_OBJECT_NAME(connectionGroup)
 
   90            SET_OBJECT_NAME(advancedSettings)
 
   91            SET_OBJECT_NAME(baseDnEdit)
 
   92            SET_OBJECT_NAME(additionalFlagsEdit)
 
   93            SET_OBJECT_NAME(buttonBox)
 
   95            auto mainLayout = 
new QVBoxLayout{
parent};
 
   99                auto layout = 
new QGridLayout{serverWidget};
 
  100                layout->setColumnStretch(2, 1);
 
  103                hostEdit->setToolTip(
i18nc(
"@info:tooltip", 
"Enter the name or IP address of the server hosting the directory service."));
 
  104                hostEdit->setClearButtonEnabled(
true);
 
  111                invalidHostLabel->setPalette(
palette);
 
  112                invalidHostLabel->setText(
i18nc(
"@info:label", 
"Error: Enter a hostname in the correct format, like ldap.example.com."));
 
  113                invalidHostLabel->setVisible(
false);
 
  117                portSpinBox->setRange(1, USHRT_MAX);
 
  118                portSpinBox->setToolTip(
i18nc(
"@info:tooltip",
 
  119                                              "<b>(Optional, the default is fine in most cases)</b> " 
  120                                              "Pick the port number the directory service is listening on."));
 
  122                useDefaultPortCheckBox->setText(
i18n(
"Use default"));
 
  123                useDefaultPortCheckBox->setChecked(
true);
 
  126            mainLayout->addWidget(serverWidget);
 
  128            auto authenticationWidget = 
new QGroupBox{
i18n(
"Authentication"), 
parent};
 
  130                auto layout = 
new QVBoxLayout{authenticationWidget};
 
  132                    auto radioButton = 
new QRadioButton{
i18n(
"Anonymous")};
 
  133                    radioButton->setToolTip(
i18nc(
"@info:tooltip", 
"Use an anonymous LDAP server that does not require authentication."));
 
  134                    radioButton->setChecked(
true);
 
  135                    authenticationGroup->addButton(radioButton, 
static_cast<int>(KeyserverAuthentication::Anonymous));
 
  139                    auto radioButton = 
new QRadioButton{
i18n(
"Authenticate via Active Directory")};
 
  140                    if (!engineIsVersion(2, 2, 28, GpgME::GpgSMEngine)) {
 
  141                        radioButton->setText(
i18n(
"Authenticate via Active Directory (requires GnuPG 2.2.28 or later)"));
 
  143                    radioButton->setToolTip(
 
  144                        i18nc(
"@info:tooltip", 
"On Windows, authenticate to the LDAP server using the Active Directory with the current user."));
 
  145                    authenticationGroup->addButton(radioButton, 
static_cast<int>(KeyserverAuthentication::ActiveDirectory));
 
  149                    auto radioButton = 
new QRadioButton{
i18n(
"Authenticate with user and password")};
 
  150                    radioButton->setToolTip(
i18nc(
"@info:tooltip", 
"Authenticate to the LDAP server with your LDAP credentials."));
 
  151                    authenticationGroup->addButton(radioButton, 
static_cast<int>(KeyserverAuthentication::Password));
 
  157                    auto layout = 
new QGridLayout{credentialsWidget};
 
  158                    layout->setColumnStretch(1, 1);
 
  161                    userEdit->setToolTip(
i18nc(
"@info:tooltip", 
"Enter your LDAP user resp. Bind DN for authenticating to the LDAP server."));
 
  162                    userEdit->setClearButtonEnabled(
true);
 
  166                    passwordEdit->setToolTip(
xi18nc(
"@info:tooltip",
 
  167                                                    "Enter your password for authenticating to the LDAP server.<nl/>" 
  168                                                    "<warning>The password will be saved in the clear " 
  169                                                    "in a configuration file in your home directory.</warning>"));
 
  170                    passwordEdit->setClearButtonEnabled(
true);
 
  175            mainLayout->addWidget(authenticationWidget);
 
  177            auto securityWidget = 
new QGroupBox{
i18n(
"Connection Security"), 
parent};
 
  178            if (!engineIsVersion(2, 2, 28, GpgME::GpgSMEngine)) {
 
  179                securityWidget->setTitle(
i18n(
"Connection Security (requires GnuPG 2.2.28 or later)"));
 
  182                auto layout = 
new QVBoxLayout{securityWidget};
 
  184                    auto radioButton = 
new QRadioButton{
i18n(
"Use default connection (probably not TLS secured)")};
 
  185                    radioButton->setToolTip(
i18nc(
"@info:tooltip",
 
  186                                                  "Use GnuPG's default to connect to the LDAP server. " 
  187                                                  "By default, GnuPG 2.3 and earlier use a plain, not TLS secured connection. " 
  188                                                  "<b>(Not recommended)</b>"));
 
  189                    radioButton->setChecked(
true);
 
  190                    connectionGroup->addButton(radioButton, 
static_cast<int>(KeyserverConnection::Default));
 
  194                    auto radioButton = 
new QRadioButton{
i18n(
"Do not use a TLS secured connection")};
 
  195                    radioButton->setToolTip(
i18nc(
"@info:tooltip",
 
  196                                                  "Use a plain, not TLS secured connection to connect to the LDAP server. " 
  197                                                  "<b>(Not recommended)</b>"));
 
  198                    connectionGroup->addButton(radioButton, 
static_cast<int>(KeyserverConnection::Plain));
 
  202                    auto radioButton = 
new QRadioButton{
i18n(
"Use TLS secured connection")};
 
  203                    radioButton->setToolTip(
i18nc(
"@info:tooltip",
 
  204                                                  "Use a standard TLS secured connection (initiated with STARTTLS) " 
  205                                                  "to connect to the LDAP server. " 
  206                                                  "<b>(Recommended)</b>"));
 
  207                    connectionGroup->addButton(radioButton, 
static_cast<int>(KeyserverConnection::UseSTARTTLS));
 
  211                    auto radioButton = 
new QRadioButton{
i18n(
"Tunnel LDAP through a TLS connection")};
 
  212                    radioButton->setToolTip(
i18nc(
"@info:tooltip",
 
  213                                                  "Use a TLS secured connection through which the connection to the " 
  214                                                  "LDAP server is tunneled. " 
  215                                                  "<b>(Not recommended)</b>"));
 
  216                    connectionGroup->addButton(radioButton, 
static_cast<int>(KeyserverConnection::TunnelThroughTLS));
 
  220            mainLayout->addWidget(securityWidget);
 
  222            advancedSettings->setTitle(
i18n(
"Advanced Settings"));
 
  224                auto layout = 
new QGridLayout{advancedSettings};
 
  225                layout->setColumnStretch(1, 1);
 
  228                baseDnEdit->setToolTip(
i18nc(
"@info:tooltip",
 
  229                                             "<b>(Optional, can usually be left empty)</b> " 
  230                                             "Enter the base DN for this LDAP server to limit searches " 
  231                                             "to only that subtree of the directory."));
 
  232                baseDnEdit->setClearButtonEnabled(
true);
 
  236                additionalFlagsEdit->setToolTip(
i18nc(
"@info:tooltip",
 
  237                                                      "Here you can enter additional flags that are not yet (or no longer) " 
  238                                                      "supported by Kleopatra. For example, older versions of GnuPG use " 
  239                                                      "<code>ldaps</code> to request a TLS secured connection."));
 
  240                additionalFlagsEdit->setClearButtonEnabled(
true);
 
  243            mainLayout->addWidget(advancedSettings);
 
  245            mainLayout->addStretch(1);
 
  251            mainLayout->addWidget(buttonBox);
 
  257        return ui.hostEdit->text().trimmed();
 
  262        return ui.useDefaultPortCheckBox->isChecked() ? -1 : ui.portSpinBox->value();
 
  265    KeyserverAuthentication authentication()
 const 
  267        return KeyserverAuthentication{ui.authenticationGroup->checkedId()};
 
  272        return ui.userEdit->text().trimmed();
 
  275    QString password()
 const 
  277        return ui.passwordEdit->password(); 
 
  280    KeyserverConnection connection()
 const 
  282        return KeyserverConnection{ui.connectionGroup->checkedId()};
 
  285    QString baseDn()
 const 
  287        return ui.baseDnEdit->text().trimmed();
 
  290    QStringList additionalFlags()
 const 
  292        return transformInPlace(ui.additionalFlagsEdit->text().split(QLatin1Char{
','}, 
Qt::SkipEmptyParts), [](
const auto &flag) {
 
  293            return flag.trimmed();
 
  297    bool inputIsAcceptable()
 const 
  299        const bool hostIsSet = !host().isEmpty();
 
  302        ui.invalidHostLabel->setVisible(!url.
isValid());
 
  303        const bool requiredCredentialsAreSet = authentication() != KeyserverAuthentication::Password || (!user().isEmpty() && !password().isEmpty());
 
  304        return hostIsSet && requiredCredentialsAreSet && url.
isValid();
 
  309        ui.portSpinBox->setEnabled(!ui.useDefaultPortCheckBox->isChecked());
 
  310        if (ui.useDefaultPortCheckBox->isChecked()) {
 
  311            ui.portSpinBox->setValue(defaultPort(connection()));
 
  314        ui.userEdit->setEnabled(authentication() == KeyserverAuthentication::Password);
 
  315        ui.passwordEdit->setEnabled(authentication() == KeyserverAuthentication::Password);
 
  321    Private(EditDirectoryServiceDialog *q)
 
  337        connect(ui.passwordEdit, &KPasswordLineEdit::passwordChanged, q, [
this]() {
 
  357    void setKeyserver(
const KeyserverConfig &keyserver)
 
  359        ui.hostEdit->setText(keyserver.host());
 
  360        ui.useDefaultPortCheckBox->setChecked(keyserver.port() == -1);
 
  361        ui.portSpinBox->setValue(keyserver.port() == -1 ? defaultPort(keyserver.connection()) : keyserver.port());
 
  362        ui.authenticationGroup->button(
static_cast<int>(keyserver.authentication()))->setChecked(
true);
 
  363        ui.userEdit->setText(keyserver.user());
 
  364        ui.passwordEdit->setPassword(keyserver.password());
 
  365        ui.connectionGroup->button(
static_cast<int>(keyserver.connection()))->setChecked(
true);
 
  366        ui.baseDnEdit->setText(keyserver.ldapBaseDn());
 
  367        ui.additionalFlagsEdit->setText(keyserver.additionalFlags().join(QLatin1Char{
','}));
 
  369        ui.advancedSettings->setExpanded(!keyserver.ldapBaseDn().isEmpty() || !keyserver.additionalFlags().empty());
 
  373    KeyserverConfig keyserver()
 const 
  375        KeyserverConfig keyserver;
 
  376        keyserver.setHost(host());
 
  377        keyserver.setPort(port());
 
  378        keyserver.setAuthentication(authentication());
 
  379        keyserver.setUser(user());
 
  380        keyserver.setPassword(password());
 
  381        keyserver.setConnection(connection());
 
  382        keyserver.setLdapBaseDn(baseDn());
 
  383        keyserver.setAdditionalFlags(additionalFlags());
 
  392        configGroup.writeEntry(
"Size", q->size());
 
  399        const auto size = configGroup.readEntry(
"Size", QSize{});
 
  400        if (
size.isValid()) {
 
  408    , d{std::make_unique<Private>(this)}
 
  410    setWindowTitle(
i18nc(
"@title:window", 
"Edit Directory Service"));
 
  413EditDirectoryServiceDialog::~EditDirectoryServiceDialog() = 
default;
 
  415void EditDirectoryServiceDialog::setKeyserver(
const KeyserverConfig &keyserver)
 
  417    d->setKeyserver(keyserver);
 
  420KeyserverConfig EditDirectoryServiceDialog::keyserver()
 const 
  422    return d->keyserver();
 
  425#include "moc_editdirectoryservicedialog.cpp" 
static void assign(QPushButton *button, const KGuiItem &item)
 
static KSharedConfig::Ptr openStateConfig(const QString &fileName=QString())
 
QString xi18nc(const char *context, const char *text, const TYPE &arg...)
 
QString i18nc(const char *context, const char *text, const TYPE &arg...)
 
QString i18n(const char *text, const TYPE &arg...)
 
void textEdited(const QString &text)
 
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
 
QObject * parent() const const
 
bool isValid() const const
 
void setHost(const QString &host, ParsingMode mode)