File indexing completed on 2024-05-19 05:47:12

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