File indexing completed on 2024-05-05 17:43:12

0001 /*
0002  *   SPDX-FileCopyrightText: 2017, 2018, 2019 Ivan Cukic <ivan.cukic (at) kde.org>
0003  *
0004  *   SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  */
0006 
0007 #include "vault.h"
0008 
0009 #include <QDir>
0010 #include <QFutureWatcher>
0011 #include <QDBusMetaType>
0012 #include <QMessageBox>
0013 #include <QUrl>
0014 #include <QPointer>
0015 
0016 #include <KConfig>
0017 #include <KConfigGroup>
0018 #include <KSharedConfig>
0019 #include <QRegularExpression>
0020 
0021 #include <processcore/process.h>
0022 #include <processcore/processes.h>
0023 
0024 #include <KLocalizedString>
0025 #include <kdirnotify.h>
0026 
0027 #include "backend_p.h"
0028 
0029 #include "asynqt/basic/all.h"
0030 #include "asynqt/wrappers/process.h"
0031 #include "asynqt/operations/listen.h"
0032 #include "asynqt/operations/cast.h"
0033 
0034 #include <signal.h>
0035 
0036 #define CFG_NAME "name"
0037 #define CFG_LAST_STATUS "lastStatus"
0038 #define CFG_LAST_ERROR "lastError"
0039 #define CFG_MOUNT_POINT "mountPoint"
0040 #define CFG_BACKEND "backend"
0041 #define CFG_ACTIVITIES "activities"
0042 #define CFG_OFFLINEONLY "offlineOnly"
0043 
0044 namespace PlasmaVault {
0045 
0046 class Vault::Private {
0047 public:
0048     Vault * const q;
0049 
0050     KSharedConfigPtr config;
0051     Device device;
0052 
0053     FILE* deviceDirectoryLock = nullptr;
0054 
0055     void lockDeviceDirectory()
0056     {
0057         if (!deviceDirectoryLock) {
0058             deviceDirectoryLock = fopen(device.data().toLocal8Bit().data(), "r");
0059         }
0060     }
0061 
0062     void unlockDeviceDirectory()
0063     {
0064         if (deviceDirectoryLock) {
0065             fclose(deviceDirectoryLock);
0066             deviceDirectoryLock = nullptr;
0067         }
0068     }
0069 
0070     QTimer savingDelay;
0071 
0072 
0073     enum DeletionState {
0074         Normal,
0075         DeletionBlocked,
0076         DeletionScheduled,
0077     };
0078     DeletionState deletionState = Normal;
0079 
0080 
0081     struct Data {
0082         QString name;
0083         MountPoint mountPoint;
0084 
0085         VaultInfo::Status status;
0086         QString message;
0087 
0088         QStringList activities;
0089         bool isOfflineOnly;
0090 
0091         QString backendName;
0092         Backend::Ptr backend;
0093     };
0094     using ExpectedData = AsynQt::Expected<Data, PlasmaVault::Error>;
0095     ExpectedData data;
0096 
0097 
0098 
0099     void updateMessage(const QString &message)
0100     {
0101         if (!data) return;
0102 
0103         data->message = message;
0104         Q_EMIT q->messageChanged(message);
0105     }
0106 
0107 
0108     void writeConfiguration()
0109     {
0110         if (data) {
0111 
0112             const auto deviceStr = device.data();
0113             const auto mountPointStr = data->mountPoint.data();
0114 
0115             Q_ASSERT(!deviceStr.isEmpty() && !mountPointStr.isEmpty());
0116 
0117             // Saving the data for the current mount
0118             KConfigGroup generalConfig(config, "EncryptedDevices");
0119             generalConfig.writeEntry(deviceStr, true);
0120 
0121             KConfigGroup vaultConfig(config, deviceStr);
0122             vaultConfig.writeEntry(CFG_LAST_STATUS, (int)data->status);
0123             vaultConfig.writeEntry(CFG_MOUNT_POINT, mountPointStr);
0124             vaultConfig.writeEntry(CFG_NAME,        data->name);
0125             vaultConfig.writeEntry(CFG_BACKEND,     data->backend->name());
0126 
0127             vaultConfig.writeEntry(CFG_ACTIVITIES,  data->activities);
0128             vaultConfig.writeEntry(CFG_OFFLINEONLY, data->isOfflineOnly);
0129 
0130         } else {
0131 
0132             KConfigGroup generalConfig(config, "EncryptedDevices");
0133             generalConfig.writeEntry(device.data(), false);
0134 
0135             KConfigGroup vaultConfig(config, device.data());
0136             vaultConfig.writeEntry(CFG_LAST_STATUS, (int)VaultInfo::Error);
0137             vaultConfig.writeEntry(CFG_LAST_ERROR,
0138                     QString(data.error().message() + QStringLiteral(" (code: ") +
0139                     QString::number(data.error().code()) + QStringLiteral(")")));
0140             // vaultConfig.deleteEntry(CFG_MOUNT_POINT);
0141             // vaultConfig.deleteEntry(CFG_NAME);
0142             // vaultConfig.deleteEntry(CFG_BACKEND);
0143             // vaultConfig.deleteEntry(CFG_ACTIVITIES);
0144             // vaultConfig.deleteEntry(CFG_OFFLINEONLY);
0145 
0146         }
0147 
0148         config->sync();
0149     }
0150 
0151 
0152     void updateStatus()
0153     {
0154         if (data) {
0155             // Checking the status, and whether we should update it
0156             const auto oldStatus = data->status;
0157 
0158             if (oldStatus == VaultInfo::Dismantling) {
0159                 // This means that the vault should be forgotten
0160                 KConfigGroup generalConfig(config, "EncryptedDevices");
0161                 generalConfig.deleteEntry(device.data());
0162 
0163                 KConfigGroup vaultConfig(config, device.data());
0164                 vaultConfig.deleteGroup();
0165 
0166                 Q_EMIT q->statusChanged(data->status = VaultInfo::Dismantled);
0167 
0168             } else {
0169                 QDir deviceDir(device.data());
0170 
0171                 const auto newStatus =
0172                                !deviceDir.exists() ? VaultInfo::DeviceMissing :
0173                                isOpened()          ? VaultInfo::Opened :
0174                                isInitialized()     ? VaultInfo::Closed :
0175                                                      VaultInfo::NotInitialized;
0176 
0177                 if (oldStatus == newStatus) return;
0178 
0179                 data->status = newStatus;
0180 
0181                 Q_EMIT q->statusChanged(data->status);
0182 
0183                 if (newStatus == VaultInfo::Closed //
0184                         || newStatus == VaultInfo::Opened) {
0185                     Q_EMIT q->isOpenedChanged(newStatus == VaultInfo::Opened);
0186                 }
0187 
0188                 if (oldStatus == VaultInfo::NotInitialized //
0189                         || newStatus == VaultInfo::NotInitialized) {
0190                     Q_EMIT q->isInitializedChanged(newStatus);
0191                 }
0192 
0193                 if (oldStatus == VaultInfo::Creating //
0194                         || oldStatus == VaultInfo::Opening //
0195                         || oldStatus == VaultInfo::Closing //
0196                         || oldStatus == VaultInfo::Dismantling) {
0197                     Q_EMIT q->isBusyChanged(false);
0198                 }
0199 
0200                 writeConfiguration();
0201 
0202                 org::kde::KDirNotify::emitFilesAdded(
0203                         QUrl::fromLocalFile(data->mountPoint.data()));
0204             }
0205 
0206         } else {
0207             Q_EMIT q->isOpenedChanged(false);
0208             Q_EMIT q->isInitializedChanged(false);
0209             Q_EMIT q->isBusyChanged(false);
0210 
0211             writeConfiguration();
0212 
0213             Q_EMIT q->statusChanged(VaultInfo::Error);
0214         }
0215 
0216         if (data && data->status == VaultInfo::Opened) {
0217             lockDeviceDirectory();
0218         } else {
0219             unlockDeviceDirectory();
0220         }
0221     }
0222 
0223 
0224 
0225     ExpectedData errorData(Error::Code error, const QString &message) const
0226     {
0227         qWarning() << "error: " << message;
0228         return ExpectedData::error(error, message);
0229     }
0230 
0231 
0232 
0233     ExpectedData loadVault(const Device &device,
0234                            const QString &name = QString(),
0235                            const MountPoint &mountPoint = MountPoint(),
0236                            const Payload &payload = Payload()) const
0237     {
0238         if (!config->hasGroup(device.data())) {
0239             return errorData(Error::DeviceError, i18n("Unknown device"));
0240         }
0241 
0242         Data vaultData;
0243         const QString backendName    = payload[KEY_BACKEND].toString();
0244         const QStringList activities = payload[KEY_ACTIVITIES].toStringList();
0245         const bool isOfflineOnly     = payload[KEY_OFFLINEONLY].toBool();
0246 
0247         // status should never be in this state, if we got an error,
0248         // d->data should not be valid
0249         vaultData.status = VaultInfo::Error;
0250 
0251         // Reading the mount data from the config
0252         KConfigGroup vaultConfig(config, device.data());
0253         vaultData.name          = vaultConfig.readEntry(CFG_NAME, name);
0254         vaultData.backendName   = vaultConfig.readEntry(CFG_BACKEND, backendName);
0255         vaultData.activities    = vaultConfig.readEntry(CFG_ACTIVITIES, activities);
0256         vaultData.isOfflineOnly = vaultConfig.readEntry(CFG_OFFLINEONLY, isOfflineOnly);
0257 
0258         const QString configuredMountPoint = vaultConfig.readEntry(CFG_MOUNT_POINT, mountPoint.data());
0259         vaultData.mountPoint = MountPoint(configuredMountPoint);
0260         const QString actualMountPoint = vaultData.mountPoint.data();
0261         vaultConfig.writeEntry(CFG_MOUNT_POINT, actualMountPoint);
0262 
0263         const QDir mountPointDir(vaultData.mountPoint.data());
0264 
0265         return
0266             // If the backend is not known, we need to fail
0267             !Backend::availableBackends().contains(vaultData.backendName) ?
0268                 errorData(Error::BackendError,
0269                           i18n("Configured backend does not exist: %1", vaultData.backendName)) :
0270 
0271             // If the mount point is empty, we can not do anything
0272             vaultData.mountPoint.isEmpty() ?
0273                 errorData(Error::MountPointError,
0274                           i18n("Mount point is not specified")) :
0275 
0276             // Lets try to create the mount point
0277             !mountPointDir.exists() && !QDir().mkpath(vaultData.mountPoint.data()) ?
0278                 errorData(Error::MountPointError,
0279                           i18n("Cannot create the mount point")) :
0280 
0281             // Instantiate the backend if possible
0282             !(vaultData.backend = Backend::instance(vaultData.backendName)) ?
0283                 errorData(Error::BackendError,
0284                           i18n("Configured backend cannot be instantiated: %1", vaultData.backendName)) :
0285 
0286             // otherwise
0287             ExpectedData::success(vaultData);
0288     }
0289 
0290 
0291 
0292     Private(Vault *parent, const Device &device)
0293         : q(parent)
0294         , config(KSharedConfig::openConfig(PLASMAVAULT_CONFIG_FILE))
0295         , device(device)
0296         , data(loadVault(device))
0297     {
0298         updateStatus();
0299     }
0300 
0301 
0302 
0303     ~Private()
0304     {
0305         unlockDeviceDirectory();
0306     }
0307 
0308 
0309 
0310     template <typename T>
0311     T followFuture(VaultInfo::Status whileNotFinished, const T &future)
0312     {
0313         using namespace AsynQt::operators;
0314 
0315         Q_EMIT q->isBusyChanged(true);
0316         data->status = whileNotFinished;
0317 
0318         deletionState = DeletionBlocked;
0319 
0320         return future | onSuccess([this] {
0321                 updateStatus();
0322 
0323                 if (deletionState == DeletionScheduled) {
0324                     q->deleteLater();
0325                 }
0326                 deletionState = Normal;
0327             });
0328     }
0329 
0330 
0331 
0332     bool isInitialized() const
0333     {
0334         return data && data->backend->isInitialized(device);
0335     }
0336 
0337 
0338 
0339     bool isOpened() const
0340     {
0341         return data && data->backend->isOpened(data->mountPoint);
0342     }
0343 };
0344 
0345 
0346 
0347 Vault::Vault(const Device &device, QObject *parent)
0348     : QObject(parent)
0349     , d(new Private(this, device))
0350 {
0351     d->savingDelay.setInterval(300);
0352     d->savingDelay.setSingleShot(true);
0353     connect(&d->savingDelay, &QTimer::timeout,
0354             this, [&] {
0355                 d->writeConfiguration();
0356                 Q_EMIT infoChanged();
0357             });
0358 }
0359 
0360 
0361 
0362 Vault::~Vault()
0363 {
0364     if (d->isOpened()) {
0365         close();
0366     }
0367 }
0368 
0369 
0370 
0371 void Vault::scheduleDeletion()
0372 {
0373     if (d->deletionState == Private::Normal) {
0374         deleteLater();
0375     } else {
0376         d->deletionState = Private::DeletionScheduled;
0377     }
0378 }
0379 
0380 
0381 
0382 void Vault::saveConfiguration()
0383 {
0384     d->savingDelay.start();
0385 }
0386 
0387 
0388 
0389 FutureResult<> Vault::create(const QString &name, const MountPoint &mountPoint,
0390                              const Payload &payload)
0391 {
0392     using namespace AsynQt::operators;
0393 
0394     return
0395         // If the backend is already known, and the device is initialized,
0396         // we do not want to do it again
0397         d->data && d->data->backend->isInitialized(d->device) ?
0398             errorResult(Error::DeviceError,
0399                         i18n("This device is already registered. Cannot recreate it.")) :
0400 
0401         // Mount not open, check the error messages
0402         !(d->data = d->loadVault(d->device, name, mountPoint, payload)) ?
0403             errorResult(Error::BackendError,
0404                         i18n("Unknown error; unable to create the backend.")) :
0405 
0406         // otherwise
0407         d->followFuture(VaultInfo::Creating,
0408                         d->data->backend->initialize(name, d->device, mountPoint, payload))
0409             | onSuccess([mountPoint] {
0410                 // If we have successfully created the vault,
0411                 // lets try to set its icon
0412                 QFile dotDir(mountPoint.data() + QStringLiteral("/.directory"));
0413 
0414                 if (dotDir.open(QIODevice::WriteOnly | QIODevice::Text)) {
0415                     QTextStream out(&dotDir);
0416                     out << "[Desktop Entry]\nIcon=folder-decrypted\n";
0417                 }
0418             });
0419 }
0420 
0421 
0422 
0423 FutureResult<> Vault::import(const QString &name, const MountPoint &mountPoint,
0424                              const Payload &payload)
0425 {
0426     using namespace AsynQt::operators;
0427 
0428     return
0429         // If the backend is already known, and the device is initialized,
0430         // we do not want to do it again
0431         d->data && (!d->data->backend->isInitialized(d->device)) ?
0432             errorResult(Error::DeviceError,
0433                         i18n("This device is not initialized. Cannot import it.")) :
0434 
0435         // Mount not open, check the error messages
0436         !(d->data = d->loadVault(d->device, name, mountPoint, payload)) ?
0437             errorResult(Error::BackendError,
0438                         i18n("Unknown error; unable to create the backend.")) :
0439 
0440         // otherwise
0441         d->followFuture(VaultInfo::Creating,
0442                         d->data->backend->import(name, d->device, mountPoint, payload))
0443             | onSuccess([mountPoint] {
0444                 // If we have successfully created the vault,
0445                 // lets try to set its icon
0446                 QFile dotDir(mountPoint.data() + QStringLiteral("/.directory"));
0447 
0448                 if (dotDir.open(QIODevice::WriteOnly | QIODevice::Text)) {
0449                     QTextStream out(&dotDir);
0450                     out << "[Desktop Entry]\nIcon=folder-decrypted\n";
0451                 }
0452             });
0453 }
0454 
0455 
0456 
0457 
0458 FutureResult<> Vault::open(const Payload &payload)
0459 {
0460     return
0461         // We can not mount something that has not been registered
0462         // with us before
0463         !d->data ? errorResult(Error::BackendError,
0464                                i18n("Cannot open an unknown vault.")) :
0465 
0466         // otherwise
0467         d->followFuture(VaultInfo::Opening,
0468                         d->data->backend->open(d->device, d->data->mountPoint, payload));
0469 }
0470 
0471 
0472 
0473 FutureResult<> Vault::close()
0474 {
0475     using namespace AsynQt::operators;
0476 
0477     return
0478         // We can not mount something that has not been registered
0479         // with us before
0480         !d->data ? errorResult(Error::BackendError,
0481                                i18n("The vault is unknown; cannot close it.")) :
0482 
0483         // otherwise
0484         d->followFuture(VaultInfo::Closing,
0485                         d->data->backend->close(d->device, d->data->mountPoint))
0486             | onSuccess([this] (const Result<> &result) {
0487                 if (!isOpened() || result) {
0488                     d->updateMessage(QString());
0489 
0490                 } else {
0491                     // We want to check whether there is an application
0492                     // that is accessing the vault
0493                     AsynQt::Process::getOutput(QStringLiteral("lsof"), { QStringLiteral("-t"), mountPoint().data() })
0494                         | cast<QString>()
0495                         | onError([this] {
0496                             d->updateMessage(i18n("Unable to close the vault because an application is using it"));
0497                         })
0498                         | onSuccess([this] (const QString &result) {
0499                             // based on ksolidnotify.cpp
0500                             QStringList blockApps;
0501 
0502                             const auto &pidList = result.split(QRegularExpression(QStringLiteral("\\s+")), Qt::SkipEmptyParts);
0503 
0504                             if (pidList.isEmpty()) {
0505                                 d->updateMessage(i18n("Unable to close the vault because an application is using it"));
0506                                 close();
0507 
0508                             } else {
0509                                 KSysGuard::Processes procs;
0510 
0511                                 for (const QString &pidStr: pidList) {
0512                                     int pid = pidStr.toInt();
0513                                     if (!pid) {
0514                                         continue;
0515                                     }
0516 
0517                                     procs.updateOrAddProcess(pid);
0518 
0519                                     KSysGuard::Process *proc = procs.getProcess(pid);
0520 
0521                                     if (!blockApps.contains(proc->name())) {
0522                                         blockApps << proc->name();
0523                                     }
0524                                 }
0525 
0526                                 blockApps.removeDuplicates();
0527 
0528                                 d->updateMessage(i18n("Unable to close the vault because it is being used by %1", blockApps.join(QStringLiteral(", "))));
0529                             }
0530                         });
0531                     }
0532                 });
0533 }
0534 
0535 
0536 
0537 // FutureResult<> Vault::configure()
0538 // {
0539 //     return close();
0540 // }
0541 
0542 
0543 
0544 FutureResult<> Vault::forceClose()
0545 {
0546     using namespace AsynQt::operators;
0547 
0548     AsynQt::await(
0549         AsynQt::Process::getOutput(QStringLiteral("lsof"), { QStringLiteral("-t"), mountPoint().data() })
0550             | cast<QString>()
0551             | onError([this] {
0552                 d->updateMessage(i18n("Failed to fetch the list of applications using this vault"));
0553             })
0554             | onSuccess([] (const QString &result) {
0555                 // based on ksolidnotify.cpp
0556 
0557                 const auto &pidList = result.split(QRegularExpression(QStringLiteral("\\s+")), Qt::SkipEmptyParts);
0558 
0559                 KSysGuard::Processes procs;
0560 
0561                 for (const QString &pidStr: pidList) {
0562                     int pid = pidStr.toInt();
0563                     if (!pid) {
0564                         continue;
0565                     }
0566 
0567                     procs.sendSignal(pid, SIGKILL);
0568                 }
0569             }));
0570 
0571     return close();
0572 }
0573 
0574 
0575 
0576 FutureResult<> Vault::dismantle(const Payload &payload)
0577 {
0578     const auto resolvedPath = [] (const QString& path) {
0579         auto result = QDir(path).canonicalPath();
0580         if (!result.endsWith(QLatin1Char('/'))) {
0581             result += QLatin1Char('/');
0582         }
0583         return result;
0584     };
0585 
0586     const auto resolvedDevice = resolvedPath(d->device.data());
0587     const auto resolvedMount  = resolvedPath(d->data->mountPoint.data());
0588 
0589     const auto devices = availableDevices();
0590     const int matches = std::count_if(devices.cbegin(), devices.cend(),
0591           [&] (const Device& device) {
0592               auto thisResolvedDevice = resolvedPath(device.data());
0593 
0594               auto diff = std::mismatch(
0595                     resolvedDevice.cbegin(), resolvedDevice.cend(),
0596                     thisResolvedDevice.cbegin(), thisResolvedDevice.cend());
0597 
0598               return diff.first == resolvedDevice.cend() ||
0599                      diff.second == thisResolvedDevice.cend();
0600           });
0601 
0602     return
0603         matches != 1 ? errorResult(Error::BackendError,
0604                                    i18n("Cannot delete the vault; there are other vaults with overlapping paths.")):
0605 
0606         // We can not mount something that has not been registered
0607         // with us before
0608         !d->data ? errorResult(Error::BackendError,
0609                                i18n("The vault is unknown; cannot dismantle it.")) :
0610 
0611         // Let's confirm with the user once more
0612         QMessageBox::question(nullptr, i18n("Are you sure you want to delete this vault"),
0613                                        i18n("This operation will irreversibly delete the following:\n%1\n%2",
0614                                             d->device.data(), d->data->mountPoint.data()), QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes ?
0615                               errorResult(Error::OperationCancelled, i18n("Delete operation cancelled")) :
0616 
0617         // otherwise
0618         d->followFuture(VaultInfo::Dismantling,
0619                         d->data->backend->dismantle(d->device, d->data->mountPoint, payload));
0620 }
0621 
0622 
0623 
0624 VaultInfo::Status Vault::status() const
0625 {
0626     return d->data->status;
0627 }
0628 
0629 
0630 
0631 bool Vault::isValid() const
0632 {
0633     return d->data;
0634 }
0635 
0636 
0637 
0638 Device Vault::device() const
0639 {
0640     return d->device;
0641 }
0642 
0643 
0644 
0645 QList<Device> Vault::availableDevices()
0646 {
0647     const auto config = KSharedConfig::openConfig(PLASMAVAULT_CONFIG_FILE);
0648     const KConfigGroup general(config, "EncryptedDevices");
0649 
0650     QList<Device> results;
0651     for (const auto& item: general.keyList()) {
0652         results << Device(item);
0653     }
0654     return results;
0655 }
0656 
0657 
0658 
0659 QStringList Vault::statusMessage()
0660 {
0661     for (const auto& backendName: Backend::availableBackends()) {
0662         auto backend = Backend::instance(backendName);
0663         backend->validateBackend();
0664     }
0665 
0666     return {};
0667 }
0668 
0669 
0670 
0671 QString Vault::message() const
0672 {
0673     if (!d->data) {
0674         return d->data.error().message();
0675     } else {
0676         return d->data->message;
0677     }
0678 }
0679 
0680 
0681 
0682 bool Vault::isInitialized() const
0683 {
0684     return d->isInitialized();
0685 }
0686 
0687 
0688 
0689 bool Vault::isOpened() const
0690 {
0691     return d->isOpened();
0692 }
0693 
0694 
0695 
0696 MountPoint Vault::mountPoint() const
0697 {
0698     return d->data->mountPoint;
0699 }
0700 
0701 void Vault::setMountPoint(const MountPoint &mountPoint)
0702 {
0703     if (d->data->mountPoint.data() != mountPoint.data()) {
0704         QDir().rmpath(d->data->mountPoint.data());
0705         QDir().mkpath(mountPoint.data());
0706 
0707         d->data->mountPoint = mountPoint;
0708         saveConfiguration();
0709     }
0710 }
0711 
0712 
0713 
0714 QStringList Vault::activities() const
0715 {
0716     return d->data->activities;
0717 }
0718 
0719 void Vault::setActivities(const QStringList &activities)
0720 {
0721     d->data->activities = activities;
0722     Q_EMIT activitiesChanged(activities);
0723     saveConfiguration();
0724 }
0725 
0726 
0727 
0728 bool Vault::isOfflineOnly() const
0729 {
0730     return d->data->isOfflineOnly;
0731 }
0732 
0733 void Vault::setIsOfflineOnly(bool isOfflineOnly)
0734 {
0735     d->data->isOfflineOnly = isOfflineOnly;
0736     Q_EMIT isOfflineOnlyChanged(isOfflineOnly);
0737     saveConfiguration();
0738 }
0739 
0740 
0741 
0742 QString Vault::name() const
0743 {
0744     return d->data->name;
0745 }
0746 
0747 void Vault::setName(const QString &name)
0748 {
0749     d->data->name = name;
0750     Q_EMIT nameChanged(name);
0751     saveConfiguration();
0752 }
0753 
0754 
0755 
0756 QString Vault::backend() const
0757 {
0758     return d->data->backendName;
0759 }
0760 
0761 
0762 
0763 bool Vault::isBusy() const
0764 {
0765     if (!d->data) {
0766         return false;
0767     }
0768 
0769     switch (status()) {
0770         case VaultInfo::Creating:
0771         case VaultInfo::Opening:
0772         case VaultInfo::Closing:
0773         case VaultInfo::Dismantling:
0774             return true;
0775 
0776         default:
0777             return false;
0778     }
0779 }
0780 
0781 
0782 
0783 VaultInfo Vault::info() const
0784 {
0785     VaultInfo vaultInfo;
0786 
0787     vaultInfo.device        = device().data();
0788     vaultInfo.name          = name();
0789 
0790     vaultInfo.status        = status();
0791     vaultInfo.message       = message();
0792 
0793     vaultInfo.activities    = activities();
0794     vaultInfo.isOfflineOnly = isOfflineOnly();
0795 
0796     return vaultInfo;
0797 }
0798 
0799 
0800 
0801 void Vault::updateStatus()
0802 {
0803     d->updateStatus();
0804 }
0805 
0806 
0807 } // namespace PlasmaVault
0808 
0809