File indexing completed on 2024-04-28 05:53:43

0001 /*
0002  * SPDX-FileCopyrightText: 2017 Elvis Angelaccio <elvis.angelaccio@kde.org>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-or-later
0005  *
0006  */
0007 
0008 #include "compositejob.h"
0009 #include "decryptjob.h"
0010 #include "encryptjob.h"
0011 #include "symmydebug.h"
0012 
0013 #include <KIO/JobTracker>
0014 #include <KJobTrackerInterface>
0015 #include <KLocalizedString>
0016 #include <KMessageBox>
0017 #include <KNewPasswordDialog>
0018 #include <KPasswordDialog>
0019 
0020 #include <QTimer>
0021 
0022 namespace Symmy
0023 {
0024 
0025 CompositeJob::CompositeJob(const QStringList &filenames, Task task)
0026     : KCompositeJob {}
0027     , m_filenames {filenames}
0028     , m_task {task}
0029 {
0030     setCapabilities(Killable);
0031     KIO::getJobTracker()->registerJob(this);
0032 }
0033 
0034 CompositeJob::~CompositeJob()
0035 {
0036 }
0037 
0038 void CompositeJob::start()
0039 {
0040     QTimer::singleShot(0, this, &CompositeJob::slotStart);
0041 }
0042 
0043 bool CompositeJob::doKill()
0044 {
0045     qCDebug(SYMMY) << "Killing composite job...";
0046 
0047     if (!hasSubjobs()) {
0048         const bool canBeKilled = !m_passwordDialog.isNull() && m_passwordDialog->isVisible();
0049         return canBeKilled;
0050     }
0051 
0052     return subjobs().at(0)->kill();
0053 }
0054 
0055 void CompositeJob::slotResult(KJob *job)
0056 {
0057     if (job->error() == KJob::UserDefinedError) {
0058         qCDebug(SYMMY) << "Job failed:" << job->errorText();
0059         if (task() == Task::Encryption) {
0060             setError(KJob::UserDefinedError);
0061             KMessageBox::error(nullptr, xi18nc("@info", "Encryption operation failed. Please check whether the <application>gpg-agent</application> process is running."));
0062             emitResult();
0063             return;
0064         }
0065 
0066         auto decryptJob = qobject_cast<Symmy::DecryptJob*>(job);
0067         if (decryptJob) {
0068             qCDebug(SYMMY) << "Subjob failed to decrypt" << decryptJob->ciphertextFilename();
0069             m_failedDecryptions << decryptJob->ciphertextFilename();
0070         }
0071     }
0072 
0073     removeSubjob(job);
0074 
0075     if (hasSubjobs()) {
0076         qCDebug(SYMMY) << "Starting next subjob...";
0077         startSubjob();
0078         return;
0079     }
0080 
0081     qCDebug(SYMMY) << "Composite job finished";
0082 
0083     if (!m_failedDecryptions.isEmpty()) {
0084         // Nothing was decrypted, mark the composite job as failed.
0085         if (m_failedDecryptions.size() == filenames().size()) {
0086             setError(KJob::UserDefinedError);
0087             KMessageBox::error(nullptr, xi18nc("@info", "Decryption operation failed. Please check whether the decryption key is correct.<nl/>"
0088                                                         "You should also check whether the <application>gpg-agent</application> process is running."));
0089         } else {
0090             KMessageBox::errorList(nullptr, xi18nc("@info", "Could not decrypt the following ciphertexts.<nl/>Please check whether the decryption key is correct."), m_failedDecryptions);
0091         }
0092     }
0093 
0094     emitResult();
0095 }
0096 
0097 void CompositeJob::slotAccepted()
0098 {
0099     for (const auto &filename : qAsConst(m_filenames)) {
0100         Symmy::Job *job = nullptr;
0101         if (task() == Task::Encryption) {
0102             job = new Symmy::EncryptJob(qobject_cast<KNewPasswordDialog*>(m_passwordDialog)->password(), filename);
0103         } else {
0104             job = new Symmy::DecryptJob(qobject_cast<KPasswordDialog*>(m_passwordDialog)->password(), filename);
0105         }
0106 
0107         addSubjob(job);
0108         connect(job, SIGNAL(percent(KJob*,ulong)), this, SLOT(slotPercent(KJob*,ulong)));
0109     }
0110 
0111     qCDebug(SYMMY) << "Got a passphrase, starting first subjob...";
0112     startSubjob();
0113 }
0114 
0115 void CompositeJob::slotRejected()
0116 {
0117     qCDebug(SYMMY) << "Passphrase dialog rejected.";
0118     setError(KilledJobError);
0119     emitResult();
0120 }
0121 
0122 void CompositeJob::slotStart()
0123 {
0124     if (filenames().isEmpty()) {
0125         emitResult();
0126         return;
0127     }
0128 
0129     qCDebug(SYMMY) << "Starting composite job...";
0130     emit description(this, i18n("Asking Passphrase"));
0131 
0132     if (task() == Task::Encryption) {
0133         auto passwordDialog = new KNewPasswordDialog {};
0134         passwordDialog->setPrompt(i18n("Please supply a password or passphrase to be used as encryption key."));
0135         passwordDialog->setAllowEmptyPasswords(false);
0136         m_passwordDialog = passwordDialog;
0137     } else {
0138         auto passwordDialog = new KPasswordDialog {};
0139         passwordDialog->setPrompt(i18n("Please supply a password or passphrase to be used as decryption key."));
0140         m_passwordDialog = passwordDialog;
0141     }
0142 
0143     connect(m_passwordDialog, &QDialog::accepted, this, &CompositeJob::slotAccepted);
0144     connect(m_passwordDialog, &QDialog::rejected, this, &CompositeJob::slotRejected);
0145     connect(m_passwordDialog, &QDialog::finished, m_passwordDialog, &QObject::deleteLater);
0146 
0147     m_passwordDialog->open();
0148 }
0149 
0150 void CompositeJob::slotPercent(KJob *, unsigned long percent)
0151 {
0152     setPercent(percent);
0153 }
0154 
0155 void CompositeJob::startSubjob()
0156 {
0157     auto job = qobject_cast<Symmy::Job*>(subjobs().at(0));
0158 
0159     if (task() == Task::Encryption) {
0160         emit description(this, i18nc("description of an encryption job", "Encrypting"),
0161                          qMakePair(i18nc("File used as input of the encryption algorithm", "Plaintext"), job->plaintextFilename()),
0162                          qMakePair(i18nc("File created by the encryption algorithm", "Ciphertext"), job->ciphertextFilename()));
0163     } else {
0164         emit description(this, i18nc("description of a decryption job", "Decrypting"),
0165                          qMakePair(i18nc("File used as input of the decryption algorithm", "Ciphertext"), job->ciphertextFilename()),
0166                          qMakePair(i18nc("File created by the decryption algorithm", "Plaintext"), job->plaintextFilename()));
0167     }
0168 
0169     job->start();
0170 }
0171 
0172 QStringList CompositeJob::filenames() const
0173 {
0174     return m_filenames;
0175 }
0176 
0177 CompositeJob::Task CompositeJob::task() const
0178 {
0179     return m_task;
0180 }
0181 
0182 }