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

0001 /* -*- mode: c++; c-basic-offset:4 -*-
0002     importcertificatefromfilecommand.cpp
0003 
0004     This file is part of Kleopatra, the KDE keymanager
0005     SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include <config-kleopatra.h>
0011 
0012 #include "importcertificatefromfilecommand.h"
0013 #include "importcertificatescommand_p.h"
0014 
0015 #include <kleopatra_debug.h>
0016 
0017 #include <QGpgME/Protocol>
0018 
0019 #include <Libkleo/Classify>
0020 
0021 #include <gpgme++/global.h>
0022 #include <gpgme++/importresult.h>
0023 
0024 #include <KConfigGroup>
0025 #include <KLocalizedString>
0026 
0027 #include <QDir>
0028 #include <QFile>
0029 #include <QFileDialog>
0030 #include <QFileInfo>
0031 #include <QString>
0032 #include <QStringDecoder>
0033 #include <QWidget>
0034 
0035 #include <KSharedConfig>
0036 
0037 #include <memory>
0038 
0039 using namespace GpgME;
0040 using namespace Kleo;
0041 using namespace QGpgME;
0042 
0043 class ImportCertificateFromFileCommand::Private : public ImportCertificatesCommand::Private
0044 {
0045     friend class ::ImportCertificateFromFileCommand;
0046     ImportCertificateFromFileCommand *q_func() const
0047     {
0048         return static_cast<ImportCertificateFromFileCommand *>(q);
0049     }
0050 
0051 public:
0052     explicit Private(ImportCertificateFromFileCommand *qq, KeyListController *c);
0053     ~Private() override;
0054 
0055     bool ensureHaveFile();
0056 
0057 private:
0058     QStringList files;
0059 };
0060 
0061 ImportCertificateFromFileCommand::Private *ImportCertificateFromFileCommand::d_func()
0062 {
0063     return static_cast<Private *>(d.get());
0064 }
0065 const ImportCertificateFromFileCommand::Private *ImportCertificateFromFileCommand::d_func() const
0066 {
0067     return static_cast<const Private *>(d.get());
0068 }
0069 
0070 ImportCertificateFromFileCommand::Private::Private(ImportCertificateFromFileCommand *qq, KeyListController *c)
0071     : ImportCertificatesCommand::Private(qq, c)
0072     , files()
0073 {
0074 }
0075 
0076 ImportCertificateFromFileCommand::Private::~Private()
0077 {
0078 }
0079 
0080 #define d d_func()
0081 #define q q_func()
0082 
0083 ImportCertificateFromFileCommand::ImportCertificateFromFileCommand()
0084     : ImportCertificatesCommand(new Private(this, nullptr))
0085 {
0086 }
0087 
0088 ImportCertificateFromFileCommand::ImportCertificateFromFileCommand(KeyListController *p)
0089     : ImportCertificatesCommand(new Private(this, p))
0090 {
0091 }
0092 
0093 ImportCertificateFromFileCommand::ImportCertificateFromFileCommand(QAbstractItemView *v, KeyListController *p)
0094     : ImportCertificatesCommand(v, new Private(this, p))
0095 {
0096 }
0097 
0098 ImportCertificateFromFileCommand::ImportCertificateFromFileCommand(const QStringList &files, KeyListController *p)
0099     : ImportCertificatesCommand(new Private(this, p))
0100 {
0101     d->files = files;
0102 }
0103 
0104 ImportCertificateFromFileCommand::ImportCertificateFromFileCommand(const QStringList &files, QAbstractItemView *v, KeyListController *p)
0105     : ImportCertificatesCommand(v, new Private(this, p))
0106 {
0107     d->files = files;
0108 }
0109 
0110 ImportCertificateFromFileCommand::~ImportCertificateFromFileCommand()
0111 {
0112 }
0113 
0114 void ImportCertificateFromFileCommand::setFiles(const QStringList &files)
0115 {
0116     d->files = files;
0117 }
0118 
0119 void ImportCertificateFromFileCommand::doStart()
0120 {
0121     if (!d->ensureHaveFile()) {
0122         Q_EMIT canceled();
0123         d->finished();
0124         return;
0125     }
0126 
0127     d->setProgressWindowTitle(i18nc("@title:window", "Importing Certificates"));
0128     d->setProgressLabelText(i18np("Importing certificates from 1 file...", "Importing certificates from %1 files...", d->files.size()));
0129 
0130     // TODO: use KIO here
0131     d->setWaitForMoreJobs(true);
0132     for (const QString &fn : std::as_const(d->files)) {
0133         QFile in(fn);
0134         if (!in.open(QIODevice::ReadOnly)) {
0135             d->error(i18n("Could not open file %1 for reading: %2", in.fileName(), in.errorString()), i18n("Certificate Import Failed"));
0136             d->addImportResult({fn, GpgME::UnknownProtocol, ImportType::Local, ImportResult{}, AuditLogEntry{}});
0137             continue;
0138         }
0139         auto data = in.readAll();
0140         // check for UTF-16- (or UTF-32- or UTF-8-with-BOM-)encoded text file;
0141         // binary certificate files don't start with a BOM, so that it's safe
0142         // to assume that data starting with a BOM is UTF-encoded text
0143         if (const auto encoding = QStringDecoder::encodingForData(data)) {
0144             QStringDecoder codec(*encoding);
0145             qCDebug(KLEOPATRA_LOG) << this << __func__ << "Decoding" << codec.name() << "encoded data";
0146             data = QString(codec.decode(data)).toUtf8();
0147         }
0148         d->startImport(GpgME::OpenPGP, data, fn);
0149         d->startImport(GpgME::CMS, data, fn);
0150         d->importGroupsFromFile(fn);
0151     }
0152     d->setWaitForMoreJobs(false);
0153 }
0154 
0155 static QStringList get_file_name(QWidget *parent)
0156 {
0157     const QString certificateFilter = i18n("Certificates") + QLatin1StringView(" (*.asc *.cer *.cert *.crt *.der *.pem *.gpg *.p7c *.p12 *.pfx *.pgp *.kgrp)");
0158     const QString anyFilesFilter = i18n("Any files") + QLatin1StringView(" (*)");
0159     QString previousDir;
0160     if (const KSharedConfig::Ptr config = KSharedConfig::openConfig()) {
0161         const KConfigGroup group(config, QStringLiteral("Import Certificate"));
0162         previousDir = group.readPathEntry("last-open-file-directory", QDir::homePath());
0163     }
0164     const QStringList files =
0165         QFileDialog::getOpenFileNames(parent, i18n("Select Certificate File"), previousDir, certificateFilter + QLatin1StringView(";;") + anyFilesFilter);
0166     if (!files.empty())
0167         if (const KSharedConfig::Ptr config = KSharedConfig::openConfig()) {
0168             KConfigGroup group(config, QStringLiteral("Import Certificate"));
0169             group.writePathEntry("last-open-file-directory", QFileInfo(files.front()).path());
0170         }
0171     return files;
0172 }
0173 
0174 bool ImportCertificateFromFileCommand::Private::ensureHaveFile()
0175 {
0176     if (files.empty()) {
0177         files = get_file_name(parentWidgetOrView());
0178     }
0179     return !files.empty();
0180 }
0181 
0182 #undef d
0183 #undef q
0184 
0185 #include "moc_importcertificatefromfilecommand.cpp"