File indexing completed on 2024-06-23 05:14:04

0001 /*  SPDX-FileCopyrightText: 2017 Intevation GmbH
0002 
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #include "exportdialog.h"
0007 
0008 #include "kleopatra_debug.h"
0009 
0010 #include "view/waitwidget.h"
0011 
0012 #include <QDialogButtonBox>
0013 #include <QPushButton>
0014 #include <QTextEdit>
0015 #include <QVBoxLayout>
0016 
0017 #include <gpgme++/key.h>
0018 
0019 #include <QGpgME/ExportJob>
0020 #include <QGpgME/Protocol>
0021 
0022 #include <KConfigGroup>
0023 #include <KLocalizedString>
0024 #include <KSharedConfig>
0025 
0026 #include <Libkleo/Formatting>
0027 
0028 using namespace Kleo;
0029 
0030 class ExportWidget::Private
0031 {
0032 public:
0033     Private(ExportWidget *qq)
0034         : q(qq)
0035     {
0036     }
0037 
0038     void setupUi();
0039 
0040     GpgME::Key key;
0041     GpgME::Subkey subkey;
0042     QTextEdit *textEdit;
0043     WaitWidget *waitWidget;
0044     unsigned int flags;
0045 
0046 private:
0047     ExportWidget *const q;
0048 };
0049 
0050 void ExportWidget::Private::setupUi()
0051 {
0052     auto vlay = new QVBoxLayout(q);
0053     vlay->setContentsMargins(0, 0, 0, 0);
0054 
0055     textEdit = new QTextEdit;
0056     textEdit->setVisible(false);
0057     textEdit->setReadOnly(true);
0058 
0059     auto fixedFont = QFont(QStringLiteral("Monospace"));
0060     fixedFont.setStyleHint(QFont::TypeWriter);
0061 
0062     textEdit->setFont(fixedFont);
0063     textEdit->setReadOnly(true);
0064     vlay->addWidget(textEdit);
0065 
0066     waitWidget = new WaitWidget;
0067     waitWidget->setText(i18n("Exporting ..."));
0068     vlay->addWidget(waitWidget);
0069 }
0070 
0071 ExportWidget::ExportWidget(QWidget *parent)
0072     : QWidget(parent)
0073     , d(new Private(this))
0074 {
0075     d->setupUi();
0076 }
0077 
0078 ExportWidget::~ExportWidget()
0079 {
0080 }
0081 
0082 static QString injectComments(const GpgME::Key &key, const QByteArray &data)
0083 {
0084     QString ret = QString::fromUtf8(data);
0085 
0086     if (key.protocol() != GpgME::OpenPGP) {
0087         return ret;
0088     }
0089 
0090     auto overView = Formatting::toolTip(key,
0091                                         Formatting::Fingerprint | Formatting::UserIDs | Formatting::Issuer | Formatting::Subject | Formatting::ExpiryDates
0092                                             | Formatting::CertificateType | Formatting::CertificateUsage);
0093 
0094     // Fixup the HTML coming from the toolTip for our own format.
0095     overView.remove(QLatin1StringView("<tr><th>"));
0096     overView.replace(QLatin1StringView("</th><td>"), QLatin1String("\t"));
0097     overView.replace(QLatin1StringView("</td></tr>"), QLatin1String("\n"));
0098     overView.remove(QLatin1StringView("<table border=\"0\">"));
0099     overView.remove(QLatin1StringView("\n</table>"));
0100     overView.replace(QLatin1StringView("&lt;"), QLatin1String("<"));
0101     overView.replace(QLatin1StringView("&gt;"), QLatin1String(">"));
0102 
0103     auto overViewLines = overView.split(QLatin1Char('\n'));
0104 
0105     // Format comments so that they fit for RFC 4880
0106     auto comments = QStringLiteral("Comment: ");
0107     comments += overViewLines.join(QLatin1StringView("\nComment: ")) + QLatin1Char('\n');
0108 
0109     ret.insert(37 /* -----BEGIN PGP PUBLIC KEY BLOCK-----\n */, comments);
0110 
0111     return ret;
0112 }
0113 
0114 void ExportWidget::exportResult(const GpgME::Error &err, const QByteArray &data)
0115 {
0116     d->waitWidget->setVisible(false);
0117     d->textEdit->setVisible(true);
0118 
0119     if (err) {
0120         /* Should not happen. But well,.. */
0121         d->textEdit->setText(i18nc("%1 is error message", "Failed to export: '%1'", Formatting::errorAsString(err)));
0122     }
0123 
0124     if (!d->flags) {
0125         d->textEdit->setText(injectComments(d->key, data));
0126     } else {
0127         d->textEdit->setText(QString::fromUtf8(data));
0128     }
0129 }
0130 
0131 void ExportWidget::setKey(const GpgME::Subkey &key, unsigned int flags)
0132 {
0133     d->waitWidget->setVisible(true);
0134     d->textEdit->setVisible(false);
0135     d->key = key.parent();
0136     d->subkey = key;
0137     d->flags = flags;
0138 
0139     auto protocol = d->key.protocol() == GpgME::CMS ? QGpgME::smime() : QGpgME::openpgp();
0140 
0141     auto job = protocol->publicKeyExportJob(true);
0142 
0143     connect(job, &QGpgME::ExportJob::result, this, &ExportWidget::exportResult);
0144 
0145     job->setExportFlags(flags);
0146     job->start(QStringList() << QLatin1StringView(key.fingerprint()) + QLatin1Char('!'));
0147 }
0148 
0149 void ExportWidget::setKey(const GpgME::Key &key, unsigned int flags)
0150 {
0151     d->waitWidget->setVisible(true);
0152     d->textEdit->setVisible(false);
0153     d->key = key;
0154     d->flags = flags;
0155 
0156     auto protocol = key.protocol() == GpgME::CMS ? QGpgME::smime() : QGpgME::openpgp();
0157 
0158     auto job = protocol->publicKeyExportJob(true);
0159 
0160     connect(job, &QGpgME::ExportJob::result, this, &ExportWidget::exportResult);
0161 
0162     job->setExportFlags(flags);
0163     job->start(QStringList() << QLatin1StringView(key.primaryFingerprint()));
0164 }
0165 
0166 GpgME::Key ExportWidget::key() const
0167 {
0168     return d->key;
0169 }
0170 
0171 ExportDialog::ExportDialog(QWidget *parent)
0172     : QDialog(parent)
0173     , mWidget(new ExportWidget(this))
0174 {
0175     KConfigGroup dialog(KSharedConfig::openStateConfig(), QStringLiteral("ExportDialog"));
0176     const auto size = dialog.readEntry("Size", QSize(600, 800));
0177     if (size.isValid()) {
0178         resize(size);
0179     }
0180     setWindowTitle(i18nc("@title:window", "Export"));
0181 
0182     auto l = new QVBoxLayout(this);
0183     l->addWidget(mWidget);
0184 
0185     auto bbox = new QDialogButtonBox(this);
0186     auto btn = bbox->addButton(QDialogButtonBox::Close);
0187     connect(btn, &QPushButton::pressed, this, &QDialog::accept);
0188     l->addWidget(bbox);
0189 }
0190 
0191 ExportDialog::~ExportDialog()
0192 {
0193     KConfigGroup dialog(KSharedConfig::openStateConfig(), QStringLiteral("ExportDialog"));
0194     dialog.writeEntry("Size", size());
0195     dialog.sync();
0196 }
0197 
0198 void ExportDialog::setKey(const GpgME::Key &key, unsigned int flags)
0199 {
0200     mWidget->setKey(key, flags);
0201 }
0202 
0203 void ExportDialog::setKey(const GpgME::Subkey &key, unsigned int flags)
0204 {
0205     mWidget->setKey(key, flags);
0206 }
0207 
0208 GpgME::Key ExportDialog::key() const
0209 {
0210     return mWidget->key();
0211 }
0212 
0213 #include "moc_exportdialog.cpp"