diff --git a/kded/service.cpp b/kded/service.cpp index d263a4a..b0ae061 100644 --- a/kded/service.cpp +++ b/kded/service.cpp @@ -1,445 +1,495 @@ /* * Copyright 2017 by Ivan Cukic * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "service.h" #include #include #include #include #include #include #include "engine/vault.h" #include "engine/commandresult.h" #include "ui/vaultcreationwizard.h" #include "ui/vaultimportingwizard.h" #include "ui/vaultconfigurationdialog.h" #include "ui/mountdialog.h" #include #include #ifdef HAVE_NETWORKMANAGER #include #else namespace NetworkManager { bool isNetworkingEnabled() { return true; } void setNetworkingEnabled(bool enabled) { Q_UNUSED(enabled); } } #endif K_PLUGIN_FACTORY_WITH_JSON(PlasmaVaultServiceFactory, "plasmavault.json", registerPlugin();) using namespace PlasmaVault; using AsynQt::Expected; class PlasmaVaultService::Private { public: QHash knownVaults; QSet openVaults; KActivities::Consumer kamd; struct NetworkingState { bool wasNetworkingEnabled; QVector devicesInhibittingNetworking; }; // Ideally, this would be std::optional... lovely C++17 Expected savedNetworkingState = Expected::error(0); void saveNetworkingState() { // Ignore the request if we already have a saved state if (savedNetworkingState) { return; } savedNetworkingState = Expected::success( NetworkingState { NetworkManager::isNetworkingEnabled() || true, {} }); } void restoreNetworkingState() { // Ignore the request if we do not have a state saved // or if there are more devices inhibitting networking if (!savedNetworkingState || !savedNetworkingState->devicesInhibittingNetworking.isEmpty()) { return; } NetworkManager::setNetworkingEnabled(savedNetworkingState->wasNetworkingEnabled); } Vault* vaultFor(const QString &device_) const { const Device device(device_); if (!knownVaults.contains(device)) { return nullptr; } return knownVaults[device]; } }; PlasmaVaultService::PlasmaVaultService(QObject * parent, const QVariantList&) : KDEDModule(parent) , d(new Private()) { connect(this, &KDEDModule::moduleRegistered, this, &PlasmaVaultService::slotRegistered); connect(&d->kamd, &KActivities::Consumer::currentActivityChanged, this, &PlasmaVaultService::onCurrentActivityChanged); for (const Device &device: Vault::availableDevices()) { registerVault(new Vault(device, this)); } } PlasmaVaultService::~PlasmaVaultService() { } PlasmaVault::VaultInfoList PlasmaVaultService::availableDevices() const { PlasmaVault::VaultInfoList result; for (const auto &vault: d->knownVaults.values()) { result << vault->info(); } return result; } void PlasmaVaultService::requestNewVault() { const auto dialog = new VaultCreationWizard(); connect(dialog, &VaultCreationWizard::createdVault, this, &PlasmaVaultService::registerVault); dialog->show(); } void PlasmaVaultService::requestImportVault() { const auto dialog = new VaultImportingWizard(); connect(dialog, &VaultImportingWizard::importedVault, this, &PlasmaVaultService::registerVault); dialog->show(); } void PlasmaVaultService::slotRegistered(const QDBusObjectPath &path) { if (path.path() == QLatin1String("/modules/plasmavault")) { emit registered(); } } void PlasmaVaultService::registerVault(Vault *vault) { if (!vault->isValid()) { qWarning() << "Warning: Trying to register an invalid vault: " << vault->device(); return; } if (d->knownVaults.contains(vault->device())) { qWarning() << "Warning: This one is already registered: " << vault->device(); return; } vault->setParent(this); d->knownVaults[vault->device()] = vault; connect(vault, &Vault::statusChanged, this, &PlasmaVaultService::onVaultStatusChanged); connect(vault, &Vault::messageChanged, this, &PlasmaVaultService::onVaultMessageChanged); connect(vault, &Vault::infoChanged, this, &PlasmaVaultService::onVaultInfoChanged); emit vaultAdded(vault->info()); if (vault->status() == VaultInfo::Opened) { d->openVaults << vault->device(); } } void PlasmaVaultService::forgetVault(Vault* vault) { // Can not be open // d->openVaults.remove(vault.device()); // and therefore can not inhibit networking // ... d->savedNetworkingState ... emit vaultRemoved(vault->device().data()); d->knownVaults.remove(vault->device()); vault->deleteLater(); } void PlasmaVaultService::onVaultStatusChanged(VaultInfo::Status status) { const auto vault = static_cast(sender()); if (status == VaultInfo::Dismantled) { forgetVault(vault); } else if (status == VaultInfo::Opened) { d->openVaults << vault->device(); if (d->openVaults.size() == 1) { emit hasOpenVaultsChanged(true); } } else { d->openVaults.remove(vault->device()); if (d->openVaults.isEmpty()) { emit hasOpenVaultsChanged(false); } } if (vault->isOfflineOnly()) { d->saveNetworkingState(); auto& devicesInhibittingNetworking = d->savedNetworkingState->devicesInhibittingNetworking; // We need to check whether this vault // should be added or removed from the // inhibitors list const bool alreadyInhibiting = devicesInhibittingNetworking.contains(vault->device()); if (status == VaultInfo::Opened && !alreadyInhibiting) { + auto deviceOpeningHandle = "{opening}" + vault->device(); + devicesInhibittingNetworking.removeAll(deviceOpeningHandle); devicesInhibittingNetworking << vault->device(); } if (status != VaultInfo::Opened && alreadyInhibiting) { devicesInhibittingNetworking.removeAll(vault->device()); } - // qDebug() << "Vaults inhibitting networking: " << devicesInhibittingNetworking; - // Now, let's handle the networking part if (!devicesInhibittingNetworking.isEmpty()) { NetworkManager::setNetworkingEnabled(false); } d->restoreNetworkingState(); } emit vaultChanged(vault->info()); } void PlasmaVaultService::onVaultInfoChanged() { const auto vault = static_cast(sender()); emit vaultChanged(vault->info()); } void PlasmaVaultService::onVaultMessageChanged(const QString &message) { Q_UNUSED(message); const auto vault = static_cast(sender()); emit vaultChanged(vault->info()); } -void showPasswordMountDialog(Vault *vault, const std::function &function) +template +void showPasswordMountDialog(Vault *vault, + OnAccepted onAccepted, + OnRejected onRejected) { - auto dialog = new MountDialog(vault, function); + auto dialog = new MountDialog(vault); + + QObject::connect(dialog, &QDialog::accepted, + vault, onAccepted); + QObject::connect(dialog, &QDialog::rejected, + vault, onRejected); + dialog->open(); } //^ void PlasmaVaultService::openVault(const QString &device) { if (auto vault = d->vaultFor(device)) { if (vault->isOpened()) return; + if (vault->isOfflineOnly()) { + d->saveNetworkingState(); + + auto& devicesInhibittingNetworking = d->savedNetworkingState->devicesInhibittingNetworking; + auto deviceOpeningHandle = "{opening}" + vault->device(); + + // We need to check whether this vault + // should be added or removed from the + // inhibitors list + const bool alreadyInhibiting = + devicesInhibittingNetworking.contains(deviceOpeningHandle); + + if (!alreadyInhibiting) { + devicesInhibittingNetworking << deviceOpeningHandle; + } + + NetworkManager::setNetworkingEnabled(false); + } + + auto stopInhibiting = [this, vault] { + auto& devicesInhibittingNetworking = d->savedNetworkingState->devicesInhibittingNetworking; + auto deviceOpeningHandle = "{opening}" + vault->device(); + devicesInhibittingNetworking.removeAll(deviceOpeningHandle); + }; + showPasswordMountDialog(vault, - [this, vault] { - emit vaultChanged(vault->info()); - }); + [this, vault, stopInhibiting] { + emit vaultChanged(vault->info()); + stopInhibiting(); + }, + [this, vault, stopInhibiting] { + stopInhibiting(); + if (vault->status() != VaultInfo::Opened) { + d->restoreNetworkingState(); + } + } + ); } } void PlasmaVaultService::closeVault(const QString &device) { if (auto vault = d->vaultFor(device)) { if (!vault->isOpened()) return; vault->close(); } } void PlasmaVaultService::configureVault(const QString &device) { if (auto vault = d->vaultFor(device)) { const auto dialog = new VaultConfigurationDialog(vault); dialog->show(); } } void PlasmaVaultService::forceCloseVault(const QString &device) { if (auto vault = d->vaultFor(device)) { if (!vault->isOpened()) return; vault->forceClose(); } } void PlasmaVaultService::openVaultInFileManager(const QString &device) { if (auto vault = d->vaultFor(device)) { if (vault->isOpened()) { new KRun(QUrl::fromLocalFile((QString)vault->mountPoint()), nullptr); } else { - showPasswordMountDialog(vault, [this, vault] { - emit vaultChanged(vault->info()); - new KRun(QUrl::fromLocalFile((QString)vault->mountPoint()), nullptr); - }); + showPasswordMountDialog(vault, + [this, vault] { + emit vaultChanged(vault->info()); + new KRun(QUrl::fromLocalFile((QString)vault->mountPoint()), nullptr); + }, + [this, vault] { + if (vault->status() != VaultInfo::Opened) { + auto& devicesInhibittingNetworking = d->savedNetworkingState->devicesInhibittingNetworking; + devicesInhibittingNetworking.removeAll(vault->device()); + d->restoreNetworkingState(); + } + }); } } } void PlasmaVaultService::onCurrentActivityChanged( const QString ¤tActivity) { for (auto* vault: d->knownVaults.values()) { const auto vaultActivities = vault->activities(); if (!vaultActivities.isEmpty() && !vaultActivities.contains(currentActivity)) { vault->close(); } } } bool PlasmaVaultService::hasOpenVaults() const { return !d->openVaults.isEmpty(); } void PlasmaVaultService::closeAllVaults() { for (const auto& device: d->openVaults) { closeVault(device.data()); } } void PlasmaVaultService::forceCloseAllVaults() { for (const auto& device: d->openVaults) { forceCloseVault(device.data()); } } void PlasmaVaultService::deleteVault(const QString &device, const QString &name) { if (!d->knownVaults.contains(Device(device))) { qWarning() << "The specified vault does not exist: " << device; return; } auto vault = d->knownVaults[Device(device)]; if (vault->status() == VaultInfo::Opened) { qWarning() << "Can not delete an open vault: " << device; return; } if (vault->name() != name) { qWarning() << "Name is not correct: " << device; return; } vault->dismantle({}); } #include "service.moc" diff --git a/kded/ui/mountdialog.cpp b/kded/ui/mountdialog.cpp index a75b9e5..5cb81e3 100644 --- a/kded/ui/mountdialog.cpp +++ b/kded/ui/mountdialog.cpp @@ -1,78 +1,76 @@ /* * Copyright 2017 by Kees vd Broek * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "mountdialog.h" #include "engine/vault.h" #include #include #include #include -MountDialog::MountDialog(PlasmaVault::Vault *vault, const std::function &function) - : m_vault(vault), - m_function(function) +MountDialog::MountDialog(PlasmaVault::Vault *vault) + : m_vault(vault) { m_ui.setupUi(this); m_errorLabel = new KMessageWidget(this); m_errorLabel->setMessageType(KMessageWidget::Error); m_errorLabel->setCloseButtonVisible(false); m_errorLabel->setIcon(QIcon::fromTheme("dialog-error")); m_errorLabel->setVisible(false); auto errorLabelSizePolicy = m_errorLabel->sizePolicy(); errorLabelSizePolicy.setHorizontalPolicy(QSizePolicy::Expanding); m_errorLabel->setSizePolicy(errorLabelSizePolicy); m_errorLabel->setVisible(false); m_ui.formLayout->addRow(QString(), m_errorLabel); m_ui.vaultName->setText(vault->name()); QStyleOption option; option.initFrom(this); const int iconSize = style()->pixelMetric(QStyle::PM_MessageBoxIconSize, &option, this); m_ui.icon->setPixmap(QIcon::fromTheme(QStringLiteral("dialog-password")).pixmap(iconSize)); } void MountDialog::accept() { setCursor(Qt::WaitCursor); m_errorLabel->setVisible(false); setEnabled(false); m_ui.password->lineEdit()->setCursor(Qt::WaitCursor); QString pwd = m_ui.password->password(); auto future = m_vault->open({ { KEY_PASSWORD, pwd } }); const auto result = AsynQt::await(future); unsetCursor(); setEnabled(true); m_ui.password->lineEdit()->unsetCursor(); if (result) { - m_function(); QDialog::accept(); } else { qDebug() << "We've got an error" << result.error().message(); // m_ui.errorLabel->setText(i18n("Failed to open: %1").arg(result.error().message())); m_errorLabel->setText(i18n("Failed to open: %1", result.error().message())); m_errorLabel->setVisible(true); } } diff --git a/kded/ui/mountdialog.h b/kded/ui/mountdialog.h index 47b365d..e050a9f 100644 --- a/kded/ui/mountdialog.h +++ b/kded/ui/mountdialog.h @@ -1,49 +1,48 @@ /* * Copyright 2017 by Kees vd Broek * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MOUNTDIALOG_H #define MOUNTDIALOG_H #include #include #include "ui_mountdialog.h" class KMessageWidget; namespace PlasmaVault { class Vault; } class MountDialog : public QDialog { public: - MountDialog(PlasmaVault::Vault *vault, const std::function &function); + MountDialog(PlasmaVault::Vault *vault); protected: void accept() override; private: PlasmaVault::Vault *m_vault; - std::function m_function; Ui_MountDialog m_ui; KMessageWidget* m_errorLabel; }; #endif