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"