File indexing completed on 2024-04-21 05:46:32

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 "backupplan.h"
0006 #include "kuputils.h"
0007 
0008 #include <QDir>
0009 #include <QStandardPaths>
0010 #include <QString>
0011 
0012 #include <KFormat>
0013 #include <KLocalizedString>
0014 #include <utility>
0015 
0016 BackupPlan::BackupPlan(int pPlanNumber, KSharedConfigPtr pConfig, QObject *pParent)
0017    :KCoreConfigSkeleton(std::move(pConfig), pParent), mPlanNumber(pPlanNumber)
0018 {
0019     setCurrentGroup(QString(QStringLiteral("Plan/%1")).arg(mPlanNumber));
0020 
0021     addItemString(QStringLiteral("Description"), mDescription,
0022                   xi18nc("@label Default name for a new backup plan, %1 is the number of the plan in order",
0023                         "Backup plan %1", pPlanNumber));
0024     QStringList lDefaultIncludeList;
0025     lDefaultIncludeList << QDir::homePath();
0026     addItemStringList(QStringLiteral("Paths included"), mPathsIncluded, lDefaultIncludeList);
0027     QStringList lDefaultExcludeList;
0028     lDefaultExcludeList << QDir::homePath() + QStringLiteral("/.cache");
0029     lDefaultExcludeList << QDir::homePath() + QStringLiteral("/.bup");
0030     lDefaultExcludeList << QDir::homePath() + QStringLiteral("/.thumbnails");
0031     lDefaultExcludeList << QDir::homePath() + QStringLiteral("/.local/share/Trash");
0032     lDefaultExcludeList << QDir::homePath() + QStringLiteral("/.local/share/baloo");
0033     lDefaultExcludeList << QDir::homePath() + QStringLiteral("/.local/share/TelegramDesktop/tdata/temp");
0034     lDefaultExcludeList << QDir::homePath() + QStringLiteral("/.config/Riot/Cache");
0035     QMutableStringListIterator i(lDefaultExcludeList);
0036     while(i.hasNext()) {
0037         ensureNoTrailingSlash(i.next());
0038     }
0039 
0040     addItemStringList(QStringLiteral("Paths excluded"), mPathsExcluded, lDefaultExcludeList);
0041     addItemInt(QStringLiteral("Backup type"), mBackupType);
0042     addItemInt(QStringLiteral("Backup version"), mBackupVersion);
0043 
0044     addItemInt(QStringLiteral("Schedule type"), mScheduleType, 2);
0045     addItemInt(QStringLiteral("Schedule interval"), mScheduleInterval, 1);
0046     addItemInt(QStringLiteral("Schedule interval unit"), mScheduleIntervalUnit, 3);
0047     addItemInt(QStringLiteral("Usage limit"), mUsageLimit, 25);
0048     addItemBool(QStringLiteral("Ask first"), mAskBeforeTakingBackup, true);
0049 
0050     addItemInt(QStringLiteral("Destination type"), mDestinationType, 1);
0051     addItem(new KCoreConfigSkeleton::ItemUrl(currentGroup(),
0052                                              QStringLiteral("Filesystem destination path"),
0053                                              mFilesystemDestinationPath,
0054                                              QUrl::fromLocalFile(QDir::homePath() + QStringLiteral("/.bup"))));
0055     addItemString(QStringLiteral("External drive UUID"), mExternalUUID);
0056     addItemPath(QStringLiteral("External drive destination path"), mExternalDestinationPath, i18n("Backups"));
0057     addItemString(QStringLiteral("External volume label"), mExternalVolumeLabel);
0058     addItemULongLong(QStringLiteral("External volume capacity"), mExternalVolumeCapacity);
0059     addItemString(QStringLiteral("External device description"), mExternalDeviceDescription);
0060     addItemInt(QStringLiteral("External partition number"), mExternalPartitionNumber);
0061     addItemInt(QStringLiteral("External partitions count"), mExternalPartitionsOnDrive);
0062 
0063     addItemBool(QStringLiteral("Show hidden folders"), mShowHiddenFolders);
0064     addItemBool(QStringLiteral("Generate recovery info"), mGenerateRecoveryInfo);
0065     addItemBool(QStringLiteral("Check backups"), mCheckBackups);
0066     addItemBool(QStringLiteral("Exclude patterns"), mExcludePatterns);
0067     addItemString(QStringLiteral("Exclude patterns file path"), mExcludePatternsPath);
0068 
0069     addItemDateTime(QStringLiteral("Last complete backup"), mLastCompleteBackup);
0070     addItemDouble(QStringLiteral("Last backup size"), mLastBackupSize);
0071     addItemDouble(QStringLiteral("Last available space"), mLastAvailableSpace);
0072     addItemUInt(QStringLiteral("Accumulated usage time"), mAccumulatedUsageTime);
0073     load();
0074 }
0075 
0076 void BackupPlan::setPlanNumber(int pPlanNumber) {
0077     mPlanNumber = pPlanNumber;
0078     QString lGroupName = QString(QStringLiteral("Plan/%1")).arg(mPlanNumber);
0079     foreach(KConfigSkeletonItem *lItem, items()) {
0080         lItem->setGroup(lGroupName);
0081     }
0082 }
0083 
0084 void BackupPlan::removePlanFromConfig() {
0085     config()->deleteGroup(QString(QStringLiteral("Plan/%1")).arg(mPlanNumber));
0086     save();
0087 }
0088 
0089 void BackupPlan::copyFrom(const BackupPlan &pPlan) {
0090     mDescription = i18nc("default description of newly duplicated backup plan",
0091                          "%1 (copy)", pPlan.mDescription);
0092     mPathsIncluded = pPlan.mPathsIncluded;
0093     mPathsExcluded = pPlan.mPathsExcluded;
0094     mBackupType = pPlan.mBackupType;
0095     mScheduleType = pPlan.mScheduleType;
0096     mScheduleInterval = pPlan.mScheduleInterval;
0097     mScheduleIntervalUnit = pPlan.mScheduleIntervalUnit;
0098     mUsageLimit = pPlan.mUsageLimit;
0099     mAskBeforeTakingBackup = pPlan.mAskBeforeTakingBackup;
0100     mDestinationType = pPlan.mDestinationType;
0101     mFilesystemDestinationPath = pPlan.mFilesystemDestinationPath;
0102     mExternalUUID = pPlan.mExternalUUID;
0103     mExternalDestinationPath = pPlan.mExternalDestinationPath;
0104     mExternalVolumeLabel = pPlan.mExternalVolumeLabel;
0105     mExternalDeviceDescription = pPlan.mExternalDeviceDescription;
0106     mExternalPartitionNumber = pPlan.mExternalPartitionNumber;
0107     mExternalPartitionsOnDrive = pPlan.mExternalPartitionsOnDrive;
0108     mExternalVolumeCapacity = pPlan.mExternalVolumeCapacity;
0109     mShowHiddenFolders = pPlan.mShowHiddenFolders;
0110     mGenerateRecoveryInfo = pPlan.mGenerateRecoveryInfo;
0111     mCheckBackups = pPlan.mCheckBackups;
0112 }
0113 
0114 QDateTime BackupPlan::nextScheduledTime() {
0115     Q_ASSERT(mScheduleType == 1);
0116     if(!mLastCompleteBackup.isValid())
0117         return QDateTime(); //plan has never been run
0118 
0119     return mLastCompleteBackup.addSecs(scheduleIntervalInSeconds());
0120 }
0121 
0122 qint64 BackupPlan::scheduleIntervalInSeconds() {
0123     Q_ASSERT(mScheduleType == 1);
0124 
0125     switch(mScheduleIntervalUnit) {
0126     case 0:
0127         return mScheduleInterval * 60;
0128     case 1:
0129         return mScheduleInterval * 60 * 60;
0130     case 2:
0131         return mScheduleInterval * 60 * 60 * 24;
0132     case 3:
0133         return mScheduleInterval * 60 * 60 * 24 * 7;
0134     default:
0135         return 0;
0136     }
0137 }
0138 
0139 BackupPlan::Status BackupPlan::backupStatus() {
0140     if(!mLastCompleteBackup.isValid()) {
0141         return BAD;
0142     }
0143     if(mScheduleType == MANUAL) {
0144         return NO_STATUS;
0145     }
0146 
0147     qint64 lStatus = 5; //trigger BAD status if schedule type is something strange
0148     qint64 lInterval = 1;
0149 
0150     switch(mScheduleType) {
0151     case INTERVAL:
0152         lStatus = mLastCompleteBackup.secsTo(QDateTime::currentDateTimeUtc());
0153         lInterval = scheduleIntervalInSeconds();
0154         break;
0155     case USAGE:
0156         lStatus = mAccumulatedUsageTime;
0157         lInterval = mUsageLimit * 3600;
0158         break;
0159     }
0160 
0161     if(lStatus < lInterval)
0162         return GOOD;
0163     if(lStatus < lInterval * 3)
0164         return MEDIUM;
0165     return BAD;
0166 }
0167 
0168 QString BackupPlan::iconName(Status pStatus) {
0169     switch(pStatus) {
0170     case GOOD:
0171         return QStringLiteral("security-high");
0172     case MEDIUM:
0173         return QStringLiteral("security-medium");
0174     case BAD:
0175         return QStringLiteral("security-low");
0176     case NO_STATUS:
0177         break;
0178     }
0179     return QString();
0180 }
0181 
0182 QString BackupPlan::absoluteExcludesFilePath() {
0183     if(QDir::isRelativePath(mExcludePatternsPath)) {
0184         return QDir::homePath() + QDir::separator() + mExcludePatternsPath;
0185     }
0186     return mExcludePatternsPath;
0187 }
0188 
0189 void BackupPlan::usrRead() {
0190     //correct the time spec after default read routines.
0191     mLastCompleteBackup.setTimeSpec(Qt::UTC);
0192     QMutableStringListIterator lExcludes(mPathsExcluded);
0193     while(lExcludes.hasNext()) {
0194         ensureNoTrailingSlash(lExcludes.next());
0195     }
0196     QMutableStringListIterator lIncludes(mPathsIncluded);
0197     while(lIncludes.hasNext()) {
0198         ensureNoTrailingSlash(lIncludes.next());
0199     }
0200 }
0201 
0202 QString BackupPlan::statusText() {
0203     QLocale lLocale;
0204     KFormat lFormat(lLocale);
0205     QString lStatus;
0206     if(mLastCompleteBackup.isValid()) {
0207         QDateTime lLocalTime = mLastCompleteBackup.toLocalTime();
0208 
0209         lStatus += i18nc("%1 is fancy formatted date", "Last saved: %1",
0210                          lFormat.formatRelativeDate(lLocalTime.date(), QLocale::LongFormat));
0211 
0212         if(mLastBackupSize > 0.0) {
0213             lStatus += '\n';
0214             lStatus += i18nc("%1 is storage size of archive", "Size: %1",
0215                              lFormat.formatByteSize(mLastBackupSize));
0216         }
0217         if(mLastAvailableSpace > 0.0) {
0218             lStatus += '\n';
0219             lStatus += i18nc("%1 is free storage space", "Free space: %1",
0220                              lFormat.formatByteSize(mLastAvailableSpace));
0221         }
0222     } else {
0223         lStatus = xi18nc("@label", "This backup plan has never been run.");
0224     }
0225     return lStatus;
0226 }