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

0001 /* -*- mode: c++; c-basic-offset:4 -*-
0002     crypto/gui/resolverecipientspage.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 "resolverecipientspage.h"
0013 #include "resolverecipientspage_p.h"
0014 
0015 #include <dialogs/certificateselectiondialog.h>
0016 
0017 #include <crypto/certificateresolver.h>
0018 
0019 #include <Libkleo/Formatting>
0020 #include <Libkleo/KeyCache>
0021 
0022 #include <gpgme++/key.h>
0023 
0024 #include <KLocalizedString>
0025 
0026 #include <QButtonGroup>
0027 #include <QComboBox>
0028 #include <QHBoxLayout>
0029 #include <QLabel>
0030 #include <QListWidget>
0031 #include <QPointer>
0032 #include <QPushButton>
0033 #include <QRadioButton>
0034 #include <QStringList>
0035 #include <QToolButton>
0036 #include <QVBoxLayout>
0037 
0038 using namespace GpgME;
0039 using namespace Kleo;
0040 using namespace Kleo::Dialogs;
0041 using namespace Kleo::Crypto;
0042 using namespace Kleo::Crypto::Gui;
0043 using namespace KMime::Types;
0044 
0045 ResolveRecipientsPage::ListWidget::ListWidget(QWidget *parent, Qt::WindowFlags flags)
0046     : QWidget(parent, flags)
0047     , m_protocol(UnknownProtocol)
0048 {
0049     m_listWidget = new QListWidget;
0050     m_listWidget->setSelectionMode(QAbstractItemView::MultiSelection);
0051     auto const layout = new QVBoxLayout(this);
0052     layout->addWidget(m_listWidget);
0053     connect(m_listWidget, &QListWidget::itemSelectionChanged, this, &ListWidget::onSelectionChange);
0054 }
0055 
0056 ResolveRecipientsPage::ListWidget::~ListWidget()
0057 {
0058 }
0059 
0060 void ResolveRecipientsPage::ListWidget::onSelectionChange()
0061 {
0062     const auto widgetskeys = widgets.keys();
0063     for (const QString &i : widgetskeys) {
0064         Q_ASSERT(items.contains(i));
0065         widgets[i]->setSelected(items[i]->isSelected());
0066     }
0067     Q_EMIT selectionChanged();
0068 }
0069 
0070 void ResolveRecipientsPage::ListWidget::addEntry(const Mailbox &mbox)
0071 {
0072     addEntry(mbox.prettyAddress(), mbox.prettyAddress(), mbox);
0073 }
0074 
0075 void ResolveRecipientsPage::ListWidget::addEntry(const QString &id, const QString &name)
0076 {
0077     addEntry(id, name, Mailbox());
0078 }
0079 
0080 void ResolveRecipientsPage::ListWidget::addEntry(const QString &id, const QString &name, const Mailbox &mbox)
0081 {
0082     Q_ASSERT(!widgets.contains(id) && !items.contains(id));
0083     auto item = new QListWidgetItem;
0084     item->setData(IdRole, id);
0085     auto wid = new ItemWidget(id, name, mbox, this);
0086     connect(wid, &ItemWidget::changed, this, &ListWidget::completeChanged);
0087     wid->setProtocol(m_protocol);
0088     item->setSizeHint(wid->sizeHint());
0089     m_listWidget->addItem(item);
0090     m_listWidget->setItemWidget(item, wid);
0091     widgets[id] = wid;
0092     items[id] = item;
0093 }
0094 
0095 Mailbox ResolveRecipientsPage::ListWidget::mailbox(const QString &id) const
0096 {
0097     return widgets.contains(id) ? widgets[id]->mailbox() : Mailbox();
0098 }
0099 
0100 void ResolveRecipientsPage::ListWidget::setCertificates(const QString &id, const std::vector<Key> &pgp, const std::vector<Key> &cms)
0101 {
0102     Q_ASSERT(widgets.contains(id));
0103     widgets[id]->setCertificates(pgp, cms);
0104 }
0105 
0106 Key ResolveRecipientsPage::ListWidget::selectedCertificate(const QString &id) const
0107 {
0108     return widgets.contains(id) ? widgets[id]->selectedCertificate() : Key();
0109 }
0110 
0111 GpgME::Key ResolveRecipientsPage::ListWidget::selectedCertificate(const QString &id, GpgME::Protocol prot) const
0112 {
0113     return widgets.contains(id) ? widgets[id]->selectedCertificate(prot) : Key();
0114 }
0115 
0116 QStringList ResolveRecipientsPage::ListWidget::identifiers() const
0117 {
0118     return widgets.keys();
0119 }
0120 
0121 void ResolveRecipientsPage::ListWidget::setProtocol(GpgME::Protocol prot)
0122 {
0123     if (m_protocol == prot) {
0124         return;
0125     }
0126     m_protocol = prot;
0127     for (ItemWidget *i : std::as_const(widgets)) {
0128         i->setProtocol(prot);
0129     }
0130 }
0131 
0132 void ResolveRecipientsPage::ListWidget::removeEntry(const QString &id)
0133 {
0134     if (!widgets.contains(id)) {
0135         return;
0136     }
0137     delete items[id];
0138     items.remove(id);
0139     delete widgets[id];
0140     widgets.remove(id);
0141 }
0142 
0143 void ResolveRecipientsPage::ListWidget::showSelectionDialog(const QString &id)
0144 {
0145     if (!widgets.contains(id)) {
0146         return;
0147     }
0148     widgets[id]->showSelectionDialog();
0149 }
0150 
0151 QStringList ResolveRecipientsPage::ListWidget::selectedEntries() const
0152 {
0153     QStringList entries;
0154     const QList<QListWidgetItem *> items = m_listWidget->selectedItems();
0155     entries.reserve(items.count());
0156     for (const QListWidgetItem *i : items) {
0157         entries.append(i->data(IdRole).toString());
0158     }
0159     return entries;
0160 }
0161 
0162 ResolveRecipientsPage::ItemWidget::ItemWidget(const QString &id, const QString &name, const Mailbox &mbox, QWidget *parent, Qt::WindowFlags flags)
0163     : QWidget(parent, flags)
0164     , m_id(id)
0165     , m_mailbox(mbox)
0166     , m_protocol(UnknownProtocol)
0167     , m_selected(false)
0168 {
0169     Q_ASSERT(!m_id.isEmpty());
0170     setAutoFillBackground(true);
0171     auto layout = new QHBoxLayout(this);
0172     layout->setContentsMargins(0, 0, 0, 0);
0173     layout->addSpacing(15);
0174     m_nameLabel = new QLabel;
0175     m_nameLabel->setText(name);
0176     layout->addWidget(m_nameLabel);
0177     layout->addStretch();
0178     m_certLabel = new QLabel;
0179     m_certLabel->setText(i18n("<i>No certificate selected</i>"));
0180     layout->addWidget(m_certLabel);
0181     m_certCombo = new QComboBox;
0182     connect(m_certCombo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(changed()));
0183     layout->addWidget(m_certCombo);
0184     m_selectButton = new QToolButton;
0185     m_selectButton->setText(i18n("..."));
0186     connect(m_selectButton, &QAbstractButton::clicked, this, &ItemWidget::showSelectionDialog);
0187     layout->addWidget(m_selectButton);
0188     layout->addSpacing(15);
0189     setCertificates(std::vector<Key>(), std::vector<Key>());
0190 }
0191 
0192 void ResolveRecipientsPage::ItemWidget::updateVisibility()
0193 {
0194     m_certLabel->setVisible(m_certCombo->count() == 0);
0195     m_certCombo->setVisible(m_certCombo->count() > 0);
0196 }
0197 
0198 ResolveRecipientsPage::ItemWidget::~ItemWidget()
0199 {
0200 }
0201 
0202 QString ResolveRecipientsPage::ItemWidget::id() const
0203 {
0204     return m_id;
0205 }
0206 
0207 void ResolveRecipientsPage::ItemWidget::setSelected(bool selected)
0208 {
0209     if (m_selected == selected) {
0210         return;
0211     }
0212     m_selected = selected;
0213     setBackgroundRole(selected ? QPalette::Highlight : QPalette::Base);
0214     const QPalette::ColorRole foreground = selected ? QPalette::HighlightedText : QPalette::Text;
0215     setForegroundRole(foreground);
0216     m_nameLabel->setForegroundRole(foreground);
0217     m_certLabel->setForegroundRole(foreground);
0218 }
0219 
0220 bool ResolveRecipientsPage::ItemWidget::isSelected() const
0221 {
0222     return m_selected;
0223 }
0224 
0225 static CertificateSelectionDialog *createCertificateSelectionDialog(QWidget *parent, GpgME::Protocol prot)
0226 {
0227     auto const dlg = new CertificateSelectionDialog(parent);
0228     const CertificateSelectionDialog::Options options = //
0229         CertificateSelectionDialog::SingleSelection | //
0230         CertificateSelectionDialog::EncryptOnly | //
0231         CertificateSelectionDialog::MultiSelection | //
0232         CertificateSelectionDialog::optionsFromProtocol(prot);
0233     dlg->setOptions(options);
0234     return dlg;
0235 }
0236 
0237 void ResolveRecipientsPage::ItemWidget::showSelectionDialog()
0238 {
0239     QPointer<CertificateSelectionDialog> dlg = createCertificateSelectionDialog(this, m_protocol);
0240 
0241     if (dlg->exec() == QDialog::Accepted && dlg /* still with us? */) {
0242         const GpgME::Key cert = dlg->selectedCertificate();
0243         if (!cert.isNull()) {
0244             addCertificateToComboBox(cert);
0245             selectCertificateInComboBox(cert);
0246         }
0247     }
0248     delete dlg;
0249 }
0250 
0251 Mailbox ResolveRecipientsPage::ItemWidget::mailbox() const
0252 {
0253     return m_mailbox;
0254 }
0255 
0256 void ResolveRecipientsPage::ItemWidget::selectCertificateInComboBox(const Key &key)
0257 {
0258     m_certCombo->setCurrentIndex(m_certCombo->findData(QLatin1StringView(key.keyID())));
0259 }
0260 
0261 void ResolveRecipientsPage::ItemWidget::addCertificateToComboBox(const GpgME::Key &key)
0262 {
0263     m_certCombo->addItem(Formatting::formatForComboBox(key), QByteArray(key.keyID()));
0264     if (m_certCombo->count() == 1) {
0265         m_certCombo->setCurrentIndex(0);
0266     }
0267     updateVisibility();
0268 }
0269 
0270 void ResolveRecipientsPage::ItemWidget::resetCertificates()
0271 {
0272     std::vector<Key> certs;
0273     Key selected;
0274     switch (m_protocol) {
0275     case OpenPGP:
0276         certs = m_pgp;
0277         break;
0278     case CMS:
0279         certs = m_cms;
0280         break;
0281     case UnknownProtocol:
0282         certs = m_cms;
0283         certs.insert(certs.end(), m_pgp.begin(), m_pgp.end());
0284     }
0285 
0286     m_certCombo->clear();
0287     for (const Key &i : std::as_const(certs)) {
0288         addCertificateToComboBox(i);
0289     }
0290     if (!m_selectedCertificates[m_protocol].isNull()) {
0291         selectCertificateInComboBox(m_selectedCertificates[m_protocol]);
0292     } else if (m_certCombo->count() > 0) {
0293         m_certCombo->setCurrentIndex(0);
0294     }
0295     updateVisibility();
0296     Q_EMIT changed();
0297 }
0298 
0299 void ResolveRecipientsPage::ItemWidget::setProtocol(Protocol prot)
0300 {
0301     if (m_protocol == prot) {
0302         return;
0303     }
0304     m_selectedCertificates[m_protocol] = selectedCertificate();
0305     if (m_protocol != UnknownProtocol) {
0306         (m_protocol == OpenPGP ? m_pgp : m_cms) = certificates();
0307     }
0308     m_protocol = prot;
0309     resetCertificates();
0310 }
0311 
0312 void ResolveRecipientsPage::ItemWidget::setCertificates(const std::vector<Key> &pgp, const std::vector<Key> &cms)
0313 {
0314     m_pgp = pgp;
0315     m_cms = cms;
0316     resetCertificates();
0317 }
0318 
0319 Key ResolveRecipientsPage::ItemWidget::selectedCertificate() const
0320 {
0321     return KeyCache::instance()->findByKeyIDOrFingerprint(m_certCombo->itemData(m_certCombo->currentIndex(), ListWidget::IdRole).toString().toStdString());
0322 }
0323 
0324 GpgME::Key ResolveRecipientsPage::ItemWidget::selectedCertificate(GpgME::Protocol prot) const
0325 {
0326     return prot == m_protocol ? selectedCertificate() : m_selectedCertificates.value(prot);
0327 }
0328 
0329 std::vector<Key> ResolveRecipientsPage::ItemWidget::certificates() const
0330 {
0331     std::vector<Key> certs;
0332     for (int i = 0; i < m_certCombo->count(); ++i) {
0333         certs.push_back(KeyCache::instance()->findByKeyIDOrFingerprint(m_certCombo->itemData(i, ListWidget::IdRole).toString().toStdString()));
0334     }
0335     return certs;
0336 }
0337 
0338 class ResolveRecipientsPage::Private
0339 {
0340     friend class ::Kleo::Crypto::Gui::ResolveRecipientsPage;
0341     ResolveRecipientsPage *const q;
0342 
0343 public:
0344     explicit Private(ResolveRecipientsPage *qq);
0345     ~Private();
0346 
0347     void setSelectedProtocol(Protocol protocol);
0348     void selectionChanged();
0349     void removeSelectedEntries();
0350     void addRecipient();
0351     void addRecipient(const Mailbox &mbox);
0352     void addRecipient(const QString &id, const QString &name);
0353     void updateProtocolRBVisibility();
0354     void protocolSelected(int prot);
0355     void writeSelectedCertificatesToPreferences();
0356     void completeChangedInternal();
0357 
0358 private:
0359     ListWidget *m_listWidget;
0360     QPushButton *m_addButton;
0361     QPushButton *m_removeButton;
0362     QRadioButton *m_pgpRB;
0363     QRadioButton *m_cmsRB;
0364     QLabel *m_additionalRecipientsLabel;
0365     Protocol m_presetProtocol;
0366     Protocol m_selectedProtocol;
0367     bool m_multipleProtocolsAllowed;
0368     std::shared_ptr<RecipientPreferences> m_recipientPreferences;
0369 };
0370 
0371 ResolveRecipientsPage::Private::Private(ResolveRecipientsPage *qq)
0372     : q(qq)
0373     , m_presetProtocol(UnknownProtocol)
0374     , m_selectedProtocol(m_presetProtocol)
0375     , m_multipleProtocolsAllowed(false)
0376     , m_recipientPreferences()
0377 {
0378     connect(q, SIGNAL(completeChanged()), q, SLOT(completeChangedInternal()));
0379     q->setTitle(i18n("<b>Recipients</b>"));
0380     auto const layout = new QVBoxLayout(q);
0381     m_listWidget = new ListWidget;
0382     connect(m_listWidget, SIGNAL(selectionChanged()), q, SLOT(selectionChanged()));
0383     connect(m_listWidget, &ListWidget::completeChanged, q, &WizardPage::completeChanged);
0384     layout->addWidget(m_listWidget);
0385     m_additionalRecipientsLabel = new QLabel;
0386     m_additionalRecipientsLabel->setWordWrap(true);
0387     layout->addWidget(m_additionalRecipientsLabel);
0388     m_additionalRecipientsLabel->setVisible(false);
0389     auto buttonWidget = new QWidget;
0390     auto buttonLayout = new QHBoxLayout(buttonWidget);
0391     buttonLayout->setContentsMargins(0, 0, 0, 0);
0392     m_addButton = new QPushButton;
0393     connect(m_addButton, SIGNAL(clicked()), q, SLOT(addRecipient()));
0394     m_addButton->setText(i18n("Add Recipient..."));
0395     buttonLayout->addWidget(m_addButton);
0396     m_removeButton = new QPushButton;
0397     m_removeButton->setEnabled(false);
0398     m_removeButton->setText(i18n("Remove Selected"));
0399     connect(m_removeButton, SIGNAL(clicked()), q, SLOT(removeSelectedEntries()));
0400     buttonLayout->addWidget(m_removeButton);
0401     buttonLayout->addStretch();
0402     layout->addWidget(buttonWidget);
0403     auto protocolWidget = new QWidget;
0404     auto protocolLayout = new QHBoxLayout(protocolWidget);
0405     auto protocolGroup = new QButtonGroup(q);
0406     connect(protocolGroup, &QButtonGroup::idClicked, q, [this](int buttonClicked) {
0407         protocolSelected(buttonClicked);
0408     });
0409     m_pgpRB = new QRadioButton;
0410     m_pgpRB->setText(i18n("OpenPGP"));
0411     protocolGroup->addButton(m_pgpRB, OpenPGP);
0412     protocolLayout->addWidget(m_pgpRB);
0413     m_cmsRB = new QRadioButton;
0414     m_cmsRB->setText(i18n("S/MIME"));
0415     protocolGroup->addButton(m_cmsRB, CMS);
0416     protocolLayout->addWidget(m_cmsRB);
0417     protocolLayout->addStretch();
0418     layout->addWidget(protocolWidget);
0419 }
0420 
0421 ResolveRecipientsPage::Private::~Private()
0422 {
0423 }
0424 
0425 void ResolveRecipientsPage::Private::completeChangedInternal()
0426 {
0427     const bool isComplete = q->isComplete();
0428     const std::vector<Key> keys = q->resolvedCertificates();
0429     const bool haveSecret = std::find_if(keys.begin(),
0430                                          keys.end(),
0431                                          [](const Key &key) {
0432                                              return key.hasSecret();
0433                                          })
0434         != keys.end();
0435     if (isComplete && !haveSecret) {
0436         q->setExplanation(
0437             i18n("<b>Warning:</b> None of the selected certificates seem to be your own. You will not be able to decrypt the encrypted data again."));
0438     } else {
0439         q->setExplanation(QString());
0440     }
0441 }
0442 
0443 void ResolveRecipientsPage::Private::updateProtocolRBVisibility()
0444 {
0445     const bool visible = !m_multipleProtocolsAllowed && m_presetProtocol == UnknownProtocol;
0446     m_cmsRB->setVisible(visible);
0447     m_pgpRB->setVisible(visible);
0448     if (visible) {
0449         if (m_selectedProtocol == CMS) {
0450             m_cmsRB->click();
0451         } else {
0452             m_pgpRB->click();
0453         }
0454     }
0455 }
0456 
0457 bool ResolveRecipientsPage::isComplete() const
0458 {
0459     const QStringList ids = d->m_listWidget->identifiers();
0460     if (ids.isEmpty()) {
0461         return false;
0462     }
0463 
0464     for (const QString &i : ids) {
0465         if (d->m_listWidget->selectedCertificate(i).isNull()) {
0466             return false;
0467         }
0468     }
0469 
0470     return true;
0471 }
0472 
0473 ResolveRecipientsPage::ResolveRecipientsPage(QWidget *parent)
0474     : WizardPage(parent)
0475     , d(new Private(this))
0476 {
0477 }
0478 
0479 ResolveRecipientsPage::~ResolveRecipientsPage()
0480 {
0481 }
0482 
0483 Protocol ResolveRecipientsPage::selectedProtocol() const
0484 {
0485     return d->m_selectedProtocol;
0486 }
0487 
0488 void ResolveRecipientsPage::Private::setSelectedProtocol(Protocol protocol)
0489 {
0490     if (m_selectedProtocol == protocol) {
0491         return;
0492     }
0493     m_selectedProtocol = protocol;
0494     m_listWidget->setProtocol(m_selectedProtocol);
0495     Q_EMIT q->selectedProtocolChanged();
0496 }
0497 
0498 void ResolveRecipientsPage::Private::protocolSelected(int p)
0499 {
0500     const auto protocol = static_cast<Protocol>(p);
0501     Q_ASSERT(protocol != UnknownProtocol);
0502     setSelectedProtocol(protocol);
0503 }
0504 
0505 void ResolveRecipientsPage::setPresetProtocol(Protocol prot)
0506 {
0507     if (d->m_presetProtocol == prot) {
0508         return;
0509     }
0510     d->m_presetProtocol = prot;
0511     d->setSelectedProtocol(prot);
0512     if (prot != UnknownProtocol) {
0513         d->m_multipleProtocolsAllowed = false;
0514     }
0515     d->updateProtocolRBVisibility();
0516 }
0517 
0518 Protocol ResolveRecipientsPage::presetProtocol() const
0519 {
0520     return d->m_presetProtocol;
0521 }
0522 
0523 bool ResolveRecipientsPage::multipleProtocolsAllowed() const
0524 {
0525     return d->m_multipleProtocolsAllowed;
0526 }
0527 
0528 void ResolveRecipientsPage::setMultipleProtocolsAllowed(bool allowed)
0529 {
0530     if (d->m_multipleProtocolsAllowed == allowed) {
0531         return;
0532     }
0533     d->m_multipleProtocolsAllowed = allowed;
0534     if (d->m_multipleProtocolsAllowed) {
0535         setPresetProtocol(UnknownProtocol);
0536         d->setSelectedProtocol(UnknownProtocol);
0537     }
0538     d->updateProtocolRBVisibility();
0539 }
0540 
0541 void ResolveRecipientsPage::Private::addRecipient(const QString &id, const QString &name)
0542 {
0543     m_listWidget->addEntry(id, name);
0544 }
0545 
0546 void ResolveRecipientsPage::Private::addRecipient(const Mailbox &mbox)
0547 {
0548     m_listWidget->addEntry(mbox);
0549 }
0550 
0551 void ResolveRecipientsPage::Private::addRecipient()
0552 {
0553     QPointer<CertificateSelectionDialog> dlg = createCertificateSelectionDialog(q, q->selectedProtocol());
0554     if (dlg->exec() != QDialog::Accepted || !dlg /*q already deleted*/) {
0555         return;
0556     }
0557     const std::vector<Key> keys = dlg->selectedCertificates();
0558 
0559     int i = 0;
0560     for (const Key &key : keys) {
0561         const QStringList existing = m_listWidget->identifiers();
0562         QString rec = i18n("Recipient");
0563         while (existing.contains(rec)) {
0564             rec = i18nc("%1 == number", "Recipient (%1)", ++i);
0565         }
0566         addRecipient(rec, rec);
0567         const std::vector<Key> pgp = key.protocol() == OpenPGP ? std::vector<Key>(1, key) : std::vector<Key>();
0568         const std::vector<Key> cms = key.protocol() == CMS ? std::vector<Key>(1, key) : std::vector<Key>();
0569         m_listWidget->setCertificates(rec, pgp, cms);
0570     }
0571     Q_EMIT q->completeChanged();
0572 }
0573 
0574 static QString listKeysForInfo(const std::vector<Key> &keys)
0575 {
0576     QStringList list;
0577     std::transform(keys.begin(), keys.end(), list.begin(), &Formatting::formatKeyLink);
0578     return list.join(QLatin1StringView("<br/>"));
0579 }
0580 
0581 void ResolveRecipientsPage::setAdditionalRecipientsInfo(const std::vector<Key> &recipients)
0582 {
0583     d->m_additionalRecipientsLabel->setVisible(!recipients.empty());
0584     if (recipients.empty()) {
0585         return;
0586     }
0587     d->m_additionalRecipientsLabel->setText(i18n("<qt><p>Recipients predefined via GnuPG settings:</p>%1</qt>", listKeysForInfo(recipients)));
0588 }
0589 
0590 std::vector<Key> ResolveRecipientsPage::resolvedCertificates() const
0591 {
0592     std::vector<Key> certs;
0593     const QStringList identifiers = d->m_listWidget->identifiers();
0594     for (const QString &i : identifiers) {
0595         const GpgME::Key cert = d->m_listWidget->selectedCertificate(i);
0596         if (!cert.isNull()) {
0597             certs.push_back(cert);
0598         }
0599     }
0600     return certs;
0601 }
0602 
0603 void ResolveRecipientsPage::Private::selectionChanged()
0604 {
0605     m_removeButton->setEnabled(!m_listWidget->selectedEntries().isEmpty());
0606 }
0607 
0608 void ResolveRecipientsPage::Private::removeSelectedEntries()
0609 {
0610     const auto selectedEntries{m_listWidget->selectedEntries()};
0611     for (const QString &i : selectedEntries) {
0612         m_listWidget->removeEntry(i);
0613     }
0614     Q_EMIT q->completeChanged();
0615 }
0616 
0617 void ResolveRecipientsPage::setRecipientsUserMutable(bool isMutable)
0618 {
0619     d->m_addButton->setVisible(isMutable);
0620     d->m_removeButton->setVisible(isMutable);
0621 }
0622 
0623 bool ResolveRecipientsPage::recipientsUserMutable() const
0624 {
0625     return d->m_addButton->isVisible();
0626 }
0627 
0628 std::shared_ptr<RecipientPreferences> ResolveRecipientsPage::recipientPreferences() const
0629 {
0630     return d->m_recipientPreferences;
0631 }
0632 
0633 void ResolveRecipientsPage::setRecipientPreferences(const std::shared_ptr<RecipientPreferences> &prefs)
0634 {
0635     d->m_recipientPreferences = prefs;
0636 }
0637 
0638 void ResolveRecipientsPage::Private::writeSelectedCertificatesToPreferences()
0639 {
0640     if (!m_recipientPreferences) {
0641         return;
0642     }
0643 
0644     const auto identifiers{m_listWidget->identifiers()};
0645     for (const QString &i : identifiers) {
0646         const Mailbox mbox = m_listWidget->mailbox(i);
0647         if (!mbox.hasAddress()) {
0648             continue;
0649         }
0650         const Key pgp = m_listWidget->selectedCertificate(i, OpenPGP);
0651         if (!pgp.isNull()) {
0652             m_recipientPreferences->setPreferredCertificate(mbox, OpenPGP, pgp);
0653         }
0654         const Key cms = m_listWidget->selectedCertificate(i, CMS);
0655         if (!cms.isNull()) {
0656             m_recipientPreferences->setPreferredCertificate(mbox, CMS, cms);
0657         }
0658     }
0659 }
0660 
0661 void ResolveRecipientsPage::onNext()
0662 {
0663     d->writeSelectedCertificatesToPreferences();
0664 }
0665 
0666 #include "moc_resolverecipientspage.cpp"
0667 #include "moc_resolverecipientspage_p.cpp"