File indexing completed on 2024-04-21 16:30:25

0001 // SPDX-FileCopyrightText: 2020 Simon Persson <simon.persson@mykolab.com>
0002 //
0003 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 
0005 #include "planexecutor.h"
0006 #include "bupjob.h"
0007 #include "bupverificationjob.h"
0008 #include "buprepairjob.h"
0009 #include "kupdaemon.h"
0010 #include "kupdaemon_debug.h"
0011 #include "rsyncjob.h"
0012 
0013 #include <KIO/DirectorySizeJob>
0014 #include <KIO/OpenUrlJob>
0015 #include <KFormat>
0016 #include <KLocalizedString>
0017 #include <KNotification>
0018 #include <QDBusConnection>
0019 #include <QDBusReply>
0020 #include <QDir>
0021 #include <QTimer>
0022 #include <QStorageInfo>
0023 
0024 
0025 static const QString cPwrMgmtServiceName = QStringLiteral("org.freedesktop.PowerManagement");
0026 static const QString cPwrMgmtPath = QStringLiteral("/org/freedesktop/PowerManagement");
0027 static const QString cPwrMgmtInhibitInterface = QStringLiteral("org.freedesktop.PowerManagement.Inhibit");
0028 static const QString cPwrMgmtInterface = QStringLiteral("org.freedesktop.PowerManagement");
0029 
0030 PlanExecutor::PlanExecutor(BackupPlan *pPlan, KupDaemon *pKupDaemon)
0031    :QObject(pKupDaemon), mState(NOT_AVAILABLE), mPlan(pPlan), mQuestion(nullptr),
0032      mFailNotification(nullptr), mIntegrityNotification(nullptr), mRepairNotification(nullptr),
0033      mLastState(NOT_AVAILABLE), mKupDaemon(pKupDaemon), mSleepCookie(0)
0034 {
0035     QString lCachePath = QString::fromLocal8Bit(qgetenv("XDG_CACHE_HOME").constData());
0036     if(lCachePath.isEmpty()) {
0037         lCachePath = QDir::homePath();
0038         lCachePath.append(QStringLiteral("/.cache"));
0039     }
0040     lCachePath.append(QStringLiteral("/kup"));
0041     QDir lCacheDir(lCachePath);
0042     if(!lCacheDir.exists()) {
0043         if(!lCacheDir.mkpath(lCachePath)) {
0044             lCachePath = QStringLiteral("/tmp");
0045         }
0046     }
0047     mLogFilePath = lCachePath;
0048     mLogFilePath.append(QStringLiteral("/kup_plan"));
0049     mLogFilePath.append(QString::number(mPlan->planNumber()));
0050     mLogFilePath.append(QStringLiteral(".log"));
0051 
0052     mSchedulingTimer = new QTimer(this);
0053     mSchedulingTimer->setSingleShot(true);
0054     connect(mSchedulingTimer, SIGNAL(timeout()), SLOT(enterAvailableState()));
0055 }
0056 
0057 PlanExecutor::~PlanExecutor() = default;
0058 
0059 QString PlanExecutor::currentActivityTitle() {
0060     switch(mState) {
0061     case BACKUP_RUNNING:
0062         return i18nc("status in tooltip", "Saving backup");
0063     case INTEGRITY_TESTING:
0064         return i18nc("status in tooltip", "Checking backup integrity");
0065     case REPAIRING:
0066         return i18nc("status in tooltip", "Repairing backups");
0067     default:;
0068     }
0069 
0070     switch (mPlan->backupStatus()) {
0071     case BackupPlan::GOOD:
0072         return i18nc("status in tooltip", "Backup status OK");
0073     case BackupPlan::MEDIUM:
0074         return i18nc("status in tooltip", "New backup suggested");
0075     case BackupPlan::BAD:
0076         return i18nc("status in tooltip", "New backup needed");
0077     default:;
0078     }
0079     return QString();
0080 }
0081 
0082 // dispatcher code for entering one of the available states
0083 void PlanExecutor::enterAvailableState() {
0084     if(mState == NOT_AVAILABLE) {
0085         mState = WAITING_FOR_FIRST_BACKUP; //initial child state of "Available" state
0086         emit stateChanged();
0087     }
0088     QDateTime lNow = QDateTime::currentDateTimeUtc();
0089     switch(mPlan->mScheduleType) {
0090     case BackupPlan::MANUAL:
0091         break;
0092     case BackupPlan::INTERVAL: {
0093         QDateTime lNextTime = mPlan->nextScheduledTime();
0094         if(!lNextTime.isValid() || lNextTime < lNow) {
0095             if(!mPlan->mLastCompleteBackup.isValid())
0096                 askUserOrStart(xi18nc("@info", "Do you want to save a first backup now?"));
0097             else {
0098                 QString t = KFormat().formatSpelloutDuration(static_cast<quint64>(mPlan->mLastCompleteBackup.secsTo(lNow)) * 1000);
0099                 askUserOrStart(xi18nc("@info", "It has been %1 since last backup was saved.\n"
0100                                                "Save a new backup now?", t));
0101             }
0102         } else {
0103             // Call this method again in five minutes to check if it's time.
0104             // The alternative of sleeping all the way to when backup saving is due
0105             // has the problem that time spent suspended is not counted.
0106             mSchedulingTimer->start(5*60*1000);
0107         }
0108         break;
0109     }
0110     case BackupPlan::USAGE:
0111         if(!mPlan->mLastCompleteBackup.isValid()) {
0112             askUserOrStart(xi18nc("@info", "Do you want to save a first backup now?"));
0113         } else if(mPlan->mAccumulatedUsageTime > static_cast<quint32>(mPlan->mUsageLimit) * 3600) {
0114             QString t = KFormat().formatSpelloutDuration(mPlan->mAccumulatedUsageTime * 1000);
0115             askUserOrStart(xi18nc("@info", "You have been active for %1 since last backup was saved.\n"
0116                                            "Save a new backup now?", t));
0117         }
0118         break;
0119     }
0120 }
0121 
0122 void PlanExecutor::askUserOrStart(const QString& pUserQuestion) {
0123     // Only ask the first time after destination has become available.
0124     // Always ask if power saving is active.
0125     if( (mPlan->mAskBeforeTakingBackup && mState == WAITING_FOR_FIRST_BACKUP) ||
0126         powerSaveActive()) {
0127         askUser(pUserQuestion);
0128     } else {
0129         startBackupSaveJob();
0130     }
0131 }
0132 
0133 void PlanExecutor::enterNotAvailableState() {
0134     discardUserQuestion();
0135     mSchedulingTimer->stop();
0136     mState = NOT_AVAILABLE;
0137     emit stateChanged();
0138 }
0139 
0140 void PlanExecutor::askUser(const QString &pQuestion) {
0141     discardUserQuestion();
0142     mQuestion = new KNotification(QStringLiteral("StartBackup"), KNotification::Persistent);
0143     mQuestion->setTitle(mPlan->mDescription);
0144     mQuestion->setText(pQuestion);
0145 
0146 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0147     QStringList lAnswers;
0148     lAnswers << xi18nc("@action:button", "Yes") << xi18nc("@action:button", "No");
0149     mQuestion->setActions(lAnswers);
0150     connect(mQuestion, SIGNAL(action1Activated()), SLOT(startBackupSaveJob()));
0151     connect(mQuestion, SIGNAL(action2Activated()), SLOT(discardUserQuestion()));
0152 #else
0153     KNotificationAction *yes = mQuestion->addAction(xi18nc("@action:button", "Yes"));
0154     connect(yes, &KNotificationAction::activated, this, &PlanExecutor::startBackupSaveJob);
0155 
0156     KNotificationAction *no = mQuestion->addAction(xi18nc("@action:button", "No"));
0157     connect(no, &KNotificationAction::activated, this, &PlanExecutor::discardUserQuestion);
0158 #endif
0159     connect(mQuestion, SIGNAL(closed()), SLOT(discardUserQuestion()));
0160     connect(mQuestion, SIGNAL(ignored()), SLOT(discardUserQuestion()));
0161     // enter this "do nothing" state, if user answers "no" or ignores, remain there
0162     mState = WAITING_FOR_MANUAL_BACKUP;
0163     emit stateChanged();
0164     mQuestion->sendEvent();
0165 }
0166 
0167 void PlanExecutor::discardUserQuestion() {
0168     if(mQuestion) {
0169         mQuestion->deleteLater();
0170         mQuestion = nullptr;
0171     }
0172 }
0173 
0174 void PlanExecutor::notifyBackupFailed(KJob *pFailedJob) {
0175     discardFailNotification();
0176     mFailNotification = new KNotification(QStringLiteral("BackupFailed"), KNotification::Persistent);
0177     mFailNotification->setTitle(xi18nc("@title:window", "Saving of Backup Failed"));
0178     mFailNotification->setText(pFailedJob->errorText());
0179 
0180 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0181     QStringList lAnswers;
0182     if(pFailedJob->error() == BackupJob::ErrorWithLog) {
0183         lAnswers << xi18nc("@action:button", "Show log file");
0184         connect(mFailNotification, SIGNAL(action1Activated()), SLOT(showLog()));
0185     } else if(pFailedJob->error() == BackupJob::ErrorSuggestRepair) {
0186         lAnswers << xi18nc("@action:button", "Yes");
0187         lAnswers << xi18nc("@action:button", "No");
0188         connect(mFailNotification, SIGNAL(action1Activated()), SLOT(startRepairJob()));
0189     } else if(pFailedJob->error() == BackupJob::ErrorSourcesConfig) {
0190         lAnswers << xi18nc("@action:button", "Open settings");
0191         connect(mFailNotification, &KNotification::action1Activated, this, [this] {
0192             QProcess::startDetached(QStringLiteral("kcmshell5"), {QStringLiteral("--args"),
0193                                                                   QStringLiteral("show_sources %1").arg(mPlan->planNumber()),
0194                                                                   QStringLiteral("kcm_kup")});
0195         });
0196     }
0197     mFailNotification->setActions(lAnswers);
0198 
0199     connect(mFailNotification, SIGNAL(action2Activated()), SLOT(discardFailNotification()));
0200 #else
0201     if(pFailedJob->error() == BackupJob::ErrorWithLog) {
0202         KNotificationAction *showLogFile = mFailNotification->addAction(xi18nc("@action:button", "Show log file"));
0203         connect(showLogFile, &KNotificationAction::activated, this, &PlanExecutor::showLog);
0204     } else if(pFailedJob->error() == BackupJob::ErrorSuggestRepair) {
0205         KNotificationAction *yes = mFailNotification->addAction(xi18nc("@action:button", "Yes"));
0206         connect(yes, &KNotificationAction::activated, this, &PlanExecutor::startRepairJob);
0207 
0208         KNotificationAction *no = mFailNotification->addAction(xi18nc("@action:button", "No"));
0209         connect(no, &KNotificationAction::activated, this, &PlanExecutor::discardFailNotification);
0210     } else if(pFailedJob->error() == BackupJob::ErrorSourcesConfig) {
0211         KNotificationAction *openSettings = mFailNotification->addAction(xi18nc("@action:button", "Open settings"));
0212         connect(openSettings, &KNotificationAction::activated, this, [this] {
0213             QProcess::startDetached(QStringLiteral("kcmshell5"), {QStringLiteral("--args"),
0214                                                                   QStringLiteral("show_sources %1").arg(mPlan->planNumber()),
0215                                                                   QStringLiteral("kcm_kup")});
0216         });
0217     }
0218 #endif
0219     connect(mFailNotification, SIGNAL(closed()), SLOT(discardFailNotification()));
0220     connect(mFailNotification, SIGNAL(ignored()), SLOT(discardFailNotification()));
0221     mFailNotification->sendEvent();
0222 }
0223 
0224 void PlanExecutor::discardFailNotification() {
0225     if(mFailNotification) {
0226         mFailNotification->deleteLater();
0227         mFailNotification = nullptr;
0228     }
0229 }
0230 
0231 void PlanExecutor::notifyBackupSucceeded() {
0232     auto *lNotification = new KNotification(QStringLiteral("BackupSucceeded"));
0233     lNotification->setTitle(xi18nc("@title:window", "Backup Saved"));
0234     lNotification->setText(xi18nc("@info notification", "Saving backup completed successfully."));
0235     lNotification->sendEvent();
0236 }
0237 
0238 void PlanExecutor::showLog() {
0239     auto *job = new KIO::OpenUrlJob(QUrl::fromLocalFile(mLogFilePath), QStringLiteral("text/x-log"));
0240     job->start();
0241 }
0242 
0243 void PlanExecutor::startIntegrityCheck() {
0244     if(mPlan->mBackupType != BackupPlan::BupType || busy() || !destinationAvailable()) {
0245         return;
0246     }
0247     KJob *lJob = new BupVerificationJob(*mPlan, mDestinationPath, mLogFilePath, mKupDaemon);
0248     connect(lJob, SIGNAL(result(KJob*)), SLOT(integrityCheckFinished(KJob*)));
0249     lJob->start();
0250     mLastState = mState;
0251     mState = INTEGRITY_TESTING;
0252     emit stateChanged();
0253     startSleepInhibit();
0254 }
0255 
0256 void PlanExecutor::startRepairJob() {
0257     if(mPlan->mBackupType != BackupPlan::BupType || busy() || !destinationAvailable()) {
0258         return;
0259     }
0260     KJob *lJob = new BupRepairJob(*mPlan, mDestinationPath, mLogFilePath, mKupDaemon);
0261     connect(lJob, SIGNAL(result(KJob*)), SLOT(repairFinished(KJob*)));
0262     lJob->start();
0263     mLastState = mState;
0264     mState = REPAIRING;
0265     emit stateChanged();
0266     startSleepInhibit();
0267 }
0268 
0269 void PlanExecutor::startBackupSaveJob() {
0270     if(busy() || !destinationAvailable()) {
0271         return;
0272     }
0273     discardUserQuestion();
0274     mState = BACKUP_RUNNING;
0275     emit stateChanged();
0276     startSleepInhibit();
0277     startBackup();
0278 }
0279 
0280 void PlanExecutor::startBackup() {
0281     QFileInfo lInfo(mDestinationPath);
0282     if(!lInfo.isWritable()) {
0283         KNotification::event(KNotification::Error, xi18nc("@title:window", "Problem"),
0284                              xi18nc("notification", "You don't have write permission to backup destination."));
0285         exitBackupRunningState(false);
0286         return;
0287     }
0288     BackupJob *lJob = createBackupJob();
0289     if(lJob == nullptr) {
0290         KNotification::event(KNotification::Error, xi18nc("@title:window", "Problem"),
0291                              xi18nc("notification", "Invalid type of backup in configuration."));
0292         exitBackupRunningState(false);
0293         return;
0294     }
0295     connect(lJob, &KJob::result, this, &PlanExecutor::finishBackup);
0296     lJob->start();
0297 }
0298 
0299 void PlanExecutor::finishBackup(KJob *pJob) {
0300     if(pJob->error()) {
0301         if(pJob->error() != KJob::KilledJobError) {
0302             notifyBackupFailed(pJob);
0303         }
0304         exitBackupRunningState(false);
0305     } else {
0306         notifyBackupSucceeded();
0307         mPlan->mLastCompleteBackup = QDateTime::currentDateTimeUtc();
0308         QStorageInfo storageInfo(mDestinationPath);
0309         if(storageInfo.isValid())
0310             mPlan->mLastAvailableSpace = static_cast<double>(storageInfo.bytesAvailable());
0311         else
0312             mPlan->mLastAvailableSpace = -1.0; //unknown size
0313 
0314         auto lSizeJob = KIO::directorySize(QUrl::fromLocalFile(mDestinationPath));
0315         connect(lSizeJob, &KJob::result, this, &PlanExecutor::finishSizeCheck);
0316         lSizeJob->start();
0317     }
0318 }
0319 
0320 void PlanExecutor::finishSizeCheck(KJob* pJob) {
0321     if(pJob->error()) {
0322         KNotification::event(KNotification::Error, xi18nc("@title:window", "Problem"), pJob->errorText());
0323         mPlan->mLastBackupSize = -1.0; //unknown size
0324     } else {
0325         auto lSizeJob = qobject_cast<KIO::DirectorySizeJob *>(pJob);
0326         mPlan->mLastBackupSize = static_cast<double>(lSizeJob->totalSize());
0327     }
0328     mPlan->save();
0329     exitBackupRunningState(pJob->error() == 0);
0330 }
0331 
0332 void PlanExecutor::integrityCheckFinished(KJob *pJob) {
0333     endSleepInhibit();
0334     discardIntegrityNotification();
0335     mIntegrityNotification = new KNotification(QStringLiteral("IntegrityCheckCompleted"), KNotification::Persistent);
0336     mIntegrityNotification->setTitle(xi18nc("@title:window", "Integrity Check Completed"));
0337     mIntegrityNotification->setText(pJob->errorText());
0338 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0339     QStringList lAnswers;
0340     if(pJob->error() == BackupJob::ErrorWithLog) {
0341         lAnswers << xi18nc("@action:button", "Show log file");
0342         connect(mIntegrityNotification, SIGNAL(action1Activated()), SLOT(showLog()));
0343     } else if(pJob->error() == BackupJob::ErrorSuggestRepair) {
0344         lAnswers << xi18nc("@action:button", "Yes");
0345         lAnswers << xi18nc("@action:button", "No");
0346         connect(mIntegrityNotification, SIGNAL(action1Activated()), SLOT(startRepairJob()));
0347     }
0348     mIntegrityNotification->setActions(lAnswers);
0349 
0350     connect(mIntegrityNotification, SIGNAL(action2Activated()), SLOT(discardIntegrityNotification()));
0351 #else
0352     if(pJob->error() == BackupJob::ErrorWithLog) {
0353         KNotificationAction *showLogFile = new KNotificationAction(xi18nc("@action:button", "Show log file"));
0354         connect(showLogFile, &KNotificationAction::activated, this, &PlanExecutor::showLog);
0355     } else if(pJob->error() == BackupJob::ErrorSuggestRepair) {
0356         KNotificationAction *yes = mIntegrityNotification->addAction(xi18nc("@action:button", "Yes"));
0357         connect(yes, &KNotificationAction::activated, this, &PlanExecutor::startRepairJob);
0358 
0359         KNotificationAction *no = mIntegrityNotification->addAction(xi18nc("@action:button", "No"));
0360         connect(no, &KNotificationAction::activated, this, &PlanExecutor::discardIntegrityNotification);
0361     }
0362 #endif
0363 
0364     connect(mIntegrityNotification, SIGNAL(closed()), SLOT(discardIntegrityNotification()));
0365     connect(mIntegrityNotification, SIGNAL(ignored()), SLOT(discardIntegrityNotification()));
0366     mIntegrityNotification->sendEvent();
0367 
0368     if(mState == INTEGRITY_TESTING) { //only restore if nothing has changed during the run
0369         mState = mLastState;
0370     }
0371     emit stateChanged();
0372 }
0373 
0374 void PlanExecutor::discardIntegrityNotification() {
0375     if(mIntegrityNotification) {
0376         mIntegrityNotification->deleteLater();
0377         mIntegrityNotification = nullptr;
0378     }
0379 }
0380 
0381 void PlanExecutor::repairFinished(KJob *pJob) {
0382     endSleepInhibit();
0383     discardRepairNotification();
0384     mRepairNotification = new KNotification(QStringLiteral("RepairCompleted"), KNotification::Persistent);
0385     mRepairNotification->setTitle(xi18nc("@title:window", "Repair Completed"));
0386     mRepairNotification->setText(pJob->errorText());
0387 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0388     QStringList lAnswers;
0389     lAnswers << xi18nc("@action:button", "Show log file");
0390     mRepairNotification->setActions(lAnswers);
0391     connect(mRepairNotification, SIGNAL(action1Activated()), SLOT(showLog()));
0392 #else
0393     KNotificationAction *showLogFile = mRepairNotification->addAction(xi18nc("@action:button", "Show log file"));
0394     connect(showLogFile, &KNotificationAction::activated, this, &PlanExecutor::showLog);
0395 #endif
0396     connect(mRepairNotification, SIGNAL(closed()), SLOT(discardRepairNotification()));
0397     connect(mRepairNotification, SIGNAL(ignored()), SLOT(discardRepairNotification()));
0398     mRepairNotification->sendEvent();
0399 
0400     if(mState == REPAIRING) { //only restore if nothing has changed during the run
0401         mState = mLastState;
0402     }
0403     emit stateChanged();
0404 }
0405 
0406 void PlanExecutor::discardRepairNotification() {
0407     if(mRepairNotification) {
0408         mRepairNotification->deleteLater();
0409         mRepairNotification = nullptr;
0410     }
0411 }
0412 
0413 void PlanExecutor::startSleepInhibit() {
0414     if(mSleepCookie != 0) {
0415         return;
0416     }
0417     QDBusMessage lMsg = QDBusMessage::createMethodCall(cPwrMgmtServiceName,
0418                                                        cPwrMgmtPath,
0419                                                        cPwrMgmtInhibitInterface,
0420                                                        QStringLiteral("Inhibit"));
0421     lMsg << i18n("Kup Backup System");
0422     lMsg << currentActivityTitle();
0423     QDBusReply<uint> lReply = QDBusConnection::sessionBus().call(lMsg);
0424     mSleepCookie = lReply.value();
0425 }
0426 
0427 void PlanExecutor::endSleepInhibit() {
0428     if(mSleepCookie == 0) {
0429         return;
0430     }
0431     QDBusMessage lMsg = QDBusMessage::createMethodCall(cPwrMgmtServiceName,
0432                                                       cPwrMgmtPath,
0433                                                       cPwrMgmtInhibitInterface,
0434                                                       QStringLiteral("UnInhibit"));
0435     lMsg << mSleepCookie;
0436     QDBusConnection::sessionBus().asyncCall(lMsg);
0437     mSleepCookie = 0;
0438 }
0439 
0440 void PlanExecutor::exitBackupRunningState(bool pWasSuccessful) {
0441     endSleepInhibit();
0442     if(pWasSuccessful) {
0443         if(mPlan->mScheduleType == BackupPlan::USAGE) {
0444             //reset usage time after successful backup
0445             mPlan->mAccumulatedUsageTime =0;
0446             mPlan->save();
0447         }
0448         mState = WAITING_FOR_BACKUP_AGAIN;
0449         emit stateChanged();
0450 
0451         //don't know if status actually changed, potentially did... so trigger a re-read of status
0452         emit backupStatusChanged();
0453 
0454         // re-enter the main "available" state dispatcher
0455         enterAvailableState();
0456     } else {
0457         mState = WAITING_FOR_MANUAL_BACKUP;
0458         emit stateChanged();
0459     }
0460 }
0461 
0462 void PlanExecutor::updateAccumulatedUsageTime() {
0463     if(mState == BACKUP_RUNNING) { //usage time during backup doesn't count...
0464         return;
0465     }
0466 
0467     if(mPlan->mScheduleType == BackupPlan::USAGE) {
0468         mPlan->mAccumulatedUsageTime += KUP_USAGE_MONITOR_INTERVAL_S;
0469         mPlan->save();
0470     }
0471 
0472     // trigger refresh of backup status, potentially changed since some time has passed...
0473     // this is the reason why this slot is called repeatedly even when
0474     // not in BackupPlan::USAGE mode
0475     emit backupStatusChanged();
0476 
0477     //if we're waiting to run backup again, check if it is time now.
0478     if(mPlan->mScheduleType == BackupPlan::USAGE &&
0479           (mState == WAITING_FOR_FIRST_BACKUP || mState == WAITING_FOR_BACKUP_AGAIN)) {
0480         enterAvailableState();
0481     }
0482 }
0483 
0484 void PlanExecutor::showBackupFiles() {
0485     if(mState == NOT_AVAILABLE)
0486         return;
0487     if(mPlan->mBackupType == BackupPlan::BupType) {
0488         QStringList lArgs;
0489         lArgs << mDestinationPath;
0490         KProcess::startDetached(QStringLiteral("kup-filedigger"), lArgs);
0491     } else if(mPlan->mBackupType == BackupPlan::RsyncType) {
0492         auto *job = new KIO::OpenUrlJob(QUrl::fromLocalFile(mDestinationPath));
0493         job->start();
0494     }
0495 }
0496 
0497 void PlanExecutor::showBackupPurger() {
0498     if(mPlan->mBackupType != BackupPlan::BupType || busy() || !destinationAvailable()) {
0499         return;
0500     }
0501     QStringList lArgs;
0502     lArgs << mDestinationPath;
0503     KProcess::startDetached(QStringLiteral("kup-purger"), lArgs);
0504 }
0505 
0506 BackupJob *PlanExecutor::createBackupJob() {
0507     if(mPlan->mBackupType == BackupPlan::BupType) {
0508         return new BupJob(*mPlan, mDestinationPath, mLogFilePath, mKupDaemon);
0509     }
0510     if(mPlan->mBackupType == BackupPlan::RsyncType) {
0511         return new RsyncJob(*mPlan, mDestinationPath, mLogFilePath, mKupDaemon);
0512     }
0513     qCWarning(KUPDAEMON) << "Invalid backup type in configuration!";
0514     return nullptr;
0515 }
0516 
0517 bool PlanExecutor::powerSaveActive() {
0518     QDBusMessage lMsg = QDBusMessage::createMethodCall(cPwrMgmtServiceName,
0519                                                        cPwrMgmtPath,
0520                                                        cPwrMgmtInterface,
0521                                                        QStringLiteral("GetPowerSaveStatus"));
0522     QDBusReply<bool> lReply = QDBusConnection::sessionBus().call(lMsg);
0523     return lReply.value();
0524 }