jobs.h 10.8 KB
Newer Older
1 2
/*
 * Copyright (c) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
3
 * Copyright (c) 2008-2009 Harald Hvaal <haraldhv@stud.ntnu.no>
4
 * Copyright (c) 2009-2012 Raphael Kubo da Costa <rakuco@FreeBSD.org>
5
 * Copyright (c) 2016 Vladyslav Batyrenko <mvlabat@gmail.com>
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
28

29 30 31 32 33
#ifndef JOBS_H
#define JOBS_H

#include "kerfuffle_export.h"
#include "archiveinterface.h"
34
#include "archive_kerfuffle.h"
35
#include "archiveentry.h"
36
#include "queries.h"
37 38

#include <KJob>
39

40
#include <QElapsedTimer>
41
#include <QTemporaryDir>
42 43 44

namespace Kerfuffle
{
45

46
class KERFUFFLE_EXPORT Job : public KJob
47 48 49 50
{
    Q_OBJECT

public:
Elvis Angelaccio's avatar
Elvis Angelaccio committed
51 52 53 54 55 56

    /**
     * @return The archive processed by this job.
     * @warning This method should not be called before start().
     */
    Archive *archive() const;
57 58
    QString errorString() const override;
    void start() override;
59 60

protected:
Elvis Angelaccio's avatar
Elvis Angelaccio committed
61 62
    Job(Archive *archive, ReadOnlyArchiveInterface *interface);
    Job(Archive *archive);
Elvis Angelaccio's avatar
Elvis Angelaccio committed
63
    Job(ReadOnlyArchiveInterface *interface);
64 65
    ~Job() override;
    bool doKill() override;
66

67
    ReadOnlyArchiveInterface *archiveInterface();
68

69 70
    void connectToArchiveInterfaceSignals();

71
public Q_SLOTS:
72 73
    virtual void doWork() = 0;

74
protected Q_SLOTS:
75
    virtual void onCancelled();
76 77
    virtual void onError(const QString &message, const QString &details);
    virtual void onInfo(const QString &info);
78
    virtual void onEntry(Archive::Entry *entry);
79 80 81
    virtual void onProgress(double progress);
    virtual void onEntryRemoved(const QString &path);
    virtual void onFinished(bool result);
82
    virtual void onUserQuery(Kerfuffle::Query *query);
83

84
Q_SIGNALS:
85
    void entryRemoved(const QString & entry);
86
    void newEntry(Archive::Entry*);
87
    void userQuery(Kerfuffle::Query*);
88 89

private:
Elvis Angelaccio's avatar
Elvis Angelaccio committed
90
    Archive *m_archive;
91
    ReadOnlyArchiveInterface *m_archiveInterface;
92
    QElapsedTimer jobTimer;
93

94 95
    class Private;
    Private * const d;
96 97
};

Elvis Angelaccio's avatar
Elvis Angelaccio committed
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
/**
 * Load an existing archive.
 * Example usage:
 *
 * \code
 *
 * auto job = Archive::load(filename);
 * connect(job, &KJob::result, [](KJob *job) {
 *     if (!job->error) {
 *         auto archive = qobject_cast<Archive::LoadJob*>(job)->archive();
 *         // do something with archive.
 *     }
 * });
 * job->start();
 *
 * \endcode
 */
class KERFUFFLE_EXPORT LoadJob : public Job
116 117 118 119
{
    Q_OBJECT

public:
Elvis Angelaccio's avatar
Elvis Angelaccio committed
120 121
    explicit LoadJob(Archive *archive);
    explicit LoadJob(ReadOnlyArchiveInterface *interface);
122

123 124 125 126
    qlonglong extractedFilesSize() const;
    bool isPasswordProtected() const;
    bool isSingleFolderArchive() const;
    QString subfolderName() const;
127

128
public Q_SLOTS:
129
    void doWork() override;
130

131
protected Q_SLOTS:
132
    void onFinished(bool result) override;
Elvis Angelaccio's avatar
Elvis Angelaccio committed
133

134
private:
Elvis Angelaccio's avatar
Elvis Angelaccio committed
135 136
    explicit LoadJob(Archive *archive, ReadOnlyArchiveInterface *interface);

137 138 139
    bool m_isSingleFolderArchive;
    bool m_isPasswordProtected;
    QString m_subfolderName;
140
    QString m_basePath;
141
    qlonglong m_extractedFilesSize;
142 143
    qlonglong m_dirCount;
    qlonglong m_filesCount;
144

145
private Q_SLOTS:
146
    void onNewEntry(const Archive::Entry*);
147 148
};

Elvis Angelaccio's avatar
Elvis Angelaccio committed
149 150 151 152 153 154 155 156 157 158 159 160
/**
 * Perform a batch extraction of an existing archive.
 * Internally it runs a LoadJob before the actual extraction,
 * to figure out properties such as the subfolder name.
 */
