File indexing completed on 2024-04-14 04:56:28

0001 /*
0002     The configuration page for the authentication settings of Smb4K
0003 
0004     SPDX-FileCopyrightText: 2003-2023 Alexander Reinholdt <alexander.reinholdt@kdemail.net>
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 // application specific includes
0009 #include "smb4kconfigpageauthentication.h"
0010 #include "core/smb4ksettings.h"
0011 #include "core/smb4kwalletmanager.h"
0012 
0013 // Qt includes
0014 #include <QDialogButtonBox>
0015 #include <QGroupBox>
0016 #include <QHBoxLayout>
0017 #include <QListWidgetItem>
0018 #include <QMouseEvent>
0019 #include <QVBoxLayout>
0020 
0021 // KDE includes
0022 #include <KIconLoader>
0023 #include <KLocalizedString>
0024 #include <KPasswordDialog>
0025 
0026 Smb4KConfigPageAuthentication::Smb4KConfigPageAuthentication(QWidget *parent)
0027     : QWidget(parent)
0028 {
0029     m_entriesLoaded = false;
0030 
0031     QVBoxLayout *layout = new QVBoxLayout(this);
0032 
0033     QGroupBox *settingsBox = new QGroupBox(i18n("Settings"), this);
0034     QVBoxLayout *settingsBoxLayout = new QVBoxLayout(settingsBox);
0035 
0036     QCheckBox *useWallet = new QCheckBox(Smb4KSettings::self()->useWalletItem()->label(), settingsBox);
0037     useWallet->setObjectName(QStringLiteral("kcfg_UseWallet"));
0038 
0039     connect(useWallet, &QCheckBox::toggled, this, &Smb4KConfigPageAuthentication::slotKWalletButtonToggled);
0040 
0041     settingsBoxLayout->addWidget(useWallet);
0042 
0043     m_useDefaultLogin = new QCheckBox(Smb4KSettings::self()->useDefaultLoginItem()->label(), settingsBox);
0044     m_useDefaultLogin->setObjectName(QStringLiteral("kcfg_UseDefaultLogin"));
0045     m_useDefaultLogin->setEnabled(false);
0046 
0047     connect(m_useDefaultLogin, &QCheckBox::toggled, this, &Smb4KConfigPageAuthentication::slotDefaultLoginToggled);
0048 
0049     settingsBoxLayout->addWidget(m_useDefaultLogin);
0050 
0051     layout->addWidget(settingsBox);
0052 
0053     QGroupBox *walletEntriesBox = new QGroupBox(i18n("Wallet Entries"), this);
0054     QVBoxLayout *walletEntriesBoxLayout = new QVBoxLayout(walletEntriesBox);
0055 
0056     m_walletEntriesEditor = new QWidget(walletEntriesBox);
0057     m_walletEntriesEditor->setEnabled(false);
0058     QHBoxLayout *walletEntriesEditorLayout = new QHBoxLayout(m_walletEntriesEditor);
0059     walletEntriesEditorLayout->setContentsMargins(0, 0, 0, 0);
0060 
0061     m_walletEntriesWidget = new QListWidget(m_walletEntriesEditor);
0062     m_walletEntriesWidget->setDragDropMode(QListWidget::NoDragDrop);
0063     m_walletEntriesWidget->setSelectionMode(QListWidget::SingleSelection);
0064     m_walletEntriesWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
0065     m_walletEntriesWidget->viewport()->installEventFilter(this);
0066 
0067     connect(m_walletEntriesWidget, &QListWidget::itemDoubleClicked, this, &Smb4KConfigPageAuthentication::slotWalletItemDoubleClicked);
0068 
0069     walletEntriesEditorLayout->addWidget(m_walletEntriesWidget);
0070 
0071     QDialogButtonBox *buttonBox = new QDialogButtonBox(Qt::Vertical, m_walletEntriesEditor);
0072 
0073     m_loadButton = buttonBox->addButton(i18n("Load"), QDialogButtonBox::ActionRole);
0074     m_loadButton->setIcon(KDE::icon(QStringLiteral("document-open")));
0075 
0076     connect(m_loadButton, &QPushButton::clicked, this, &Smb4KConfigPageAuthentication::slotLoadButtonClicked);
0077 
0078     m_saveButton = buttonBox->addButton(i18n("Save"), QDialogButtonBox::ActionRole);
0079     m_saveButton->setIcon(KDE::icon(QStringLiteral("document-save-all")));
0080     m_saveButton->setEnabled(false);
0081 
0082     connect(m_saveButton, &QPushButton::clicked, this, &Smb4KConfigPageAuthentication::slotSaveButtonClicked);
0083 
0084     m_editButton = buttonBox->addButton(i18n("Edit"), QDialogButtonBox::ActionRole);
0085     m_editButton->setIcon(KDE::icon(QStringLiteral("edit-rename")));
0086     m_editButton->setEnabled(false);
0087 
0088     connect(m_editButton, &QPushButton::clicked, this, &Smb4KConfigPageAuthentication::slotEditButtonClicked);
0089 
0090     m_removeButton = buttonBox->addButton(i18n("Remove"), QDialogButtonBox::ActionRole);
0091     m_removeButton->setIcon(KDE::icon(QStringLiteral("edit-delete")));
0092     m_removeButton->setEnabled(false);
0093 
0094     connect(m_removeButton, &QPushButton::clicked, this, &Smb4KConfigPageAuthentication::slotRemoveButtonClicked);
0095 
0096     m_clearButton = buttonBox->addButton(i18n("Clear"), QDialogButtonBox::ActionRole);
0097     m_clearButton->setIcon(KDE::icon(QStringLiteral("edit-clear-list")));
0098     m_clearButton->setEnabled(false);
0099 
0100     connect(m_clearButton, &QPushButton::clicked, this, &Smb4KConfigPageAuthentication::slotClearButtonClicked);
0101 
0102     m_resetButton = buttonBox->addButton(QDialogButtonBox::Reset);
0103     m_resetButton->setEnabled(false);
0104 
0105     connect(m_resetButton, &QPushButton::clicked, this, &Smb4KConfigPageAuthentication::slotResetButtonClicked);
0106 
0107     walletEntriesEditorLayout->addWidget(buttonBox);
0108 
0109     walletEntriesBoxLayout->addWidget(m_walletEntriesEditor);
0110 
0111     layout->addWidget(walletEntriesBox);
0112 
0113     connect(this, &Smb4KConfigPageAuthentication::walletEntriesModified, this, &Smb4KConfigPageAuthentication::slotEnableResetButton);
0114 }
0115 
0116 Smb4KConfigPageAuthentication::~Smb4KConfigPageAuthentication()
0117 {
0118 }
0119 
0120 void Smb4KConfigPageAuthentication::loadLoginCredentials()
0121 {
0122     m_entriesList = Smb4KWalletManager::self()->loginCredentialsList();
0123 
0124     Q_EMIT walletEntriesModified();
0125 
0126     m_walletEntriesWidget->clear();
0127 
0128     for (Smb4KAuthInfo *authInfo : qAsConst(m_entriesList)) {
0129         switch (authInfo->type()) {
0130         case UnknownNetworkItem: {
0131             QListWidgetItem *item = new QListWidgetItem(KDE::icon(QStringLiteral("dialog-password")), i18n("Default Login"), m_walletEntriesWidget);
0132             item->setData(Qt::UserRole, authInfo->url());
0133             break;
0134         }
0135         default: {
0136             QListWidgetItem *item = new QListWidgetItem(KDE::icon(QStringLiteral("dialog-password")), authInfo->displayString(), m_walletEntriesWidget);
0137             item->setData(Qt::UserRole, authInfo->url());
0138             break;
0139         }
0140         }
0141     }
0142 
0143     m_walletEntriesWidget->sortItems();
0144 
0145     m_entriesLoaded = true;
0146 
0147     m_saveButton->setEnabled(m_walletEntriesWidget->count() != 0);
0148     m_clearButton->setEnabled(m_walletEntriesWidget->count() != 0);
0149 }
0150 
0151 void Smb4KConfigPageAuthentication::saveLoginCredentials()
0152 {
0153     if (loginCredentialsChanged()) {
0154         Smb4KWalletManager::self()->writeLoginCredentialsList(m_entriesList);
0155 
0156         // Do not emit walletEntriesModified() signal, because we do not
0157         // want to enable/disable the "Apply" button as well.
0158         slotEnableResetButton();
0159     }
0160 }
0161 
0162 bool Smb4KConfigPageAuthentication::loginCredentialsLoaded()
0163 {
0164     return m_entriesLoaded;
0165 }
0166 
0167 bool Smb4KConfigPageAuthentication::loginCredentialsChanged()
0168 {
0169     bool changed = false;
0170 
0171     if (m_entriesLoaded) {
0172         QList<Smb4KAuthInfo *> savedLoginCredentials = Smb4KWalletManager::self()->loginCredentialsList();
0173 
0174         if (savedLoginCredentials.size() != m_entriesList.size()) {
0175             changed = true;
0176         } else {
0177             for (Smb4KAuthInfo *oldEntry : qAsConst(savedLoginCredentials)) {
0178                 for (Smb4KAuthInfo *newEntry : qAsConst(m_entriesList)) {
0179                     if (oldEntry->url().matches(newEntry->url(), QUrl::RemoveUserInfo | QUrl::RemovePort)) {
0180                         changed = (oldEntry->url().userInfo() != newEntry->url().userInfo());
0181                         break;
0182                     }
0183                 }
0184 
0185                 if (changed) {
0186                     break;
0187                 }
0188             }
0189         }
0190     }
0191 
0192     return changed;
0193 }
0194 
0195 bool Smb4KConfigPageAuthentication::eventFilter(QObject *object, QEvent *e)
0196 {
0197     if (object == m_walletEntriesWidget->viewport()) {
0198         // If the user clicked on the viewport of the entries view, clear
0199         // the details widget and the "Details" button, if no item
0200         // is under the mouse.
0201         if (e->type() == QEvent::MouseButtonPress) {
0202             QMouseEvent *event = static_cast<QMouseEvent *>(e);
0203 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0204             QPointF pos = m_walletEntriesWidget->mapFromGlobal(event->globalPosition());
0205             QListWidgetItem *item = m_walletEntriesWidget->itemAt(pos.toPoint());
0206 #else
0207             QPoint pos = m_walletEntriesWidget->mapFromGlobal(event->globalPos());
0208             QListWidgetItem *item = m_walletEntriesWidget->itemAt(pos);
0209 #endif
0210 
0211             m_editButton->setEnabled(item != nullptr);
0212             m_removeButton->setEnabled(item != nullptr);
0213 
0214             if (!item) {
0215                 m_walletEntriesWidget->clearSelection();
0216             }
0217         }
0218     }
0219 
0220     return QWidget::eventFilter(object, e);
0221 }
0222 
0223 /////////////////////////////////////////////////////////////////////////////
0224 // SLOT IMPLEMENTATIONS
0225 /////////////////////////////////////////////////////////////////////////////
0226 
0227 void Smb4KConfigPageAuthentication::slotKWalletButtonToggled(bool checked)
0228 {
0229     m_useDefaultLogin->setEnabled(checked);
0230     m_walletEntriesEditor->setEnabled(checked);
0231 }
0232 
0233 void Smb4KConfigPageAuthentication::slotDefaultLoginToggled(bool checked)
0234 {
0235     if (checked && !Smb4KSettings::useDefaultLogin()) {
0236         if (!Smb4KWalletManager::self()->hasDefaultCredentials()) {
0237             Smb4KAuthInfo authInfo;
0238             // If there are no default credentials, we do not need to read them.
0239             KPasswordDialog dlg(this, KPasswordDialog::ShowUsernameLine);
0240             dlg.setPrompt(i18n("Enter the default login information."));
0241             dlg.setUsername(authInfo.userName());
0242             dlg.setPassword(authInfo.password());
0243 
0244             if (dlg.exec() == KPasswordDialog::Accepted) {
0245                 authInfo.setUserName(dlg.username());
0246                 authInfo.setPassword(dlg.password());
0247 
0248                 Smb4KWalletManager::self()->writeLoginCredentials(&authInfo);
0249 
0250                 if (m_entriesLoaded) {
0251                     loadLoginCredentials();
0252                 }
0253             } else {
0254                 m_useDefaultLogin->setChecked(false);
0255             }
0256         }
0257     }
0258 }
0259 
0260 void Smb4KConfigPageAuthentication::slotLoadButtonClicked(bool checked)
0261 {
0262     Q_UNUSED(checked);
0263 
0264     if (!m_entriesLoaded) {
0265         loadLoginCredentials();
0266     }
0267 
0268     m_loadButton->setEnabled(false);
0269     m_walletEntriesWidget->setFocus();
0270 }
0271 
0272 void Smb4KConfigPageAuthentication::slotSaveButtonClicked(bool checked)
0273 {
0274     Q_UNUSED(checked);
0275 
0276     if (m_entriesLoaded) {
0277         saveLoginCredentials();
0278     }
0279 
0280     m_editButton->setEnabled(false);
0281     m_removeButton->setEnabled(false);
0282     m_clearButton->setEnabled((m_walletEntriesWidget->count() != 0));
0283 
0284     m_walletEntriesWidget->clearSelection();
0285 
0286     Q_EMIT walletEntriesModified();
0287 }
0288 
0289 void Smb4KConfigPageAuthentication::slotEditButtonClicked(bool checked)
0290 {
0291     Q_UNUSED(checked);
0292 
0293     KPasswordDialog dlg(this, KPasswordDialog::ShowUsernameLine);
0294 
0295     if (m_walletEntriesWidget->currentItem()) {
0296         Smb4KAuthInfo *authInfo = nullptr;
0297 
0298         for (Smb4KAuthInfo *walletEntry : qAsConst(m_entriesList)) {
0299             // The following check also finds the default login, because it has an empty URL.
0300             if (m_walletEntriesWidget->currentItem()->data(Qt::UserRole).toUrl() == walletEntry->url()) {
0301                 if (walletEntry->type() != Smb4KGlobal::UnknownNetworkItem) {
0302                     dlg.setPrompt(i18n("Set the username and password for wallet entry %1.", walletEntry->displayString()));
0303                 } else {
0304                     dlg.setPrompt(i18n("Set the username and password for the default login."));
0305                 }
0306                 dlg.setUsername(walletEntry->userName());
0307                 dlg.setPassword(walletEntry->password());
0308 
0309                 authInfo = walletEntry;
0310 
0311                 break;
0312             }
0313         }
0314 
0315         if (authInfo) {
0316             if (dlg.exec() == KPasswordDialog::Accepted) {
0317                 authInfo->setUserName(dlg.username());
0318                 authInfo->setPassword(dlg.password());
0319 
0320                 Q_EMIT walletEntriesModified();
0321             }
0322         }
0323     }
0324 }
0325 
0326 void Smb4KConfigPageAuthentication::slotRemoveButtonClicked(bool checked)
0327 {
0328     Q_UNUSED(checked);
0329 
0330     for (int i = 0; i < m_entriesList.size(); ++i) {
0331         // The following check also finds the default login, because it has an empty URL.
0332         if (m_walletEntriesWidget->currentItem()->data(Qt::UserRole).toUrl() == m_entriesList.at(i)->url()) {
0333             switch (m_entriesList.at(i)->type()) {
0334             case UnknownNetworkItem: {
0335                 m_useDefaultLogin->setChecked(false);
0336                 break;
0337             }
0338             default: {
0339                 break;
0340             }
0341             }
0342 
0343             delete m_entriesList.takeAt(i);
0344             break;
0345         } else {
0346             continue;
0347         }
0348     }
0349 
0350     delete m_walletEntriesWidget->currentItem();
0351 
0352     m_clearButton->setEnabled((m_walletEntriesWidget->count() != 0));
0353 
0354     Q_EMIT walletEntriesModified();
0355 }
0356 
0357 void Smb4KConfigPageAuthentication::slotClearButtonClicked(bool checked)
0358 {
0359     Q_UNUSED(checked);
0360 
0361     while (m_walletEntriesWidget->count() != 0) {
0362         delete m_walletEntriesWidget->item(0);
0363     }
0364 
0365     while (!m_entriesList.isEmpty()) {
0366         delete m_entriesList.takeFirst();
0367     }
0368 
0369     m_clearButton->setEnabled(false);
0370 
0371     m_useDefaultLogin->setChecked(false);
0372 
0373     Q_EMIT walletEntriesModified();
0374 }
0375 
0376 void Smb4KConfigPageAuthentication::slotResetButtonClicked(bool checked)
0377 {
0378     Q_UNUSED(checked);
0379 
0380     if (m_entriesLoaded) {
0381         loadLoginCredentials();
0382     }
0383 
0384     Q_EMIT walletEntriesModified();
0385 
0386     m_clearButton->setEnabled((m_walletEntriesWidget->count() != 0));
0387 }
0388 
0389 void Smb4KConfigPageAuthentication::slotEnableResetButton()
0390 {
0391     bool changed = loginCredentialsChanged();
0392     m_resetButton->setEnabled(changed);
0393 }
0394 
0395 void Smb4KConfigPageAuthentication::slotWalletItemDoubleClicked(QListWidgetItem *item)
0396 {
0397     Q_UNUSED(item);
0398 
0399     slotEditButtonClicked(false);
0400 }