File indexing completed on 2024-04-21 16:35:04

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     if (!hasSubjobs()) {
0046         return false;
0047     }
0048 
0049     return subjobs().at(0)->kill();
0050 }
0051 
0052 void CompositeJob::slotResult(KJob *job)
0053 {
0054     if (job->error() == KJob::UserDefinedError) {
0055         qCDebug(SYMMY) << "Job failed:" << job->errorText();
0056         if (task() == Task::Encryption) {
0057             setError(KJob::UserDefinedError);
0058             KMessageBox::error(nullptr, xi18nc("@info", "Encryption operation failed. Please check whether the <application>gpg-agent</application> process is running."));
0059             emitResult();
0060             return;
0061         }
0062 
0063         auto decryptJob = qobject_cast<Symmy::DecryptJob*>(job);
0064         if (decryptJob) {
0065             qCDebug(SYMMY) << "Subjob failed to decrypt" << decryptJob->ciphertextFilename();
0066             m_failedDecryptions << decryptJob->ciphertextFilename();
0067         }
0068     }
0069 
0070     removeSubjob(job);
0071 
0072     if (hasSubjobs()) {
0073         qCDebug(SYMMY) << "Starting next subjob...";
0074         startSubjob();
0075         return;
0076     }
0077 
0078     qCDebug(SYMMY) << "Composite job finished";
0079 
0080     if (!m_failedDecryptions.isEmpty()) {
0081         // Nothing was decrypted, mark the composite job as failed.
0082         if (m_failedDecryptions.size() == filenames().size()) {
0083             setError(KJob::UserDefinedError);
0084             KMessageBox::error(nullptr, xi18nc("@info", "Decryption operation failed. Please check whether the decryption key is correct.<nl/>"
0085                                                         "You should also check whether the <application>gpg-agent</application> process is running."));
0086         } else {
0087             KMessageBox::errorList(nullptr, xi18nc("@info", "Could not decrypt the following ciphertexts.<nl/>Please check whether the decryption key is correct."), m_failedDecryptions);
0088         }
0089     }
0090 
0091     emitResult();
0092 }
0093 
0094 void CompositeJob::slotAccepted()
0095 {
0096     for (const auto &filename : qAsConst(m_filenames)) {
0097         Symmy::Job *job = nullptr;
0098         if (task() == Task::Encryption) {
0099             job = new Symmy::EncryptJob(qobject_cast<KNewPasswordDialog*>(m_passwordDialog)->password(), filename);
0100         } else {
0101             job = new Symmy::DecryptJob(qobject_cast<KPasswordDialog*>(m_passwordDialog)->password(), filename);
0102         }
0103 
0104         addSubjob(job);
0105         connect(job, SIGNAL(percent(KJob*,ulong)), this, SLOT(slotPercent(KJob*,ulong)));
0106     }
0107 
0108     qCDebug(SYMMY) << "Got a passphrase, starting first subjob...";
0109     startSubjob();
0110 }
0111 
0112 void CompositeJob::slotRejected()
0113 {
0114     qCDebug(SYMMY) << "Passphrase dialog rejected.";
0115     setError(KilledJobError);
0116     emitResult();
0117 }
0118 
0119 void CompositeJob::slotStart()
0120 {
0121     if (filenames().isEmpty()) {
0122         emitResult();
0123         return;
0124     }
0125 
0126     qCDebug(SYMMY) << "Starting composite job...";
0127     emit description(this, i18n("Asking Passphrase"));
0128 
0129     if (task() == Task::Encryption) {
0130         auto passwordDialog = new KNewPasswordDialog {};
0131         passwordDialog->setPrompt(i18n("Please supply a password or passphrase to be used as encryption key."));
0132         passwordDialog->setAllowEmptyPasswords(false);
0133         m_passwordDialog = passwordDialog;
0134     } else {
0135         auto passwordDialog = new KPasswordDialog {};
0136         passwordDialog->setPrompt(i18n("Please supply a password or passphrase to be used as decryption key."));
0137         m_passwordDialog = passwordDialog;
0138     }
0139 
0140     connect(m_passwordDialog, &QDialog::accepted, this, &CompositeJob::slotAccepted);
0141     connect(m_passwordDialog, &QDialog::rejected, this, &CompositeJob::slotRejected);
0142     connect(m_passwordDialog, &QDialog::finished, m_passwordDialog, &QObject::deleteLater);
0143 
0144     m_passwordDialog->open();
0145 }
0146 
0147 void CompositeJob::slotPercent(KJob *, unsigned long percent)
0148 {
0149     setPercent(percent);
0150 }
0151 
0152 void CompositeJob::startSubjob()
0153 {
0154     auto job = qobject_cast<Symmy::Job*>(subjobs().at(0));
0155 
0156     if (task() == Task::Encryption) {
0157         emit description(this, i18nc("description of an encryption job", "Encrypting"),
0158                          qMakePair(i18nc("File used as input of the encryption algorithm", "Plaintext"), job->plaintextFilename()),
0159                          qMakePair(i18nc("File created by the encryption algorithm", "Ciphertext"), job->ciphertextFilename()));
0160     } else {
0161         emit description(this, i18nc("description of a decryption job", "Decrypting"),
0162                          qMakePair(i18nc("File used as input of the decryption algorithm", "Ciphertext"), job->ciphertextFilename()),
0163                          qMakePair(i18nc("File created by the decryption algorithm", "Plaintext"), job->plaintextFilename()));
0164     }
0165 
0166     job->start();
0167 }
0168 
0169 QStringList CompositeJob::filenames() const
0170 {
0171     return m_filenames;
0172 }
0173 
0174 CompositeJob::Task CompositeJob::task() const
0175 {
0176     return m_task;
0177 }
0178 
0179 }