class KERFUFFLE_EXPORT BatchExtractJob : public Job
{
    Q_OBJECT

public:
    explicit BatchExtractJob(LoadJob *loadJob, const QString &destination, bool autoSubfolder, bool preservePaths);

161
public Q_SLOTS:
162
    void doWork() override;
Elvis Angelaccio's avatar
Elvis Angelaccio committed
163

164
protected:
165
    bool doKill() override;
166

167
private Q_SLOTS:
168 169
    void slotLoadingProgress(double progress);
    void slotExtractProgress(double progress);
Elvis Angelaccio's avatar
Elvis Angelaccio committed
170 171 172
    void slotLoadingFinished(KJob *job);

private:
173 174 175 176 177 178

    /**
     * Tracks whether the job is loading or extracting the archive.
     */
    enum Step {Loading, Extracting};

Elvis Angelaccio's avatar
Elvis Angelaccio committed
179 180
    void setupDestination();

181
    Step m_step = Loading;
182
    ExtractJob *m_extractJob = nullptr;
Elvis Angelaccio's avatar
Elvis Angelaccio committed
183 184 185 186
    LoadJob *m_loadJob;
    QString m_destination;
    bool m_autoSubfolder;
    bool m_preservePaths;
187
    unsigned long m_lastPercentage = 0;
Elvis Angelaccio's avatar
Elvis Angelaccio committed
188 189 190 191 192 193 194 195 196 197
};

/**
 * Create a new archive given a bunch of entries.
 */
class KERFUFFLE_EXPORT CreateJob : public Job
{
    Q_OBJECT

public:
198
    explicit CreateJob(Archive *archive, const QVector<Archive::Entry*> &entries, const CompressionOptions& options);
Elvis Angelaccio's avatar
Elvis Angelaccio committed
199 200 201 202 203 204 205 206 207 208 209 210

    /**
     * @param password The password to encrypt the archive with.
     * @param encryptHeader Whether to encrypt also the list of files.
     */
    void enableEncryption(const QString &password, bool encryptHeader);

    /**
     * Set whether the new archive should be multivolume.
     */
    void setMultiVolume(bool isMultiVolume);

211
public Q_SLOTS:
212
    void doWork() override;
Elvis Angelaccio's avatar
Elvis Angelaccio committed
213

214
protected:
215
    bool doKill() override;
216

Elvis Angelaccio's avatar
Elvis Angelaccio committed
217
private:
218
    AddJob *m_addJob = nullptr;
219
    QVector<Archive::Entry*> m_entries;
Elvis Angelaccio's avatar
Elvis Angelaccio committed
220 221 222
    CompressionOptions m_options;
};

223
class KERFUFFLE_EXPORT ExtractJob : public Job
224 225 226 227
{
    Q_OBJECT

public:
Laurent Montel's avatar
Laurent Montel committed
228
    ExtractJob(const QVector<Archive::Entry*> &entries, const QString& destinationDir, ExtractionOptions options, ReadOnlyArchiveInterface *interface);
229

230
    QString destinationDirectory() const;
231
    ExtractionOptions extractionOptions() const;
232

233
public Q_SLOTS:
234
    void doWork() override;
235 236

private:
237

238
    QVector<Archive::Entry*> m_entries;
239 240 241 242
    QString m_destinationDir;
    ExtractionOptions m_options;
};

243 244 245 246 247 248 249 250 251 252
/**
 * Abstract base class for jobs that extract a single file to a temporary dir.
 * It's not possible to pass extraction options and paths will be always preserved.
 * The only option that the job needs to know is whether the file is password protected.
 */
class KERFUFFLE_EXPORT TempExtractJob : public Job
{
    Q_OBJECT

public:
253
    TempExtractJob(Archive::Entry *entry, bool passwordProtectedHint, ReadOnlyArchiveInterface *interface);
254 255 256 257 258 259 260 261 262

    /**
     * @return The absolute path of the extracted file.
     * The path is validated in order to prevent directory traversal attacks.
     */
    QString validatedFilePath() const;

    ExtractionOptions extractionOptions() const;

263 264 265 266 267 268
    /**
     * @return The temporary dir used for the extraction.
     * It is safe to delete this pointer in order to remove the directory.
     */
    QTemporaryDir *tempDir() const;

269
public Q_SLOTS:
270
    void doWork() override;
271 272

private:
273
    QString extractionDir() const;
274

275
    Archive::Entry *m_entry;
276
    QTemporaryDir *m_tmpExtractDir;
277 278 279 280 281 282 283 284 285 286 287 288
    bool m_passwordProtectedHint;
};

/**
 * This TempExtractJob can be used to preview a file.
 * The temporary extraction directory will be deleted upon job's completion.
 */
