jobs.cpp 22.1 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
#include "jobs.h"
30
#include "archiveentry.h"
31
#include "ark_debug.h"
32

33
#include <QDir>
34
#include <QDirIterator>
35
#include <QFileInfo>
36
#include <QRegularExpression>
37
#include <QThread>
38
#include <QTimer>
Elvis Angelaccio's avatar
Elvis Angelaccio committed
39
#include <QUrl>
40

Elvis Angelaccio's avatar
Elvis Angelaccio committed
41
#include <KIO/RenameDialog>
42
#include <KLocalizedString>
43

44 45
namespace Kerfuffle
{
46

47 48
class Job::Private : public QThread
{
Elvis Angelaccio's avatar
Elvis Angelaccio committed
49 50
    Q_OBJECT

51
public:
52 53 54 55 56 57
    Private(Job *job, QObject *parent = 0)
        : QThread(parent)
        , q(job)
    {
    }

58
    virtual void run() Q_DECL_OVERRIDE;
59

60
private:
61 62 63 64 65
    Job *q;
};

void Job::Private::run()
{
66
    q->doWork();
67 68
}

Elvis Angelaccio's avatar
Elvis Angelaccio committed
69
Job::Job(Archive *archive, ReadOnlyArchiveInterface *interface)
Elvis Angelaccio's avatar
Elvis Angelaccio committed
70
    : KJob()
Elvis Angelaccio's avatar
Elvis Angelaccio committed
71
    , m_archive(archive)
72
    , m_archiveInterface(interface)
73
    , d(new Private(this))
74 75 76 77
{
    setCapabilities(KJob::Killable);
}

Elvis Angelaccio's avatar
Elvis Angelaccio committed
78 79 80 81 82 83 84 85
Job::Job(Archive *archive)
    : Job(archive, Q_NULLPTR)
{}

Job::Job(ReadOnlyArchiveInterface *interface)
    : Job(Q_NULLPTR, interface)
{}

86 87
Job::~Job()
{
88 89 90
    qDeleteAll(m_archiveEntries);
    m_archiveEntries.clear();

91 92
    if (d->isRunning()) {
        d->wait();
93 94
    }

95
    delete d;
96
}
97

98 99
ReadOnlyArchiveInterface *Job::archiveInterface()
{
Elvis Angelaccio's avatar
Elvis Angelaccio committed
100 101 102 103 104 105
    // Use the archive interface.
    if (archive()) {
        return archive()->interface();
    }

    // Use the interface passed to this job (e.g. JSONArchiveInterface in jobstest.cpp).
106 107 108
    return m_archiveInterface;
}

Elvis Angelaccio's avatar
Elvis Angelaccio committed
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
Archive *Job::archive() const
{
    return m_archive;
}

QString Job::errorString() const
{
    if (!errorText().isEmpty()) {
        return errorText();
    }

    if (archive()) {
        if (archive()->error() == NoPlugin) {
            return i18n("No suitable plugin found. Ark does not seem to support this file type.");
        }

        if (archive()->error() == FailedPlugin) {
            return i18n("Failed to load a suitable plugin. Make sure any executables needed to handle the archive type are installed.");
        }
    }

    return QString();
}

133 134
void Job::start()
{
135
    jobTimer.start();
136

Elvis Angelaccio's avatar
Elvis Angelaccio committed
137 138 139 140 141 142 143 144
    // We have an archive but it's not valid, nothing to do.
    if (archive() && !archive()->isValid()) {
        QTimer::singleShot(0, this, [=]() {
            onFinished(false);
        });
        return;
    }

145
    if (archiveInterface()->waitForFinishedSignal()) {
146 147 148 149 150 151
        // CLI-based interfaces run a QProcess, no need to use threads.
        QTimer::singleShot(0, this, &Job::doWork);
    } else {
        // Run the job in another thread.
        d->start();
    }
152 153
}

154 155
void Job::connectToArchiveInterfaceSignals()
{
Laurent Montel's avatar
Laurent Montel committed
156 157 158 159 160 161
    connect(archiveInterface(), &ReadOnlyArchiveInterface::cancelled, this, &Job::onCancelled);
    connect(archiveInterface(), &ReadOnlyArchiveInterface::error, this, &Job::onError);
    connect(archiveInterface(), &ReadOnlyArchiveInterface::entry, this, &Job::onEntry);
    connect(archiveInterface(), &ReadOnlyArchiveInterface::entryRemoved, this, &Job::onEntryRemoved);
    connect(archiveInterface(), &ReadOnlyArchiveInterface::progress, this, &Job::onProgress);
    connect(archiveInterface(), &ReadOnlyArchiveInterface::info, this, &Job::onInfo);
162
    connect(archiveInterface(), &ReadOnlyArchiveInterface::finished, this, &Job::onFinished);
Laurent Montel's avatar
Laurent Montel committed
163
    connect(archiveInterface(), &ReadOnlyArchiveInterface::userQuery, this, &Job::onUserQuery);
164 165
}

166 167
void Job::onCancelled()
{
168
    qCDebug(ARK) << "Cancelled emitted";
169 170 171
    setError(KJob::KilledJobError);
}

172 173
void Job::onError(const QString & message, const QString & details)
{
174
    Q_UNUSED(details)
175

176
    qCDebug(ARK) << "Error emitted:" << message;
177
    setError(KJob::UserDefinedError);
178 179 180
    setErrorText(message);
}

181
void Job::onEntry(Archive::Entry *entry)
182
{
183
    emit newEntry(entry);
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
}

void Job::onProgress(double value)
{
    setPercent(static_cast<unsigned long>(100.0*value));
}

void Job::onInfo(const QString& info)
{
    emit infoMessage(this, info);
}

void Job::onEntryRemoved(const QString & path)
{
    emit entryRemoved(path);
}

void Job::onFinished(bool result)
{
203
    qCDebug(ARK) << "Job finished, result:" << result << ", time:" << jobTimer.elapsed() << "ms";
204

Elvis Angelaccio's avatar
Elvis Angelaccio committed
205 206 207 208
    if (archive() && !archive()->isValid()) {
        setError(KJob::UserDefinedError);
    }

209 210 211 212 213 214 215 216 217 218
    emitResult();
}

void Job::onUserQuery(Query *query)
{
    emit userQuery(query);
}

bool Job::doKill()
{
219 220 221 222 223
    if (d->isRunning()) {
        d->requestInterruption();
        d->wait();
    }

224
    bool ret = archiveInterface()->doKill();
225
    if (!ret) {
226
        qCWarning(ARK) << "Killing does not seem to be supported here.";
227
    }
228 229 230
    return ret;
}

Elvis Angelaccio's avatar
Elvis Angelaccio committed
231 232
LoadJob::LoadJob(Archive *archive, ReadOnlyArchiveInterface *interface)
    : Job(archive, interface)
233 234 235
    , m_isSingleFolderArchive(true)
    , m_isPasswordProtected(false)
    , m_extractedFilesSize(0)
236 237
    , m_dirCount(0)
    , m_filesCount(0)
238
{
Elvis Angelaccio's avatar
Elvis Angelaccio committed
239 240
    qCDebug(ARK) << "LoadJob started";
    connect(this, &LoadJob::newEntry, this, &LoadJob::onNewEntry);
241 242
}

Elvis Angelaccio's avatar
Elvis Angelaccio committed
243 244 245 246 247 248 249 250 251
LoadJob::LoadJob(Archive *archive)
    : LoadJob(archive, Q_NULLPTR)
{}

LoadJob::LoadJob(ReadOnlyArchiveInterface *interface)
    : LoadJob(Q_NULLPTR, interface)
{}

void LoadJob::doWork()
252
{
253
    emit description(this, i18n("Loading archive"), qMakePair(i18n("Archive"), archiveInterface()->filename()));
254
    connectToArchiveInterfaceSignals();
Elvis Angelaccio's avatar
Elvis Angelaccio committed
255

256
    bool ret = archiveInterface()->list();
257

258
    if (!archiveInterface()->waitForFinishedSignal()) {
259
        onFinished(ret);
260
    }
261 262
}

Elvis Angelaccio's avatar
Elvis Angelaccio committed
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
void LoadJob::onFinished(bool result)
{
    if (archive()) {
        archive()->setProperty("unpackedSize", extractedFilesSize());
        archive()->setProperty("isSingleFolder", isSingleFolderArchive());
        const auto name = subfolderName().isEmpty() ? archive()->completeBaseName() : subfolderName();
        archive()->setProperty("subfolderName", name);
        if (isPasswordProtected()) {
            archive()->setProperty("encryptionType",  archive()->password().isEmpty() ? Archive::Encrypted : Archive::HeaderEncrypted);
        }
    }

    Job::onFinished(result);
}

qlonglong LoadJob::extractedFilesSize() const
279 280 281 282
{
    return m_extractedFilesSize;
}

Elvis Angelaccio's avatar
Elvis Angelaccio committed
283
bool LoadJob::isPasswordProtected() const
284 285 286 287
{
    return m_isPasswordProtected;
}

Elvis Angelaccio's avatar
Elvis Angelaccio committed
288
bool LoadJob::isSingleFolderArchive() const
289
{
290 291 292 293
    if (m_filesCount == 1 && m_dirCount == 0) {
        return false;
    }

294 295 296
    return m_isSingleFolderArchive;
}

Elvis Angelaccio's avatar
Elvis Angelaccio committed
297
void LoadJob::onNewEntry(const Archive::Entry *entry)
298
{
299 300
    m_extractedFilesSize += entry->property("size").toLongLong();
    m_isPasswordProtected |= entry->property("isPasswordProtected").toBool();
301

302
    if (entry->isDir()) {
303 304 305 306 307
        m_dirCount++;
    } else {
        m_filesCount++;
    }

308
    if (m_isSingleFolderArchive) {
309
        // RPM filenames have the ./ prefix, and "." would be detected as the subfolder name, so we remove it.
310
        const QString fullPath = entry->fullPath().replace(QRegularExpression(QStringLiteral("^\\./")), QString());
311
        const QString basePath = fullPath.split(QLatin1Char('/')).at(0);
312

313 314 315
        if (m_basePath.isEmpty()) {
            m_basePath = basePath;
            m_subfolderName = basePath;
316
        } else {
317 318 319 320
            if (m_basePath != basePath) {
                m_isSingleFolderArchive = false;
                m_subfolderName.clear();
            }
321 322 323 324
        }
    }
}

Elvis Angelaccio's avatar
Elvis Angelaccio committed
325
QString LoadJob::subfolderName() const
326
{
327 328 329 330
    if (!isSingleFolderArchive()) {
        return QString();
    }

331 332 333
    return m_subfolderName;
}

Elvis Angelaccio's avatar
Elvis Angelaccio committed
334 335 336 337 338 339 340 341 342 343 344 345 346 347
BatchExtractJob::BatchExtractJob(LoadJob *loadJob, const QString &destination, bool autoSubfolder, bool preservePaths)
    : Job(loadJob->archive())
    , m_loadJob(loadJob)
    , m_destination(destination)
    , m_autoSubfolder(autoSubfolder)
    , m_preservePaths(preservePaths)
{
    qCDebug(ARK) << "BatchExtractJob created";
}

void BatchExtractJob::doWork()
{
    connect(m_loadJob, &KJob::result, this, &BatchExtractJob::slotLoadingFinished);

348
    // Forward LoadJob's signals.
Elvis Angelaccio's avatar
Elvis Angelaccio committed
349 350 351 352 353 354 355 356
    connect(m_loadJob, &Kerfuffle::Job::newEntry, this, &BatchExtractJob::newEntry);
    connect(m_loadJob, &Kerfuffle::Job::userQuery, this, &BatchExtractJob::userQuery);
    m_loadJob->start();
}

void BatchExtractJob::slotLoadingFinished(KJob *job)
{
    if (job->error()) {
357 358 359
        // Forward errors as well.
        onError(job->errorString(), QString());
        onFinished(false);
Elvis Angelaccio's avatar
Elvis Angelaccio committed
360 361 362 363 364 365 366
        return;
    }

    // Now we can start extraction.
    setupDestination();

    Kerfuffle::ExtractionOptions options;
367
    options.setPreservePaths(m_preservePaths);
Elvis Angelaccio's avatar
Elvis Angelaccio committed
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404

    auto extractJob = archive()->extractFiles({}, m_destination, options);
    if (extractJob) {
        connect(extractJob, &KJob::result, this, &BatchExtractJob::emitResult);
        connect(extractJob, &Kerfuffle::Job::userQuery, this, &BatchExtractJob::userQuery);
        extractJob->start();
    } else {
        emitResult();
    }
}

void BatchExtractJob::setupDestination()
{
    const bool isSingleFolderRPM = (archive()->isSingleFolder() &&
                                   (archive()->mimeType().name() == QLatin1String("application/x-rpm")));

    if (m_autoSubfolder && (!archive()->isSingleFolder() || isSingleFolderRPM)) {
        const QDir d(m_destination);
        QString subfolderName = archive()->subfolderName();

        // Special case for single folder RPM archives.
        // We don't want the autodetected folder to have a meaningless "usr" name.
        if (isSingleFolderRPM && subfolderName == QStringLiteral("usr")) {
            qCDebug(ARK) << "Detected single folder RPM archive. Using archive basename as subfolder name";
            subfolderName = QFileInfo(archive()->fileName()).completeBaseName();
        }

        if (d.exists(subfolderName)) {
            subfolderName = KIO::suggestName(QUrl::fromUserInput(m_destination, QString(), QUrl::AssumeLocalFile), subfolderName);
        }

        d.mkdir(subfolderName);

        m_destination += QLatin1Char( '/' ) + subfolderName;
    }
}

405
CreateJob::CreateJob(Archive *archive, const QVector<Archive::Entry*> &entries, const CompressionOptions &options)
Elvis Angelaccio's avatar
Elvis Angelaccio committed
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
    : Job(archive)
    , m_entries(entries)
    , m_options(options)
{
    qCDebug(ARK) << "CreateJob created";
}

void CreateJob::enableEncryption(const QString &password, bool encryptHeader)
{
    archive()->encrypt(password, encryptHeader);
}

void CreateJob::setMultiVolume(bool isMultiVolume)
{
    archive()->setMultiVolume(isMultiVolume);
}

void CreateJob::doWork()
{
    auto addJob = archive()->addFiles(m_entries, new Archive::Entry(this), m_options);

    if (addJob) {
        connect(addJob, &KJob::result, this, &CreateJob::emitResult);
        addJob->start();
    } else {
        emitResult();
    }
}

435
ExtractJob::ExtractJob(const QVector<Archive::Entry*> &entries, const QString &destinationDir, const ExtractionOptions &options, ReadOnlyArchiveInterface *interface)
Elvis Angelaccio's avatar
Elvis Angelaccio committed
436
    : Job(interface)
437
    , m_entries(entries)
438 439
    , m_destinationDir(destinationDir)
    , m_options(options)
440
{
441
    qCDebug(ARK) << "ExtractJob created";
442 443 444 445 446
}

void ExtractJob::doWork()
{
    QString desc;
447
    if (m_entries.count() == 0) {
448 449
        desc = i18n("Extracting all files");
    } else {
450
        desc = i18np("Extracting one file", "Extracting %1 files", m_entries.count());
451
    }
452
    emit description(this, desc, qMakePair(i18n("Archive"), archiveInterface()->filename()));
453

454 455 456 457 458 459 460
    QFileInfo destDirInfo(m_destinationDir);
    if (destDirInfo.isDir() && (!destDirInfo.isWritable() || !destDirInfo.isExecutable())) {
        onError(xi18n("Could not write to destination <filename>%1</filename>.<nl/>Check whether you have sufficient permissions.", m_destinationDir), QString());
        onFinished(false);
        return;
    }

461
    connectToArchiveInterfaceSignals();
462

463
    qCDebug(ARK) << "Starting extraction with" << m_entries.count() << "selected files."
464
             << m_entries
465 466
             << "Destination dir:" << m_destinationDir
             << "Options:" << m_options;
467

468
    bool ret = archiveInterface()->extractFiles(m_entries, m_destinationDir, m_options);
469

470
    if (!archiveInterface()->waitForFinishedSignal()) {
471
        onFinished(ret);
472
    }
473 474
}

475 476 477 478 479
QString ExtractJob::destinationDirectory() const
{
    return m_destinationDir;
}

480 481 482 483 484
ExtractionOptions ExtractJob::extractionOptions() const
{
    return m_options;
}

485
TempExtractJob::TempExtractJob(Archive::Entry *entry, bool passwordProtectedHint, ReadOnlyArchiveInterface *interface)
486
    : Job(interface)
487
    , m_entry(entry)
488 489
    , m_passwordProtectedHint(passwordProtectedHint)
{
490
    m_tmpExtractDir = new QTemporaryDir();
491 492 493 494
}

QString TempExtractJob::validatedFilePath() const
{
495
    QString path = extractionDir() + QLatin1Char('/') + m_entry->fullPath();
496 497 498 499 500 501 502 503 504 505 506 507 508 509

    // Make sure a maliciously crafted archive with parent folders named ".." do
    // not cause the previewed file path to be located outside the temporary
    // directory, resulting in a directory traversal issue.
    path.remove(QStringLiteral("../"));

    return path;
}

ExtractionOptions TempExtractJob::extractionOptions() const
{
    ExtractionOptions options;

    if (m_passwordProtectedHint) {
510
        options.setEncryptedArchiveHint(true);
511 512 513 514 515
    }

    return options;
}

516 517 518 519 520
QTemporaryDir *TempExtractJob::tempDir() const
{
    return m_tmpExtractDir;
}

521 522 523 524 525 526
void TempExtractJob::doWork()
{
    emit description(this, i18n("Extracting one file"));

    connectToArchiveInterfaceSignals();

527
    qCDebug(ARK) << "Extracting:" << m_entry;
528

529
    bool ret = archiveInterface()->extractFiles({m_entry}, extractionDir(), extractionOptions());
530 531 532 533 534 535

    if (!archiveInterface()->waitForFinishedSignal()) {
        onFinished(ret);
    }
}

536
QString TempExtractJob::extractionDir() const
537
{
538
    return m_tmpExtractDir->path();
539 540
}

541 542
PreviewJob::PreviewJob(Archive::Entry *entry, bool passwordProtectedHint, ReadOnlyArchiveInterface *interface)
    : TempExtractJob(entry, passwordProtectedHint, interface)
543
{
544
    qCDebug(ARK) << "PreviewJob started";
545 546
}

547 548
OpenJob::OpenJob(Archive::Entry *entry, bool passwordProtectedHint, ReadOnlyArchiveInterface *interface)
    : TempExtractJob(entry, passwordProtectedHint, interface)
549 550 551 552
{
    qCDebug(ARK) << "OpenJob started";
}

553 554
OpenWithJob::OpenWithJob(Archive::Entry *entry, bool passwordProtectedHint, ReadOnlyArchiveInterface *interface)
    : OpenJob(entry, passwordProtectedHint, interface)
555 556 557 558
{
    qCDebug(ARK) << "OpenWithJob started";
}

559
AddJob::AddJob(const QVector<Archive::Entry*> &entries, const Archive::Entry *destination, const CompressionOptions& options, ReadWriteArchiveInterface *interface)
Elvis Angelaccio's avatar
Elvis Angelaccio committed
560
    : Job(interface)
561
    , m_entries(entries)
562
    , m_destination(destination)
563
    , m_options(options)
564
{
565
    qCDebug(ARK) << "AddJob started";
566 567 568 569
}

void AddJob::doWork()
{
570
    // Set current dir.
571
    const QString globalWorkDir = m_options.globalWorkDir();
572 573 574 575 576 577 578
    const QDir workDir = globalWorkDir.isEmpty() ? QDir::current() : QDir(globalWorkDir);
    if (!globalWorkDir.isEmpty()) {
        qCDebug(ARK) << "GlobalWorkDir is set, changing dir to " << globalWorkDir;
        m_oldWorkingDir = QDir::currentPath();
        QDir::setCurrent(globalWorkDir);
    }

579 580 581 582
    // Count total number of entries to be added.
    qulonglong totalCount = 0;
    QElapsedTimer timer;
    timer.start();
583
    foreach (const Archive::Entry* entry, m_entries) {
584
        totalCount++;
585
        if (QFileInfo(entry->fullPath()).isDir()) {
586
            QDirIterator it(entry->fullPath(), QDir::AllEntries | QDir::Readable | QDir::Hidden | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
587 588 589 590 591 592 593
            while (it.hasNext()) {
                it.next();
                totalCount++;
            }
        }
    }

594
    qCDebug(ARK) << "AddJob: going to add" << totalCount << "entries, counted in" << timer.elapsed() << "ms";
595 596 597

    QString desc = i18np("Adding a file", "Adding %1 files", totalCount);
    emit description(this, desc, qMakePair(i18n("Archive"), archiveInterface()->filename()));
598 599 600 601 602 603

    ReadWriteArchiveInterface *m_writeInterface =
        qobject_cast<ReadWriteArchiveInterface*>(archiveInterface());

    Q_ASSERT(m_writeInterface);

604
    // The file paths must be relative to GlobalWorkDir.
605
    foreach (Archive::Entry *entry, m_entries) {
606 607
        // #191821: workDir must be used instead of QDir::current()
        //          so that symlinks aren't resolved automatically
608
        const QString &fullPath = entry->fullPath();
609
        QString relativePath = workDir.relativeFilePath(fullPath);
610

611
        if (fullPath.endsWith(QLatin1Char('/'))) {
612 613 614
            relativePath += QLatin1Char('/');
        }

615
        entry->setFullPath(relativePath);
616 617
    }

618
    connectToArchiveInterfaceSignals();
619
    bool ret = m_writeInterface->addFiles(m_entries, m_destination, m_options, totalCount);
620

621
    if (!archiveInterface()->waitForFinishedSignal()) {
622
        onFinished(ret);
623
    }
624 625
}

626 627 628 629 630 631 632 633 634
void AddJob::onFinished(bool result)
{
    if (!m_oldWorkingDir.isEmpty()) {
        QDir::setCurrent(m_oldWorkingDir);
    }

    Job::onFinished(result);
}

635
MoveJob::MoveJob(const QVector<Archive::Entry*> &entries, Archive::Entry *destination, const CompressionOptions& options , ReadWriteArchiveInterface *interface)
636 637 638 639 640 641 642 643 644 645 646 647 648
    : Job(interface)
    , m_finishedSignalsCount(0)
    , m_entries(entries)
    , m_destination(destination)
    , m_options(options)
{
    qCDebug(ARK) << "MoveJob started";
}

void MoveJob::doWork()
{
    qCDebug(ARK) << "MoveJob: going to move" << m_entries.count() << "file(s)";

649 650
    QString desc = i18np("Moving a file", "Moving %1 files", m_entries.count());
    emit description(this, desc, qMakePair(i18n("Archive"), archiveInterface()->filename()));
651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672

    ReadWriteArchiveInterface *m_writeInterface =
        qobject_cast<ReadWriteArchiveInterface*>(archiveInterface());

    Q_ASSERT(m_writeInterface);

    connectToArchiveInterfaceSignals();
    bool ret = m_writeInterface->moveFiles(m_entries, m_destination, m_options);

    if (!archiveInterface()->waitForFinishedSignal()) {
        onFinished(ret);
    }
}

void MoveJob::onFinished(bool result)
{
    m_finishedSignalsCount++;
    if (m_finishedSignalsCount == archiveInterface()->moveRequiredSignals()) {
        Job::onFinished(result);
    }
}

673
CopyJob::CopyJob(const QVector<Archive::Entry*> &entries, Archive::Entry *destination, const CompressionOptions &options, ReadWriteArchiveInterface *interface)
674 675 676 677 678 679 680 681 682 683 684 685 686
    : Job(interface)
    , m_finishedSignalsCount(0)
    , m_entries(entries)
    , m_destination(destination)
    , m_options(options)
{
    qCDebug(ARK) << "CopyJob started";
}

void CopyJob::doWork()
{
    qCDebug(ARK) << "CopyJob: going to copy" << m_entries.count() << "file(s)";

687 688
    QString desc = i18np("Copying a file", "Copying %1 files", m_entries.count());
    emit description(this, desc, qMakePair(i18n("Archive"), archiveInterface()->filename()));
689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710

    ReadWriteArchiveInterface *m_writeInterface =
        qobject_cast<ReadWriteArchiveInterface*>(archiveInterface());

    Q_ASSERT(m_writeInterface);

    connectToArchiveInterfaceSignals();
    bool ret = m_writeInterface->copyFiles(m_entries, m_destination, m_options);

    if (!archiveInterface()->waitForFinishedSignal()) {
        onFinished(ret);
    }
}

void CopyJob::onFinished(bool result)
{
    m_finishedSignalsCount++;
    if (m_finishedSignalsCount == archiveInterface()->copyRequiredSignals()) {
        Job::onFinished(result);
    }
}

711
DeleteJob::DeleteJob(const QVector<Archive::Entry*> &entries, ReadWriteArchiveInterface *interface)
Elvis Angelaccio's avatar
Elvis Angelaccio committed
712
    : Job(interface)
713
    , m_entries(entries)
714 715 716 717 718
{
}

void DeleteJob::doWork()
{
719 720
    QString desc = i18np("Deleting a file from the archive", "Deleting %1 files", m_entries.count());
    emit description(this, desc, qMakePair(i18n("Archive"), archiveInterface()->filename()));
721 722

    ReadWriteArchiveInterface *m_writeInterface =
723
        qobject_cast<ReadWriteArchiveInterface*>(archiveInterface());
724 725 726

    Q_ASSERT(m_writeInterface);

727
    connectToArchiveInterfaceSignals();
728
    bool ret = m_writeInterface->deleteFiles(m_entries);
729

730
    if (!archiveInterface()->waitForFinishedSignal()) {
731
        onFinished(ret);
732
    }
733
}
734

Elvis Angelaccio's avatar
Elvis Angelaccio committed
735 736
CommentJob::CommentJob(const QString& comment, ReadWriteArchiveInterface *interface)
    : Job(interface)
737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
    , m_comment(comment)
{
}

void CommentJob::doWork()
{
    emit description(this, i18n("Adding comment"));

    ReadWriteArchiveInterface *m_writeInterface =
        qobject_cast<ReadWriteArchiveInterface*>(archiveInterface());

    Q_ASSERT(m_writeInterface);

    connectToArchiveInterfaceSignals();
    bool ret = m_writeInterface->addComment(m_comment);

    if (!archiveInterface()->waitForFinishedSignal()) {
        onFinished(ret);
    }
}

Elvis Angelaccio's avatar
Elvis Angelaccio committed
758 759
TestJob::TestJob(ReadOnlyArchiveInterface *interface)
    : Job(interface)
Ragnar Thomsen's avatar
Ragnar Thomsen committed
760 761 762 763 764 765 766 767
{
    m_testSuccess = false;
}

void TestJob::doWork()
{
    qCDebug(ARK) << "TestJob started";

768 769
    emit description(this, i18n("Testing archive"), qMakePair(i18n("Archive"), archiveInterface()->filename()));

Ragnar Thomsen's avatar
Ragnar Thomsen committed
770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
    connectToArchiveInterfaceSignals();
    connect(archiveInterface(), &ReadOnlyArchiveInterface::testSuccess, this, &TestJob::onTestSuccess);

    bool ret = archiveInterface()->testArchive();

    if (!archiveInterface()->waitForFinishedSignal()) {
        onFinished(ret);
    }
}

void TestJob::onTestSuccess()
{
    m_testSuccess = true;
}

bool TestJob::testSucceeded()
{
    return m_testSuccess;
}

790
} // namespace Kerfuffle
791

Elvis Angelaccio's avatar
Elvis Angelaccio committed
792
#include "jobs.moc"