Commit eadb8c06 authored by Ivan Čukić's avatar Ivan Čukić 👁
Browse files

Added vault deletion through the configuration dialogue

BUG:385444
parent db2986a2
/*
* Copyright (C) 2016 Ivan Cukic <ivan.cukic(at)kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 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 6 of version 3 of the license.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* If not, see <http://www.gnu.org/licenses/>.
*/
//
// W A R N I N G
// -------------
//
// This file is not part of the AsynQt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
namespace AsynQt {
namespace detail {
template <typename _Result>
class KJobFutureInterface : public QObject,
public QFutureInterface<_Result> {
public:
KJobFutureInterface(KJob* job)
: job(job)
{
job->setAutoDelete(false);
}
~KJobFutureInterface()
{
}
void callFinished();
QFuture<_Result> start()
{
QObject::connect(job, &KJob::result,
this, [this] () { callFinished(); },
Qt::QueuedConnection);
this->reportStarted();
job->start();
return this->future();
}
private:
KJob* job;
};
template <typename _Result>
void KJobFutureInterface<_Result>::callFinished()
{
this->reportResult(job);
this->reportFinished();
deleteLater();
}
template <>
void KJobFutureInterface<void>::callFinished()
{
this->reportFinished();
job->deleteLater();
deleteLater();
}
} // namespace detail
} // namespace AsynQt
/*
* Copyright (C) 2016 Ivan Cukic <ivan.cukic(at)kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 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 6 of version 3 of the license.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ASYNQT_CONS_KJOBFUTURE_H
#define ASYNQT_CONS_KJOBFUTURE_H
#include <KJob>
#include <QFuture>
#include <QFutureInterface>
#include <QObject>
#include <memory>
#include "../private/wrappers/kjob_p.h"
namespace AsynQt {
/**
* Creates a future from the specified dbus reply
*/
template <typename _Result>
QFuture<_Result> makeFuture(KJob* job)
{
using namespace detail;
return (new KJobFutureInterface<_Result>(job))->start();
}
} // namespace AsynQt
#endif // ASYNQT_CONS_DBUSFUTURE_H
......@@ -40,7 +40,8 @@ public:
Creating = 3,
Opening = 4,
Closing = 5,
Destroying = 6,
Dismantling = 6,
Dismantled = 7,
Error = 255
};
......@@ -78,7 +79,7 @@ public:
return status == Creating
|| status == Opening
|| status == Closing
|| status == Destroying;
|| status == Dismantling;
}
};
......
......@@ -26,6 +26,7 @@ set (
ui/noticewidget.cpp
ui/passwordchooserwidget.cpp
ui/offlineonlywidget.cpp
ui/vaultdeletionwidget.cpp
ui/vaultcreationwizard.cpp
ui/vaultconfigurationwizard.cpp
......@@ -45,6 +46,7 @@ ki18n_wrap_ui (
ui/noticewidget.ui
ui/passwordchooserwidget.ui
ui/offlineonlywidget.ui
ui/vaultdeletionwidget.ui
ui/vaultcreationwizard.ui
ui/vaultconfigurationwizard.ui
......
......@@ -54,9 +54,9 @@ public:
virtual FutureResult<> close(const Device &device,
const MountPoint &mountPoint) = 0;
virtual FutureResult<> destroy(const Device &device,
const MountPoint &mountPoint,
const Vault::Payload &payload) = 0;
virtual FutureResult<> dismantle(const Device &device,
const MountPoint &mountPoint,
const Vault::Payload &payload) = 0;
virtual FutureResult<> validateBackend() = 0;
......
......@@ -34,7 +34,8 @@ public:
MountPointError,
DeviceError,
BackendError,
CommandError
CommandError,
DeletionError
};
Error(Code code, const QString &message = QString());
......
......@@ -20,17 +20,20 @@
#include "fusebackend_p.h"
#include <QUrl>
#include <QDir>
#include <QProcess>
#include <QRegularExpression>
#include <KMountPoint>
#include <KLocalizedString>
#include <KIO/DeleteJob>
#include <algorithm>
#include <asynqt/basic/all.h>
#include <asynqt/wrappers/process.h>
#include <asynqt/wrappers/kjob.h>
#include <asynqt/operations/collect.h>
#include <asynqt/operations/transform.h>
......@@ -162,20 +165,29 @@ FutureResult<> FuseBackend::close(const Device &device,
FutureResult<> FuseBackend::destroy(const Device &device,
const MountPoint &mountPoint,
const Vault::Payload &payload)
FutureResult<> FuseBackend::dismantle(const Device &device,
const MountPoint &mountPoint,
const Vault::Payload &payload)
{
// TODO:
// mount
// unmount
// remove the directories
// return Fuse::destroy(device, mountPoint, password);
// return Fuse::dismantle(device, mountPoint, password);
Q_UNUSED(device)
Q_UNUSED(mountPoint)
Q_UNUSED(payload)
return {};
// Removing the data and the mount point
return transform(makeFuture<KJob*>(
KIO::del( { QUrl::fromLocalFile(device.data())
, QUrl::fromLocalFile(mountPoint.data())
} )),
[] (KJob *job) {
job->deleteLater();
return job->error() == 0 ? Result<>::success()
: Result<>::error(Error::DeletionError, job->errorString());
}
);
}
......
......@@ -45,9 +45,9 @@ public:
FutureResult<> close(const Device &device,
const MountPoint &mountPoint) override;
FutureResult<> destroy(const Device &device,
const MountPoint &mountPoint,
const Vault::Payload &payload) override;
FutureResult<> dismantle(const Device &device,
const MountPoint &mountPoint,
const Vault::Payload &payload) override;
protected:
virtual FutureResult<> mount(const Device &device,
......
......@@ -98,47 +98,60 @@ public:
if (data) {
// Checking the status, and whether we should update it
const auto oldStatus = data->status;
const auto newStatus =
isOpened() ? VaultInfo::Opened :
isInitialized() ? VaultInfo::Closed :
VaultInfo::NotInitialized;
if (oldStatus == newStatus) return;
if (oldStatus == VaultInfo::Dismantling) {
// This means that the vault should be forgotten
KConfigGroup generalConfig(config, "EncryptedDevices");
generalConfig.deleteEntry(device.data());
data->status = newStatus;
KConfigGroup vaultConfig(config, device.data());
vaultConfig.deleteGroup();
emit q->statusChanged(data->status);
emit q->statusChanged(data->status = VaultInfo::Dismantled);
if (newStatus == VaultInfo::Closed || newStatus == VaultInfo::Opened) {
emit q->isOpenedChanged(newStatus == VaultInfo::Opened);
}
} else {
const auto newStatus =
isOpened() ? VaultInfo::Opened :
isInitialized() ? VaultInfo::Closed :
VaultInfo::NotInitialized;
if (oldStatus == VaultInfo::NotInitialized || newStatus == VaultInfo::NotInitialized) {
emit q->isInitializedChanged(newStatus);
}
if (oldStatus == newStatus) return;
if (oldStatus == VaultInfo::Creating
|| oldStatus == VaultInfo::Opening
|| oldStatus == VaultInfo::Closing
|| oldStatus == VaultInfo::Destroying) {
emit q->isBusyChanged(false);
}
data->status = newStatus;
// Saving the data for the current mount
KConfigGroup generalConfig(config, "EncryptedDevices");
generalConfig.writeEntry(device.data(), true);
emit q->statusChanged(data->status);
KConfigGroup vaultConfig(config, device.data());
vaultConfig.writeEntry(CFG_LAST_STATUS, (int)data->status);
vaultConfig.writeEntry(CFG_MOUNT_POINT, data->mountPoint.data());
vaultConfig.writeEntry(CFG_NAME, data->name);
vaultConfig.writeEntry(CFG_BACKEND, data->backend->name());
if (newStatus == VaultInfo::Closed || newStatus == VaultInfo::Opened) {
emit q->isOpenedChanged(newStatus == VaultInfo::Opened);
}
if (oldStatus == VaultInfo::NotInitialized || newStatus == VaultInfo::NotInitialized) {
emit q->isInitializedChanged(newStatus);
}
if (oldStatus == VaultInfo::Creating
|| oldStatus == VaultInfo::Opening
|| oldStatus == VaultInfo::Closing
|| oldStatus == VaultInfo::Dismantling) {
emit q->isBusyChanged(false);
}
// Saving the data for the current mount
KConfigGroup generalConfig(config, "EncryptedDevices");
generalConfig.writeEntry(device.data(), true);
vaultConfig.writeEntry(CFG_ACTIVITIES, data->activities);
vaultConfig.writeEntry(CFG_OFFLINEONLY, data->isOfflineOnly);
KConfigGroup vaultConfig(config, device.data());
vaultConfig.writeEntry(CFG_LAST_STATUS, (int)data->status);
vaultConfig.writeEntry(CFG_MOUNT_POINT, data->mountPoint.data());
vaultConfig.writeEntry(CFG_NAME, data->name);
vaultConfig.writeEntry(CFG_BACKEND, data->backend->name());
org::kde::KDirNotify::emitFilesAdded(
QUrl::fromLocalFile(data->mountPoint.data()));
vaultConfig.writeEntry(CFG_ACTIVITIES, data->activities);
vaultConfig.writeEntry(CFG_OFFLINEONLY, data->isOfflineOnly);
org::kde::KDirNotify::emitFilesAdded(
QUrl::fromLocalFile(data->mountPoint.data()));
}
} else {
emit q->isOpenedChanged(false);
......@@ -302,7 +315,9 @@ Vault::Vault(const Device &device, QObject *parent)
Vault::~Vault()
{
close();
if (d->isOpened()) {
close();
}
}
......@@ -470,17 +485,17 @@ FutureResult<> Vault::forceClose()
FutureResult<> Vault::destroy(const Payload &payload)
FutureResult<> Vault::dismantle(const Payload &payload)
{
return
// We can not mount something that has not been registered
// with us before
!d->data ? errorResult(Error::BackendError,
i18n("The vault is unknown, cannot destroy it.")) :
i18n("The vault is unknown, cannot dismantle it.")) :
// otherwise
d->followFuture(VaultInfo::Destroying,
d->data->backend->destroy(d->device, d->data->mountPoint, payload));
d->followFuture(VaultInfo::Dismantling,
d->data->backend->dismantle(d->device, d->data->mountPoint, payload));
}
......@@ -634,7 +649,7 @@ bool Vault::isBusy() const
case VaultInfo::Creating:
case VaultInfo::Opening:
case VaultInfo::Closing:
case VaultInfo::Destroying:
case VaultInfo::Dismantling:
return true;
default:
......
......@@ -82,7 +82,7 @@ public:
// FutureResult<> configure();
FutureResult<> forceClose();
FutureResult<> destroy(const Payload &payload);
FutureResult<> dismantle(const Payload &payload);
VaultInfo info() const;
......
......@@ -201,20 +201,40 @@ void PlasmaVaultService::registerVault(Vault *vault)
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 = qobject_cast<Vault*>(sender());
if (status == VaultInfo::Opened) {
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()) {
......@@ -379,5 +399,29 @@ void PlasmaVaultService::forceCloseAllVaults()
}
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"
......@@ -53,6 +53,8 @@ public Q_SLOTS:
Q_SCRIPTABLE void closeAllVaults();
Q_SCRIPTABLE void forceCloseAllVaults();
Q_SCRIPTABLE void deleteVault(const QString &device, const QString &name);
Q_SIGNALS:
void registered();
......@@ -66,6 +68,7 @@ private Q_SLOTS:
void slotRegistered(const QDBusObjectPath &path);
void registerVault(PlasmaVault::Vault *vault);
void forgetVault(PlasmaVault::Vault *vault);
void onVaultStatusChanged(PlasmaVault::VaultInfo::Status status);
void onVaultMessageChanged(const QString &message);
......
......@@ -97,8 +97,6 @@ CompoundDialogModule::CompoundDialogModule(const step &children)
auto layout = new QVBoxLayout(this);
setLayout(layout);
bool valid = true;
for (const auto& childFactory: children) {
auto child = childFactory();
child->setParent(this);
......@@ -106,12 +104,28 @@ CompoundDialogModule::CompoundDialogModule(const step &children)
QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred));
m_children << child;
valid &= child->isValid();
if (!child->isValid()) {
m_invalidChildren << child;
}
connect(child, &DialogModule::isValidChanged,
this, [this, child] (bool valid) {
if (valid) {
m_invalidChildren.remove(child);
} else {
m_invalidChildren << child;
}
setIsValid(m_invalidChildren.isEmpty());
});
connect(child, &DialogModule::requestCancellation,
this, &DialogModule::requestCancellation);
layout->addWidget(child);
}
setIsValid(valid);
setIsValid(m_invalidChildren.isEmpty());
auto spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding,
QSizePolicy::Expanding);
......
......@@ -75,6 +75,7 @@ public:
Q_SIGNALS:
void isValidChanged(bool valid);
void requestCancellation();
private:
bool m_isValid;
......@@ -121,6 +122,7 @@ public:
private:
QVector<DialogModule*> m_children;
QSet<DialogModule*> m_invalidChildren;
};
......
......@@ -96,6 +96,8 @@ void DirectoryChooserWidget::init(
const auto mountPoint = payload[KEY_MOUNT_POINT].toString();
d->ui.editMountPoint->setText(mountPoint);
d->setMountPointValid(d->isDirectoryValid(d->ui.editMountPoint->url()));
}
......
......@@ -40,6 +40,11 @@ NameChooserWidget::NameChooserWidget()
: DialogDsl::DialogModule(false), d(new Private(this))
{
d->ui.setupUi(this);
connect(d->ui.editVaultName, &QLineEdit::textChanged,
this, [this] (const QString &text) {
setIsValid(!d->ui.editVaultName->text().isEmpty());
});
}
......@@ -65,6 +70,7 @@ void NameChooserWidget::init(
const auto name = payload[KEY_NAME].toString();
d->ui.editVaultName->setText(name);
setIsValid(!d->ui.editVaultName->text().isEmpty());
}
......
......@@ -41,6 +41,7 @@ using namespace DialogDsl::operators;
#include "namechooserwidget.h"
#include "passwordchooserwidget.h"
#include "offlineonlywidget.h"
#include "vaultdeletionwidget.h"
using PlasmaVault::Vault;
......@@ -54,6 +55,7 @@ public:
steps currentSteps;
QVector<DialogDsl::DialogModule*> currentModuleDialogs;
QSet<DialogDsl::DialogModule*> invalidModules;
steps defaultSteps
{
......@@ -65,18 +67,11 @@ public:
i18n("Advanced") / step {
activitiesChooser(),
offlineOnlyChooser()
}
},
/*
i18n("Dismantle") / step {
notice(
"dismantle-message",
i18n("Note that Plasma Vault will not delete any of the files,\n\