class KERFUFFLE_EXPORT PreviewJob : public TempExtractJob
{
    Q_OBJECT

public:
289
    PreviewJob(Archive::Entry *entry, bool passwordProtectedHint, ReadOnlyArchiveInterface *interface);
290 291 292 293 294 295 296 297 298 299 300
};

/**
 * This TempExtractJob can be used to open a file in its dedicated application.
 * For this reason, the temporary extraction directory will NOT be deleted upon job's completion.
 */
class KERFUFFLE_EXPORT OpenJob : public TempExtractJob
{
    Q_OBJECT

public:
301
    OpenJob(Archive::Entry *entry, bool passwordProtectedHint, ReadOnlyArchiveInterface *interface);
302 303 304 305 306 307 308
};

class KERFUFFLE_EXPORT OpenWithJob : public OpenJob
{
    Q_OBJECT

public:
309
    OpenWithJob(Archive::Entry *entry, bool passwordProtectedHint, ReadOnlyArchiveInterface *interface);
310 311
};

312
class KERFUFFLE_EXPORT AddJob : public Job
313 314 315 316
{
    Q_OBJECT

public:
317
    AddJob(const QVector<Archive::Entry*> &files, const Archive::Entry *destination, const CompressionOptions& options, ReadWriteArchiveInterface *interface);
318

319
public Q_SLOTS:
320
    void doWork() override;
321

322
protected Q_SLOTS:
323
    void onFinished(bool result) override;
324

325
private:
326
    QString m_oldWorkingDir;
327
    const QVector<Archive::Entry*> m_entries;
328 329 330 331 332
    const Archive::Entry *m_destination;
    CompressionOptions m_options;
};

/**
Elvis Angelaccio's avatar
Elvis Angelaccio committed
333
 * This MoveJob can be used to rename or move entries within the archive.
334 335 336 337 338 339 340
 * @see Archive::moveFiles for more details.
 */
class KERFUFFLE_EXPORT MoveJob : public Job
{
Q_OBJECT

public:
341
    MoveJob(const QVector<Archive::Entry*> &files, Archive::Entry *destination, const CompressionOptions& options, ReadWriteArchiveInterface *interface);
342

343
public Q_SLOTS:
344
    void doWork() override;
345

346
protected Q_SLOTS:
347
    void onFinished(bool result) override;
348 349 350

private:
    int m_finishedSignalsCount;
351
    const QVector<Archive::Entry*> m_entries;
352 353 354 355 356
    Archive::Entry *m_destination;
    CompressionOptions m_options;
};

/**
357
 * This CopyJob can be used to copy entries within the archive.
358 359 360 361 362 363 364
 * @see Archive::copyFiles for more details.
 */
class KERFUFFLE_EXPORT CopyJob : public Job
{
Q_OBJECT

public:
365
    CopyJob(const QVector<Archive::Entry*> &entries, Archive::Entry *destination, const CompressionOptions& options, ReadWriteArchiveInterface *interface);
366

367
public Q_SLOTS:
368
    void doWork() override;
369

370
protected Q_SLOTS:
371
    void onFinished(bool result) override;
372 373 374

private:
    int m_finishedSignalsCount;
375
    const QVector<Archive::Entry*> m_entries;
376
    Archive::Entry *m_destination;
377 378 379
    CompressionOptions m_options;
};

380
class KERFUFFLE_EXPORT DeleteJob : public Job
381 382 383 384
{
    Q_OBJECT

public:
385
    DeleteJob(const QVector<Archive::Entry*> &files, ReadWriteArchiveInterface *interface);
386

387
public Q_SLOTS:
388
    void doWork() override;
389 390

private:
391
    QVector<Archive::Entry*> m_entries;
392
};
393

394 395 396 397 398
class KERFUFFLE_EXPORT CommentJob : public Job
{
    Q_OBJECT

public:
Elvis Angelaccio's avatar
Elvis Angelaccio committed
399
    CommentJob(const QString& comment, ReadWriteArchiveInterface *interface);
400

401
public Q_SLOTS:
402
    void doWork() override;
403 404 405 406 407

private:
    QString m_comment;
};

Ragnar Thomsen's avatar
Ragnar Thomsen committed
408 409 410 411 412
class KERFUFFLE_EXPORT TestJob : public Job
{
    Q_OBJECT

public:
413
    explicit TestJob(ReadOnlyArchiveInterface *interface);
Ragnar Thomsen's avatar
Ragnar Thomsen committed
414 415
    bool testSucceeded();

416
public Q_SLOTS:
417
    void doWork() override;
Ragnar Thomsen's avatar
Ragnar Thomsen committed
418

419
private Q_SLOTS:
Ragnar Thomsen's avatar
Ragnar Thomsen committed
420
    virtual void onTestSuccess();
421

Ragnar Thomsen's avatar
Ragnar Thomsen committed
422 423 424 425
private:
    bool m_testSuccess;

};
426

427 428 429
} // namespace Kerfuffle

#endif // JOBS_H