File indexing completed on 2024-06-23 05:13:43

0001 /* -*- mode: c++; c-basic-offset:4 -*-
0002     commands/importcrlcommand.cpp
0003 
0004     This file is part of Kleopatra, the KDE keymanager
0005     SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include <config-kleopatra.h>
0011 
0012 #include "importcrlcommand.h"
0013 
0014 #include "command_p.h"
0015 
0016 #include <Libkleo/GnuPG>
0017 
0018 #include <QByteArray>
0019 #include <QFileDialog>
0020 #include <QProcess>
0021 #include <QString>
0022 #include <QTimer>
0023 
0024 #include <KLocalizedString>
0025 
0026 static const int PROCESS_TERMINATE_TIMEOUT = 5000; // milliseconds
0027 
0028 using namespace Kleo;
0029 using namespace Kleo::Commands;
0030 
0031 class ImportCrlCommand::Private : Command::Private
0032 {
0033     friend class ::Kleo::Commands::ImportCrlCommand;
0034     ImportCrlCommand *q_func() const
0035     {
0036         return static_cast<ImportCrlCommand *>(q);
0037     }
0038 
0039 public:
0040     explicit Private(ImportCrlCommand *qq, KeyListController *c);
0041     ~Private() override;
0042 
0043     [[nodiscard]] QString errorString() const
0044     {
0045         return stringFromGpgOutput(errorBuffer);
0046     }
0047 
0048 private:
0049     void init();
0050 #ifndef QT_NO_FILEDIALOG
0051     QStringList getFileNames()
0052     {
0053         // loadcrl can only work with DER encoded files
0054         //   (verified with dirmngr 1.0.3)
0055         const QString filter = QStringLiteral("%1 (*.crl *.arl *-crl.der *-arl.der)").arg(i18n("Certificate Revocation Lists, DER encoded"));
0056         return QFileDialog::getOpenFileNames(parentWidgetOrView(), i18n("Select CRL File to Import"), QString(), filter);
0057     }
0058 #endif // QT_NO_FILEDIALOG
0059 
0060 private:
0061     void slotProcessFinished(int, QProcess::ExitStatus);
0062     void slotProcessReadyReadStandardError();
0063 
0064 private:
0065     QStringList files;
0066     QProcess process;
0067     QByteArray errorBuffer;
0068     bool canceled;
0069     bool firstRun;
0070 };
0071 
0072 ImportCrlCommand::Private *ImportCrlCommand::d_func()
0073 {
0074     return static_cast<Private *>(d.get());
0075 }
0076 const ImportCrlCommand::Private *ImportCrlCommand::d_func() const
0077 {
0078     return static_cast<const Private *>(d.get());
0079 }
0080 
0081 #define d d_func()
0082 #define q q_func()
0083 
0084 ImportCrlCommand::Private::Private(ImportCrlCommand *qq, KeyListController *c)
0085     : Command::Private(qq, c)
0086     , files()
0087     , process()
0088     , errorBuffer()
0089     , canceled(false)
0090     , firstRun(true)
0091 {
0092     process.setProgram(gpgSmPath());
0093     process.setArguments(QStringList() << QStringLiteral("--call-dirmngr") << QStringLiteral("loadcrl"));
0094 }
0095 
0096 ImportCrlCommand::Private::~Private()
0097 {
0098 }
0099 
0100 ImportCrlCommand::ImportCrlCommand(KeyListController *c)
0101     : Command(new Private(this, c))
0102 {
0103     d->init();
0104 }
0105 
0106 ImportCrlCommand::ImportCrlCommand(QAbstractItemView *v, KeyListController *c)
0107     : Command(v, new Private(this, c))
0108 {
0109     d->init();
0110 }
0111 
0112 ImportCrlCommand::ImportCrlCommand(const QStringList &files, KeyListController *c)
0113     : Command(new Private(this, c))
0114 {
0115     d->init();
0116     d->files = files;
0117 }
0118 
0119 ImportCrlCommand::ImportCrlCommand(const QStringList &files, QAbstractItemView *v, KeyListController *c)
0120     : Command(v, new Private(this, c))
0121 {
0122     d->init();
0123     d->files = files;
0124 }
0125 
0126 void ImportCrlCommand::Private::init()
0127 {
0128     connect(&process, &QProcess::finished, q, [this](int exitCode, QProcess::ExitStatus status) {
0129         slotProcessFinished(exitCode, status);
0130     });
0131     connect(&process, &QProcess::readyReadStandardError, q, [this]() {
0132         slotProcessReadyReadStandardError();
0133     });
0134 }
0135 
0136 ImportCrlCommand::~ImportCrlCommand()
0137 {
0138 }
0139 
0140 void ImportCrlCommand::setFiles(const QStringList &files)
0141 {
0142     d->files = files;
0143 }
0144 
0145 void ImportCrlCommand::doStart()
0146 {
0147 #ifndef QT_NO_FILEDIALOG
0148     if (d->files.empty()) {
0149         d->files = d->getFileNames();
0150     }
0151 #endif // QT_NO_FILEDIALOG
0152     if (d->files.empty()) {
0153         Q_EMIT canceled();
0154         d->finished();
0155         return;
0156     }
0157 
0158     auto args = d->process.arguments();
0159     if (!d->firstRun) {
0160         /* remove the last file */
0161         args.pop_back();
0162     }
0163     args << d->files.takeFirst();
0164 
0165     d->process.setArguments(args);
0166 
0167     d->process.start();
0168 
0169     d->firstRun = false;
0170 
0171     if (!d->process.waitForStarted()) {
0172         d->error(i18n("Unable to start process dirmngr. "
0173                       "Please check your installation."),
0174                  i18n("Clear CRL Cache Error"));
0175         d->finished();
0176     }
0177 }
0178 
0179 void ImportCrlCommand::doCancel()
0180 {
0181     d->canceled = true;
0182     if (d->process.state() != QProcess::NotRunning) {
0183         d->process.terminate();
0184         QTimer::singleShot(PROCESS_TERMINATE_TIMEOUT, &d->process, &QProcess::kill);
0185     }
0186 }
0187 
0188 void ImportCrlCommand::Private::slotProcessFinished(int code, QProcess::ExitStatus status)
0189 {
0190     if (!canceled) {
0191         if (status == QProcess::CrashExit)
0192             error(i18n("The GpgSM process that tried to import the CRL file "
0193                        "ended prematurely because of an unexpected error. "
0194                        "Please check the output of gpgsm --call-dirmngr loadcrl <filename> for details."),
0195                   i18n("Import CRL Error"));
0196         else if (code)
0197             error(i18n("An error occurred while trying to import the CRL file. "
0198                        "The output from gpgsm was:\n%1",
0199                        errorString()),
0200                   i18n("Import CRL Error"));
0201         else if (files.empty())
0202             information(i18n("CRL file imported successfully."), i18n("Import CRL Finished"));
0203     }
0204     if (!files.empty()) {
0205         q->doStart();
0206         return;
0207     }
0208     finished();
0209 }
0210 
0211 void ImportCrlCommand::Private::slotProcessReadyReadStandardError()
0212 {
0213     errorBuffer += process.readAllStandardError();
0214 }
0215 
0216 #undef d
0217 #undef q
0218 
0219 #include "moc_importcrlcommand.cpp"