File indexing completed on 2024-05-05 05:50:41

0001 /*
0002     SPDX-FileCopyrightText: 2007 Henrique Pinto <henrique.pinto@kdemail.net>
0003     SPDX-FileCopyrightText: 2008-2009 Harald Hvaal <haraldhv@stud.ntnu.no>
0004     SPDX-FileCopyrightText: 2009-2012 Raphael Kubo da Costa <rakuco@FreeBSD.org>
0005     SPDX-FileCopyrightText: 2016 Vladyslav Batyrenko <mvlabat@gmail.com>
0006 
0007     SPDX-License-Identifier: BSD-2-Clause
0008 */
0009 
0010 #ifndef JOBS_H
0011 #define JOBS_H
0012 
0013 #include "archive_kerfuffle.h"
0014 #include "archiveentry.h"
0015 #include "archiveinterface.h"
0016 #include "kerfuffle_export.h"
0017 #include "queries.h"
0018 
0019 #include <KJob>
0020 
0021 #include <QElapsedTimer>
0022 #include <QPointer>
0023 #include <QTemporaryDir>
0024 
0025 namespace Kerfuffle
0026 {
0027 class KERFUFFLE_EXPORT Job : public KJob
0028 {
0029     Q_OBJECT
0030 
0031 public:
0032     /**
0033      * @return The archive processed by this job.
0034      * @warning This method should not be called before start().
0035      */
0036     Archive *archive() const;
0037     QString errorString() const override;
0038     void start() override;
0039 
0040 protected:
0041     Job(Archive *archive, ReadOnlyArchiveInterface *interface);
0042     Job(Archive *archive);
0043     Job(ReadOnlyArchiveInterface *interface);
0044     ~Job() override;
0045     bool doKill() override;
0046 
0047     ReadOnlyArchiveInterface *archiveInterface();
0048 
0049     void connectToArchiveInterfaceSignals();
0050 
0051 public Q_SLOTS:
0052     virtual void doWork() = 0;
0053 
0054 protected Q_SLOTS:
0055     virtual void onCancelled();
0056     virtual void onError(const QString &message, const QString &details, int errorCode);
0057     virtual void onInfo(const QString &info);
0058     virtual void onEntry(Archive::Entry *entry);
0059     virtual void onProgress(double progress);
0060     virtual void onEntryRemoved(const QString &path);
0061     virtual void onFinished(bool result);
0062     virtual void onUserQuery(Kerfuffle::Query *query);
0063 
0064 Q_SIGNALS:
0065     void entryRemoved(const QString &entry);
0066     void newEntry(Archive::Entry *);
0067     void userQuery(Kerfuffle::Query *);
0068 
0069 private:
0070     Archive *m_archive;
0071     ReadOnlyArchiveInterface *m_archiveInterface;
0072     QElapsedTimer jobTimer;
0073 
0074     class Private;
0075     Private *const d;
0076 };
0077 
0078 /**
0079  * Load an existing archive.
0080  * Example usage:
0081  *
0082  * \code
0083  *
0084  * auto job = Archive::load(filename);
0085  * connect(job, &KJob::result, [](KJob *job) {
0086  *     if (!job->error) {
0087  *         auto archive = qobject_cast<Archive::LoadJob*>(job)->archive();
0088  *         // do something with archive.
0089  *     }
0090  * });
0091  * job->start();
0092  *
0093  * \endcode
0094  */
0095 class KERFUFFLE_EXPORT LoadJob : public Job
0096 {
0097     Q_OBJECT
0098 
0099 public:
0100     explicit LoadJob(Archive *archive);
0101     explicit LoadJob(ReadOnlyArchiveInterface *interface);
0102 
0103     qlonglong extractedFilesSize() const;
0104     bool isPasswordProtected() const;
0105     bool isSingleFolderArchive() const;
0106     QString subfolderName() const;
0107 
0108 public Q_SLOTS:
0109     void doWork() override;
0110 
0111 protected Q_SLOTS:
0112     void onFinished(bool result) override;
0113 
0114 private:
0115     explicit LoadJob(Archive *archive, ReadOnlyArchiveInterface *interface);
0116 
0117     bool m_isSingleFolderArchive;
0118     bool m_isPasswordProtected;
0119     QString m_subfolderName;
0120     QString m_basePath;
0121     qlonglong m_extractedFilesSize;
0122     qlonglong m_dirCount;
0123     qlonglong m_filesCount;
0124 
0125 private Q_SLOTS:
0126     void onNewEntry(const Archive::Entry *);
0127 };
0128 
0129 /**
0130  * Perform a batch extraction of an existing archive.
0131  * Internally it runs a LoadJob before the actual extraction,
0132  * to figure out properties such as the subfolder name.
0133  */
0134 class KERFUFFLE_EXPORT BatchExtractJob : public Job
0135 {
0136     Q_OBJECT
0137 
0138 public:
0139     explicit BatchExtractJob(LoadJob *loadJob, const QString &destination, bool autoSubfolder, bool preservePaths);
0140 
0141 public Q_SLOTS:
0142     void doWork() override;
0143 
0144 protected:
0145     bool doKill() override;
0146 
0147 private Q_SLOTS:
0148     void slotLoadingProgress(double progress);
0149     void slotExtractProgress(double progress);
0150     void slotLoadingFinished(KJob *job);
0151 
0152 private:
0153     /**
0154      * Tracks whether the job is loading or extracting the archive.
0155      */
0156     enum Step { Loading, Extracting };
0157 
0158     void setupDestination();
0159 
0160     Step m_step = Loading;
0161     ExtractJob *m_extractJob = nullptr;
0162     LoadJob *m_loadJob;
0163     QString m_destination;
0164     bool m_autoSubfolder;
0165     bool m_preservePaths;
0166     unsigned long m_lastPercentage = 0;
0167 };
0168 
0169 /**
0170  * Create a new archive given a bunch of entries.
0171  */
0172 class KERFUFFLE_EXPORT CreateJob : public Job
0173 {
0174     Q_OBJECT
0175 
0176 public:
0177     explicit CreateJob(Archive *archive, const QVector<Archive::Entry *> &entries, const CompressionOptions &options);
0178 
0179     ~CreateJob();
0180     /**
0181      * @param password The password to encrypt the archive with.
0182      * @param encryptHeader Whether to encrypt also the list of files.
0183      */
0184     void enableEncryption(const QString &password, bool encryptHeader);
0185 
0186     /**
0187      * Set whether the new archive should be multivolume.
0188      */
0189     void setMultiVolume(bool isMultiVolume);
0190 
0191 public Q_SLOTS:
0192     void doWork() override;
0193 
0194 protected:
0195     bool doKill() override;
0196 
0197 private:
0198     QPointer<AddJob> m_addJob;
0199     QVector<Archive::Entry *> m_entries;
0200     CompressionOptions m_options;
0201 };
0202 
0203 class KERFUFFLE_EXPORT ExtractJob : public Job
0204 {
0205     Q_OBJECT
0206 
0207 public:
0208     ExtractJob(const QVector<Archive::Entry *> &entries, const QString &destinationDir, ExtractionOptions options, ReadOnlyArchiveInterface *interface);
0209 
0210     QString destinationDirectory() const;
0211     ExtractionOptions extractionOptions() const;
0212 
0213 public Q_SLOTS:
0214     void doWork() override;
0215 
0216 private:
0217     QVector<Archive::Entry *> m_entries;
0218     QString m_destinationDir;
0219     ExtractionOptions m_options;
0220 };
0221 
0222 /**
0223  * Abstract base class for jobs that extract a single file to a temporary dir.
0224  * It's not possible to pass extraction options and paths will be always preserved.
0225  * The only option that the job needs to know is whether the file is password protected.
0226  */
0227 class KERFUFFLE_EXPORT TempExtractJob : public Job
0228 {
0229     Q_OBJECT
0230 
0231 public:
0232     TempExtractJob(Archive::Entry *entry, bool passwordProtectedHint, ReadOnlyArchiveInterface *interface);
0233 
0234     Archive::Entry *entry() const;
0235 
0236     /**
0237      * @return The absolute path of the extracted file.
0238      * The path is validated in order to prevent directory traversal attacks.
0239      */
0240     QString validatedFilePath() const;
0241 
0242     ExtractionOptions extractionOptions() const;
0243 
0244     /**
0245      * @return The temporary dir used for the extraction.
0246      * It is safe to delete this pointer in order to remove the directory.
0247      */
0248     QTemporaryDir *tempDir() const;
0249 
0250 public Q_SLOTS:
0251     void doWork() override;
0252 
0253 private:
0254     QString extractionDir() const;
0255 
0256     Archive::Entry *m_entry;
0257     QTemporaryDir *m_tmpExtractDir;
0258     bool m_passwordProtectedHint;
0259 };
0260 
0261 /**
0262  * This TempExtractJob can be used to preview a file.
0263  * The temporary extraction directory will be deleted upon job's completion.
0264  */
0265 class KERFUFFLE_EXPORT PreviewJob : public TempExtractJob
0266 {
0267     Q_OBJECT
0268 
0269 public:
0270     PreviewJob(Archive::Entry *entry, bool passwordProtectedHint, ReadOnlyArchiveInterface *interface);
0271 };
0272 
0273 /**
0274  * This TempExtractJob can be used to open a file in its dedicated application.
0275  * For this reason, the temporary extraction directory will NOT be deleted upon job's completion.
0276  */
0277 class KERFUFFLE_EXPORT OpenJob : public TempExtractJob
0278 {
0279     Q_OBJECT
0280 
0281 public:
0282     OpenJob(Archive::Entry *entry, bool passwordProtectedHint, ReadOnlyArchiveInterface *interface);
0283 };
0284 
0285 class KERFUFFLE_EXPORT OpenWithJob : public OpenJob
0286 {
0287     Q_OBJECT
0288 
0289 public:
0290     OpenWithJob(Archive::Entry *entry, bool passwordProtectedHint, ReadOnlyArchiveInterface *interface);
0291 };
0292 
0293 class KERFUFFLE_EXPORT AddJob : public Job
0294 {
0295     Q_OBJECT
0296 
0297 public:
0298     AddJob(const QVector<Archive::Entry *> &files, const Archive::Entry *destination, const CompressionOptions &options, ReadWriteArchiveInterface *interface);
0299 
0300 public Q_SLOTS:
0301     void doWork() override;
0302 
0303 protected Q_SLOTS:
0304     void onFinished(bool result) override;
0305 
0306 private:
0307     QString m_oldWorkingDir;
0308     const QVector<Archive::Entry *> m_entries;
0309     const Archive::Entry *m_destination;
0310     CompressionOptions m_options;
0311 };
0312 
0313 /**
0314  * This MoveJob can be used to rename or move entries within the archive.
0315  * @see Archive::moveFiles for more details.
0316  */
0317 class KERFUFFLE_EXPORT MoveJob : public Job
0318 {
0319     Q_OBJECT
0320 
0321 public:
0322     MoveJob(const QVector<Archive::Entry *> &files, Archive::Entry *destination, const CompressionOptions &options, ReadWriteArchiveInterface *interface);
0323 
0324 public Q_SLOTS:
0325     void doWork() override;
0326 
0327 protected Q_SLOTS:
0328     void onFinished(bool result) override;
0329 
0330 private:
0331     int m_finishedSignalsCount;
0332     const QVector<Archive::Entry *> m_entries;
0333     Archive::Entry *m_destination;
0334     CompressionOptions m_options;
0335 };
0336 
0337 /**
0338  * This CopyJob can be used to copy entries within the archive.
0339  * @see Archive::copyFiles for more details.
0340  */
0341 class KERFUFFLE_EXPORT CopyJob : public Job
0342 {
0343     Q_OBJECT
0344 
0345 public:
0346     CopyJob(const QVector<Archive::Entry *> &entries, Archive::Entry *destination, const CompressionOptions &options, ReadWriteArchiveInterface *interface);
0347 
0348 public Q_SLOTS:
0349     void doWork() override;
0350 
0351 protected Q_SLOTS:
0352     void onFinished(bool result) override;
0353 
0354 private:
0355     int m_finishedSignalsCount;
0356     const QVector<Archive::Entry *> m_entries;
0357     Archive::Entry *m_destination;
0358     CompressionOptions m_options;
0359 };
0360 
0361 class KERFUFFLE_EXPORT DeleteJob : public Job
0362 {
0363     Q_OBJECT
0364 
0365 public:
0366     DeleteJob(const QVector<Archive::Entry *> &files, ReadWriteArchiveInterface *interface);
0367 
0368 public Q_SLOTS:
0369     void doWork() override;
0370 
0371 private:
0372     QVector<Archive::Entry *> m_entries;
0373 };
0374 
0375 class KERFUFFLE_EXPORT CommentJob : public Job
0376 {
0377     Q_OBJECT
0378 
0379 public:
0380     CommentJob(const QString &comment, ReadWriteArchiveInterface *interface);
0381 
0382 public Q_SLOTS:
0383     void doWork() override;
0384 
0385 private:
0386     QString m_comment;
0387 };
0388 
0389 class KERFUFFLE_EXPORT TestJob : public Job
0390 {
0391     Q_OBJECT
0392 
0393 public:
0394     explicit TestJob(ReadOnlyArchiveInterface *interface);
0395     bool testSucceeded();
0396 
0397 public Q_SLOTS:
0398     void doWork() override;
0399 
0400 private Q_SLOTS:
0401     virtual void onTestSuccess();
0402 
0403 private:
0404     bool m_testSuccess;
0405 };
0406 
0407 } // namespace Kerfuffle
0408 
0409 #endif // JOBS_H