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

0001 /* -*- mode: c++; c-basic-offset:4 -*-
0002     uiserver/selectcertificatecommand.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 "selectcertificatecommand.h"
0013 
0014 #include <dialogs/certificateselectiondialog.h>
0015 
0016 #include <Libkleo/KeyCache>
0017 #include <Libkleo/KleoException>
0018 #include <Libkleo/Stl_Util>
0019 
0020 #include <gpgme++/key.h>
0021 
0022 #include <gpg-error.h>
0023 
0024 #include "kleopatra_debug.h"
0025 #include <KLocalizedString>
0026 
0027 #include <QByteArray>
0028 #include <QPointer>
0029 
0030 #include <algorithm>
0031 #include <string>
0032 
0033 using namespace Kleo;
0034 using namespace Kleo::Dialogs;
0035 using namespace GpgME;
0036 
0037 class SelectCertificateCommand::Private
0038 {
0039     friend class ::Kleo::SelectCertificateCommand;
0040     SelectCertificateCommand *const q;
0041 
0042 public:
0043     Private(SelectCertificateCommand *qq)
0044         : q(qq)
0045         , dialog()
0046     {
0047     }
0048 
0049 private:
0050     void slotDialogAccepted();
0051     void slotDialogRejected();
0052     void slotSelectedCertificates(int, const QByteArray &);
0053 
0054 private:
0055     void ensureDialogCreated()
0056     {
0057         if (dialog) {
0058             return;
0059         }
0060         dialog = new CertificateSelectionDialog;
0061         q->applyWindowID(dialog);
0062         dialog->setAttribute(Qt::WA_DeleteOnClose);
0063         // dialog->setWindowTitle( i18nc( "@title", "Certificate Selection" ) );
0064         connect(dialog, SIGNAL(accepted()), q, SLOT(slotDialogAccepted()));
0065         connect(dialog, SIGNAL(rejected()), q, SLOT(slotDialogRejected()));
0066     }
0067     void ensureDialogShown()
0068     {
0069         ensureDialogCreated();
0070         if (dialog->isVisible()) {
0071             dialog->raise();
0072         } else {
0073             dialog->show();
0074         }
0075     }
0076 
0077 private:
0078     QPointer<CertificateSelectionDialog> dialog;
0079 };
0080 
0081 SelectCertificateCommand::SelectCertificateCommand()
0082     : QObject()
0083     , AssuanCommandMixin<SelectCertificateCommand>()
0084     , d(new Private(this))
0085 {
0086 }
0087 
0088 SelectCertificateCommand::~SelectCertificateCommand()
0089 {
0090 }
0091 
0092 static const struct {
0093     const char *name;
0094     CertificateSelectionDialog::Option option;
0095 } option_table[] = {
0096     {"multi", CertificateSelectionDialog::MultiSelection},
0097     {"sign-only", CertificateSelectionDialog::SignOnly},
0098     {"encrypt-only", CertificateSelectionDialog::EncryptOnly},
0099     {"openpgp-only", CertificateSelectionDialog::OpenPGPFormat},
0100     {"x509-only", CertificateSelectionDialog::CMSFormat},
0101     {"secret-only", CertificateSelectionDialog::SecretKeys},
0102 };
0103 
0104 int SelectCertificateCommand::doStart()
0105 {
0106     d->ensureDialogCreated();
0107 
0108     CertificateSelectionDialog::Options opts;
0109     for (unsigned int i = 0; i < sizeof option_table / sizeof *option_table; ++i) {
0110         if (hasOption(option_table[i].name)) {
0111             opts |= option_table[i].option;
0112         }
0113     }
0114     if ((opts & CertificateSelectionDialog::AnyCertificate) == 0) {
0115         // neither sign-only nor encrypt-only => any usage
0116         opts |= CertificateSelectionDialog::AnyCertificate;
0117     }
0118     if ((opts & CertificateSelectionDialog::AnyFormat) == 0) {
0119         // neither openpgp-only nor x509-only => any protocol
0120         opts |= CertificateSelectionDialog::AnyFormat;
0121     }
0122     d->dialog->setOptions(opts);
0123 
0124     if (const int err = inquire("SELECTED_CERTIFICATES", this, SLOT(slotSelectedCertificates(int, QByteArray)))) {
0125         return err;
0126     }
0127 
0128     d->ensureDialogShown();
0129 
0130     return 0;
0131 }
0132 
0133 void SelectCertificateCommand::Private::slotSelectedCertificates(int err, const QByteArray &data)
0134 {
0135     qCDebug(KLEOPATRA_LOG) << err << ", " << data.constData();
0136     if (err) {
0137         return;
0138     }
0139     const auto split = data.split('\n');
0140     std::vector<std::string> fprs;
0141     fprs.reserve(split.size());
0142     std::transform(split.cbegin(), split.cend(), std::back_inserter(fprs), std::mem_fn(&QByteArray::constData));
0143     const std::vector<Key> keys = KeyCache::instance()->findByKeyIDOrFingerprint(fprs);
0144     for (const Key &key : keys) {
0145         qCDebug(KLEOPATRA_LOG) << "found key " << key.userID(0).id();
0146     }
0147     if (dialog) {
0148         dialog->selectCertificates(keys);
0149     } else {
0150         qCWarning(KLEOPATRA_LOG) << "dialog == NULL in slotSelectedCertificates";
0151     }
0152 }
0153 
0154 void SelectCertificateCommand::doCanceled()
0155 {
0156     if (d->dialog) {
0157         d->dialog->close();
0158     }
0159 }
0160 
0161 void SelectCertificateCommand::Private::slotDialogAccepted()
0162 {
0163     try {
0164         QByteArray data;
0165         const auto selectedCertificates(dialog->selectedCertificates());
0166         for (const Key &key : selectedCertificates) {
0167             data += key.primaryFingerprint();
0168             data += '\n';
0169         }
0170         q->sendData(data);
0171         q->done();
0172     } catch (const Exception &e) {
0173         q->done(e.error(), e.message());
0174     } catch (const std::exception &e) {
0175         q->done(makeError(GPG_ERR_UNEXPECTED),
0176                 i18n("Caught unexpected exception in SelectCertificateCommand::Private::slotDialogAccepted: %1", QString::fromLocal8Bit(e.what())));
0177     } catch (...) {
0178         q->done(makeError(GPG_ERR_UNEXPECTED), i18n("Caught unknown exception in SelectCertificateCommand::Private::slotDialogAccepted"));
0179     }
0180 }
0181 
0182 void SelectCertificateCommand::Private::slotDialogRejected()
0183 {
0184     dialog = nullptr;
0185     q->done(makeError(GPG_ERR_CANCELED));
0186 }
0187 
0188 #include "moc_selectcertificatecommand.cpp"