1 /*  crypto/gui/signencryptwidget.cpp
2 
3     This file is part of Kleopatra, the KDE keymanager
4     SPDX-FileCopyrightText: 2016 Bundesamt für Sicherheit in der Informationstechnik
5     SPDX-FileContributor: Intevation GmbH
6 
7     SPDX-License-Identifier: GPL-2.0-or-later
8 */
9 
10 #include "signencryptwidget.h"
11 
12 #include "kleopatra_debug.h"
13 
14 #include "certificatelineedit.h"
15 #include "fileoperationspreferences.h"
16 #include "kleopatraapplication.h"
17 #include "settings.h"
18 #include "unknownrecipientwidget.h"
19 
20 #include "commands/detailscommand.h"
21 
22 #include "dialogs/certificateselectiondialog.h"
23 #include "dialogs/groupdetailsdialog.h"
24 
25 #include <QVBoxLayout>
26 #include <QHBoxLayout>
27 #include <QGroupBox>
28 #include <QCheckBox>
29 #include <QScrollArea>
30 #include <QScrollBar>
31 
32 #include <Libkleo/DefaultKeyFilter>
33 #include <Libkleo/KeyCache>
34 #include <Libkleo/KeyGroup>
35 #include <Libkleo/KeyListModel>
36 #include <Libkleo/KeySelectionCombo>
37 #include <Libkleo/KeyListSortFilterProxyModel>
38 
39 #include <Libkleo/GnuPG>
40 
41 #include <KLocalizedString>
42 #include <KConfigGroup>
43 #include <KSharedConfig>
44 #include <KMessageBox>
45 
46 using namespace Kleo;
47 using namespace Kleo::Dialogs;
48 using namespace GpgME;
49 
50 namespace {
51 class SignCertificateFilter: public DefaultKeyFilter
52 {
53 public:
SignCertificateFilter(GpgME::Protocol proto)54     SignCertificateFilter(GpgME::Protocol proto) : DefaultKeyFilter()
55     {
56         setRevoked(DefaultKeyFilter::NotSet);
57         setExpired(DefaultKeyFilter::NotSet);
58         setHasSecret(DefaultKeyFilter::Set);
59         setCanSign(DefaultKeyFilter::Set);
60 
61         if (proto == GpgME::OpenPGP) {
62             setIsOpenPGP(DefaultKeyFilter::Set);
63         } else if (proto == GpgME::CMS) {
64             setIsOpenPGP(DefaultKeyFilter::NotSet);
65         }
66     }
67 };
68 class EncryptCertificateFilter: public DefaultKeyFilter
69 {
70 public:
EncryptCertificateFilter(GpgME::Protocol proto)71     EncryptCertificateFilter(GpgME::Protocol proto): DefaultKeyFilter()
72     {
73         setRevoked(DefaultKeyFilter::NotSet);
74         setExpired(DefaultKeyFilter::NotSet);
75         setCanEncrypt(DefaultKeyFilter::Set);
76 
77         if (proto == GpgME::OpenPGP) {
78             setIsOpenPGP(DefaultKeyFilter::Set);
79         } else if (proto == GpgME::CMS) {
80             setIsOpenPGP(DefaultKeyFilter::NotSet);
81         }
82     }
83 };
84 class EncryptSelfCertificateFilter: public EncryptCertificateFilter
85 {
86 public:
EncryptSelfCertificateFilter(GpgME::Protocol proto)87     EncryptSelfCertificateFilter(GpgME::Protocol proto): EncryptCertificateFilter(proto)
88     {
89         setRevoked(DefaultKeyFilter::NotSet);
90         setExpired(DefaultKeyFilter::NotSet);
91         setCanEncrypt(DefaultKeyFilter::Set);
92         setHasSecret(DefaultKeyFilter::Set);
93     }
94 };
95 }
96 
SignEncryptWidget(QWidget * parent,bool sigEncExclusive)97 SignEncryptWidget::SignEncryptWidget(QWidget *parent, bool sigEncExclusive)
98     : QWidget(parent),
99       mModel(AbstractKeyListModel::createFlatKeyListModel(this)),
100       mIsExclusive(sigEncExclusive)
101 {
102     auto lay = new QVBoxLayout(this);
103     lay->setContentsMargins(0, 0, 0, 0);
104 
105     mModel->useKeyCache(true, KeyList::IncludeGroups);
106 
107     const bool haveSecretKeys = !KeyCache::instance()->secretKeys().empty();
108     const bool havePublicKeys = !KeyCache::instance()->keys().empty();
109     const bool symmetricOnly = FileOperationsPreferences().symmetricEncryptionOnly();
110 
111     /* The signature selection */
112     auto sigLay = new QHBoxLayout;
113     auto sigGrp = new QGroupBox(i18nc("@title:group", "Prove authenticity (sign)"));
114     mSigChk = new QCheckBox(i18n("Sign as:"));
115     mSigChk->setEnabled(haveSecretKeys);
116     mSigChk->setChecked(haveSecretKeys);
117 
118     mSigSelect = new KeySelectionCombo();
119     mSigSelect->setEnabled(mSigChk->isChecked());
120 
121     sigLay->addWidget(mSigChk);
122     sigLay->addWidget(mSigSelect, 1);
123     sigGrp->setLayout(sigLay);
124     lay->addWidget(sigGrp);
125 
126     connect(mSigChk, &QCheckBox::toggled, mSigSelect, &QWidget::setEnabled);
127     connect(mSigChk, &QCheckBox::toggled, this, &SignEncryptWidget::updateOp);
128     connect(mSigSelect, &KeySelectionCombo::currentKeyChanged,
129             this, &SignEncryptWidget::updateOp);
130 
131     // Recipient selection
132     auto encBoxLay = new QVBoxLayout;
133     auto encBox = new QGroupBox(i18nc("@title:group", "Encrypt"));
134     encBox->setLayout(encBoxLay);
135     auto recipientGrid = new QGridLayout;
136 
137     // Own key
138     mEncSelfChk = new QCheckBox(i18n("Encrypt for me:"));
139     mEncSelfChk->setEnabled(haveSecretKeys && !symmetricOnly);
140     mEncSelfChk->setChecked(haveSecretKeys && !symmetricOnly);
141     mSelfSelect = new KeySelectionCombo();
142     mSelfSelect->setEnabled(mEncSelfChk->isChecked());
143     recipientGrid->addWidget(mEncSelfChk, 0, 0);
144     recipientGrid->addWidget(mSelfSelect, 0, 1);
145 
146     // Checkbox for other keys
147     mEncOtherChk = new QCheckBox(i18n("Encrypt for others:"));
148     mEncOtherChk->setEnabled(havePublicKeys && !symmetricOnly);
149     mEncOtherChk->setChecked(havePublicKeys && !symmetricOnly);
150     recipientGrid->addWidget(mEncOtherChk, 1, 0, Qt::AlignTop);
151     connect(mEncOtherChk, &QCheckBox::toggled, this,
152         [this](bool toggled) {
153             for (CertificateLineEdit *edit : std::as_const(mRecpWidgets)) {
154                 edit->setEnabled(toggled);
155             }
156             updateOp();
157         });
158     mRecpLayout = new QVBoxLayout;
159     recipientGrid->addLayout(mRecpLayout, 1, 1);
160     recipientGrid->setRowStretch(2, 1);
161 
162     // Scroll area for other keys
163     auto recipientWidget = new QWidget;
164     auto recipientScroll = new QScrollArea;
165     recipientWidget->setLayout(recipientGrid);
166     recipientScroll->setWidget(recipientWidget);
167     recipientScroll->setWidgetResizable(true);
168     recipientScroll->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow);
169     recipientScroll->setFrameStyle(QFrame::NoFrame);
170     recipientScroll->setFocusPolicy(Qt::NoFocus);
171     recipientGrid->setContentsMargins(0, 0, 0, 0);
172     encBoxLay->addWidget(recipientScroll, 1);
173 
174     auto bar = recipientScroll->verticalScrollBar();
175     connect (bar, &QScrollBar::rangeChanged, this, [bar] (int, int max) {
176             bar->setValue(max);
177         });
178 
179     addRecipientWidget();
180 
181     // Checkbox for password
182     mSymmetric = new QCheckBox(i18n("Encrypt with password. Anyone you share the password with can read the data."));
183     mSymmetric->setToolTip(i18nc("Tooltip information for symmetric encryption",
184                                  "Additionally to the keys of the recipients you can encrypt your data with a password. "
185                                  "Anyone who has the password can read the data without any secret key. "
186                                  "Using a password is <b>less secure</b> then public key cryptography. Even if you pick a very strong password."));
187     mSymmetric->setChecked(symmetricOnly || !havePublicKeys);
188     encBoxLay->addWidget(mSymmetric);
189 
190     // Connect it
191     connect(mEncSelfChk, &QCheckBox::toggled, mSelfSelect, &QWidget::setEnabled);
192     connect(mEncSelfChk, &QCheckBox::toggled, this, &SignEncryptWidget::updateOp);
193     connect(mSymmetric, &QCheckBox::toggled, this, &SignEncryptWidget::updateOp);
194     connect(mSelfSelect, &KeySelectionCombo::currentKeyChanged,
195             this, &SignEncryptWidget::updateOp);
196 
197     if (mIsExclusive) {
198         connect(mEncOtherChk, &QCheckBox::toggled, this, [this](bool value) {
199             if (mCurrentProto != GpgME::CMS) {
200                 return;
201             }
202             if (value) {
203                 mSigChk->setChecked(false);
204             }
205         });
206         connect(mEncSelfChk, &QCheckBox::toggled, this, [this](bool value) {
207             if (mCurrentProto != GpgME::CMS) {
208                 return;
209             }
210             if (value) {
211                 mSigChk->setChecked(false);
212             }
213         });
214         connect(mSigChk, &QCheckBox::toggled, this, [this](bool value) {
215             if (mCurrentProto != GpgME::CMS) {
216                 return;
217             }
218             if (value) {
219                 mEncSelfChk->setChecked(false);
220                 mEncOtherChk->setChecked(false);
221             }
222         });
223     }
224 
225     // Ensure that the mSigChk is aligned togehter with the encryption check boxes.
226     mSigChk->setMinimumWidth(qMax(mEncOtherChk->width(), mEncSelfChk->width()));
227 
228     lay->addWidget(encBox);
229 
230     connect(KeyCache::instance().get(), &Kleo::KeyCache::keysMayHaveChanged,
231             this, &SignEncryptWidget::updateCheckBoxes);
232     connect(KleopatraApplication::instance(), &KleopatraApplication::configurationChanged,
233             this, &SignEncryptWidget::updateCheckBoxes);
234 
235     loadKeys();
236     onProtocolChanged();
237     updateOp();
238 }
239 
setSignAsText(const QString & text)240 void SignEncryptWidget::setSignAsText(const QString &text)
241 {
242     mSigChk->setText(text);
243 }
244 
setEncryptForMeText(const QString & text)245 void SignEncryptWidget::setEncryptForMeText(const QString &text)
246 {
247     mEncSelfChk->setText(text);
248 }
249 
setEncryptForOthersText(const QString & text)250 void SignEncryptWidget::setEncryptForOthersText(const QString &text)
251 {
252     mEncOtherChk->setText(text);
253 }
254 
setEncryptWithPasswordText(const QString & text)255 void SignEncryptWidget::setEncryptWithPasswordText(const QString& text)
256 {
257     mSymmetric->setText(text);
258 }
259 
addRecipientWidget()260 CertificateLineEdit *SignEncryptWidget::addRecipientWidget()
261 {
262     auto certSel = new CertificateLineEdit(mModel, this,
263                                            new EncryptCertificateFilter(mCurrentProto));
264     certSel->setEnabled(mEncOtherChk->isChecked());
265     mRecpWidgets << certSel;
266 
267     if (mRecpLayout->count() > 0) {
268         auto lastWidget = mRecpLayout->itemAt(mRecpLayout->count() - 1)->widget();
269         setTabOrder(lastWidget, certSel);
270     }
271     mRecpLayout->addWidget(certSel);
272 
273     connect(certSel, &CertificateLineEdit::keyChanged,
274             this, &SignEncryptWidget::recipientsChanged);
275     connect(certSel, &CertificateLineEdit::wantsRemoval,
276             this, &SignEncryptWidget::recpRemovalRequested);
277     connect(certSel, &CertificateLineEdit::editingStarted,
278             this, &SignEncryptWidget::recipientsChanged);
279     connect(certSel, &CertificateLineEdit::dialogRequested,
280             this, [this, certSel] () { dialogRequested(certSel); });
281 
282     return certSel;
283 }
284 
addRecipient(const Key & key)285 void SignEncryptWidget::addRecipient(const Key &key)
286 {
287     CertificateLineEdit *certSel = addRecipientWidget();
288     if (!key.isNull()) {
289         certSel->setKey(key);
290         mAddedKeys << key;
291     }
292 }
293 
addRecipient(const KeyGroup & group)294 void SignEncryptWidget::addRecipient(const KeyGroup &group)
295 {
296     CertificateLineEdit *certSel = addRecipientWidget();
297     if (!group.isNull()) {
298         certSel->setGroup(group);
299         mAddedGroups << group;
300     }
301 }
302 
dialogRequested(CertificateLineEdit * certificateLineEdit)303 void SignEncryptWidget::dialogRequested(CertificateLineEdit *certificateLineEdit)
304 {
305     if (!certificateLineEdit->key().isNull()) {
306         auto cmd = new Commands::DetailsCommand(certificateLineEdit->key(), nullptr);
307         cmd->start();
308         return;
309     }
310     if (!certificateLineEdit->group().isNull()) {
311         auto dlg = new GroupDetailsDialog;
312         dlg->setAttribute(Qt::WA_DeleteOnClose);
313         dlg->setGroup(certificateLineEdit->group());
314         dlg->show();
315         return;
316     }
317 
318     auto const dlg = new CertificateSelectionDialog(this);
319 
320     dlg->setOptions(CertificateSelectionDialog::Options(
321         CertificateSelectionDialog::MultiSelection |
322         CertificateSelectionDialog::EncryptOnly |
323         CertificateSelectionDialog::optionsFromProtocol(mCurrentProto) |
324         CertificateSelectionDialog::IncludeGroups));
325 
326     if (dlg->exec()) {
327         const std::vector<Key> keys = dlg->selectedCertificates();
328         const std::vector<KeyGroup> groups = dlg->selectedGroups();
329         if (keys.size() == 0 && groups.size() == 0) {
330             return;
331         }
332         bool isFirstItem = true;
333         for (const Key &key : keys) {
334             if (isFirstItem) {
335                 certificateLineEdit->setKey(key);
336                 isFirstItem = false;
337             } else {
338                 addRecipient(key);
339             }
340         }
341         for (const KeyGroup &group : groups) {
342             if (isFirstItem) {
343                 certificateLineEdit->setGroup(group);
344                 isFirstItem = false;
345             } else {
346                 addRecipient(group);
347             }
348         }
349     }
350     delete dlg;
351     recipientsChanged();
352 }
353 
clearAddedRecipients()354 void SignEncryptWidget::clearAddedRecipients()
355 {
356     for (auto w: std::as_const(mUnknownWidgets)) {
357         mRecpLayout->removeWidget(w);
358         delete w;
359     }
360 
361     for (auto &key: std::as_const(mAddedKeys)) {
362         removeRecipient(key);
363     }
364 
365     for (auto &group: std::as_const(mAddedGroups)) {
366         removeRecipient(group);
367     }
368 }
369 
addUnknownRecipient(const char * keyID)370 void SignEncryptWidget::addUnknownRecipient(const char *keyID)
371 {
372     auto unknownWidget = new UnknownRecipientWidget(keyID);
373     mUnknownWidgets << unknownWidget;
374 
375     if (mRecpLayout->count() > 0) {
376         auto lastWidget = mRecpLayout->itemAt(mRecpLayout->count() - 1)->widget();
377         setTabOrder(lastWidget, unknownWidget);
378     }
379     mRecpLayout->addWidget(unknownWidget);
380 
381     connect(KeyCache::instance().get(), &Kleo::KeyCache::keysMayHaveChanged,
382             this, [this] () {
383         // Check if any unknown recipient can now be found.
384         for (auto w: mUnknownWidgets) {
385             auto key = KeyCache::instance()->findByKeyIDOrFingerprint(w->keyID().toLatin1().constData());
386             if (key.isNull()) {
387                 std::vector<std::string> subids;
388                 subids.push_back(std::string(w->keyID().toLatin1().constData()));
389                 for (const auto &subkey: KeyCache::instance()->findSubkeysByKeyID(subids)) {
390                     key = subkey.parent();
391                 }
392             }
393             if (key.isNull()) {
394                 continue;
395             }
396             // Key is now available replace by line edit.
397             qCDebug(KLEOPATRA_LOG) << "Removing widget for keyid: " << w->keyID();
398             mRecpLayout->removeWidget(w);
399             mUnknownWidgets.removeAll(w);
400             delete w;
401             addRecipient(key);
402         }
403     });
404 }
405 
recipientsChanged()406 void SignEncryptWidget::recipientsChanged()
407 {
408     const bool hasEmptyRecpWidget =
409         std::any_of(std::cbegin(mRecpWidgets), std::cend(mRecpWidgets),
410                     [](auto w) { return w->isEmpty(); });
411     if (!hasEmptyRecpWidget) {
412         addRecipientWidget();
413     }
414     updateOp();
415 }
416 
signKey() const417 Key SignEncryptWidget::signKey() const
418 {
419     if (mSigSelect->isEnabled()) {
420         return mSigSelect->currentKey();
421     }
422     return Key();
423 }
424 
selfKey() const425 Key SignEncryptWidget::selfKey() const
426 {
427     if (mSelfSelect->isEnabled()) {
428         return mSelfSelect->currentKey();
429     }
430     return Key();
431 }
432 
recipients() const433 std::vector<Key> SignEncryptWidget::recipients() const
434 {
435     std::vector<Key> ret;
436     for (const CertificateLineEdit *w : std::as_const(mRecpWidgets)) {
437         if (!w->isEnabled()) {
438             // If one is disabled, all are disabled.
439             break;
440         }
441         const Key k = w->key();
442         const KeyGroup g = w->group();
443         if (!k.isNull()) {
444             ret.push_back(k);
445         } else if (!g.isNull()) {
446             const auto keys = g.keys();
447             std::copy(keys.begin(), keys.end(), std::back_inserter(ret));
448         }
449     }
450     const Key k = selfKey();
451     if (!k.isNull()) {
452         ret.push_back(k);
453     }
454     return ret;
455 }
456 
isDeVsAndValid() const457 bool SignEncryptWidget::isDeVsAndValid() const
458 {
459     if (!signKey().isNull()
460         && (!IS_DE_VS(signKey()) || keyValidity(signKey()) < GpgME::UserID::Validity::Full)) {
461         return false;
462     }
463 
464     if (!selfKey().isNull()
465         && (!IS_DE_VS(selfKey()) || keyValidity(selfKey()) < GpgME::UserID::Validity::Full)) {
466         return false;
467     }
468 
469     for (const auto &key: recipients()) {
470         if (!IS_DE_VS(key) || keyValidity(key) < GpgME::UserID::Validity::Full) {
471             return false;
472         }
473     }
474 
475     return true;
476 }
477 
updateOp()478 void SignEncryptWidget::updateOp()
479 {
480     const Key sigKey = signKey();
481     const std::vector<Key> recp = recipients();
482 
483     QString newOp;
484     if (!sigKey.isNull() && (!recp.empty() || encryptSymmetric())) {
485         newOp = i18nc("@action", "Sign / Encrypt");
486     } else if (!recp.empty() || encryptSymmetric()) {
487         newOp = i18nc("@action", "Encrypt");
488     } else if (!sigKey.isNull()) {
489         newOp = i18nc("@action", "Sign");
490     } else {
491         newOp = QString();
492     }
493     mOp = newOp;
494     Q_EMIT operationChanged(mOp);
495     Q_EMIT keysChanged();
496 }
497 
currentOp() const498 QString SignEncryptWidget::currentOp() const
499 {
500     return mOp;
501 }
502 
recpRemovalRequested(CertificateLineEdit * w)503 void SignEncryptWidget::recpRemovalRequested(CertificateLineEdit *w)
504 {
505     if (!w) {
506         return;
507     }
508     const int emptyEdits =
509         std::count_if(std::cbegin(mRecpWidgets), std::cend(mRecpWidgets),
510                       [](auto w) { return w->isEmpty(); });
511     if (emptyEdits > 1) {
512         if (w->hasFocus()) {
513             const int index = mRecpLayout->indexOf(w);
514             const auto focusWidget = (index < mRecpLayout->count() - 1) ?
515                 mRecpLayout->itemAt(index + 1)->widget() :
516                 mRecpLayout->itemAt(mRecpLayout->count() - 2)->widget();
517             focusWidget->setFocus();
518         }
519         mRecpLayout->removeWidget(w);
520         mRecpWidgets.removeAll(w);
521         w->deleteLater();
522     }
523 }
524 
removeRecipient(const GpgME::Key & key)525 void SignEncryptWidget::removeRecipient(const GpgME::Key &key)
526 {
527     for (CertificateLineEdit *edit: std::as_const(mRecpWidgets)) {
528         const auto editKey = edit->key();
529         if (key.isNull() && editKey.isNull()) {
530             recpRemovalRequested(edit);
531             return;
532         }
533         if (editKey.primaryFingerprint() &&
534             key.primaryFingerprint() &&
535             !strcmp(editKey.primaryFingerprint(), key.primaryFingerprint())) {
536             recpRemovalRequested(edit);
537             return;
538         }
539     }
540 }
541 
removeRecipient(const KeyGroup & group)542 void SignEncryptWidget::removeRecipient(const KeyGroup &group)
543 {
544     for (CertificateLineEdit *edit: std::as_const(mRecpWidgets)) {
545         const auto editGroup = edit->group();
546         if (group.isNull() && editGroup.isNull()) {
547             recpRemovalRequested(edit);
548             return;
549         }
550         if (editGroup.name() == group.name()) {
551             recpRemovalRequested(edit);
552             return;
553         }
554     }
555 }
556 
encryptSymmetric() const557 bool SignEncryptWidget::encryptSymmetric() const
558 {
559     return mSymmetric->isChecked();
560 }
561 
loadKeys()562 void SignEncryptWidget::loadKeys()
563 {
564     KConfigGroup keys(KSharedConfig::openConfig(), "SignEncryptKeys");
565     auto cache = KeyCache::instance();
566     mSigSelect->setDefaultKey(keys.readEntry("SigningKey", QString()));
567     mSelfSelect->setDefaultKey(keys.readEntry("EncryptKey", QString()));
568 }
569 
saveOwnKeys() const570 void SignEncryptWidget::saveOwnKeys() const
571 {
572     KConfigGroup keys(KSharedConfig::openConfig(), "SignEncryptKeys");
573     auto sigKey = mSigSelect->currentKey();
574     auto encKey = mSelfSelect->currentKey();
575     if (!sigKey.isNull()) {
576         keys.writeEntry("SigningKey", sigKey.primaryFingerprint());
577     }
578     if (!encKey.isNull()) {
579         keys.writeEntry("EncryptKey", encKey.primaryFingerprint());
580     }
581 }
582 
setSigningChecked(bool value)583 void SignEncryptWidget::setSigningChecked(bool value)
584 {
585     mSigChk->setChecked(value && !KeyCache::instance()->secretKeys().empty());
586 }
587 
setEncryptionChecked(bool checked)588 void SignEncryptWidget::setEncryptionChecked(bool checked)
589 {
590     if (checked) {
591         const bool haveSecretKeys = !KeyCache::instance()->secretKeys().empty();
592         const bool havePublicKeys = !KeyCache::instance()->keys().empty();
593         const bool symmetricOnly = FileOperationsPreferences().symmetricEncryptionOnly();
594         mEncSelfChk->setChecked(haveSecretKeys && !symmetricOnly);
595         mEncOtherChk->setChecked(havePublicKeys && !symmetricOnly);
596         mSymmetric->setChecked(symmetricOnly || !havePublicKeys);
597     } else {
598         mEncSelfChk->setChecked(false);
599         mEncOtherChk->setChecked(false);
600         mSymmetric->setChecked(false);
601     }
602 }
603 
setProtocol(GpgME::Protocol proto)604 void SignEncryptWidget::setProtocol(GpgME::Protocol proto)
605 {
606     if (mCurrentProto == proto) {
607         return;
608     }
609     mCurrentProto = proto;
610     onProtocolChanged();
611 }
612 
onProtocolChanged()613 void Kleo::SignEncryptWidget::onProtocolChanged()
614 {
615     mSigSelect->setKeyFilter(std::shared_ptr<KeyFilter>(new SignCertificateFilter(mCurrentProto)));
616     mSelfSelect->setKeyFilter(std::shared_ptr<KeyFilter>(new EncryptSelfCertificateFilter(mCurrentProto)));
617     const auto encFilter = std::shared_ptr<KeyFilter>(new EncryptCertificateFilter(mCurrentProto));
618     for (CertificateLineEdit *edit : std::as_const(mRecpWidgets)) {
619         edit->setKeyFilter(encFilter);
620     }
621 
622     if (mIsExclusive) {
623         mSymmetric->setDisabled(mCurrentProto == GpgME::CMS);
624         if (mSymmetric->isChecked() && mCurrentProto == GpgME::CMS) {
625             mSymmetric->setChecked(false);
626         }
627         if (mSigChk->isChecked() && mCurrentProto == GpgME::CMS &&
628                 (mEncSelfChk->isChecked() || mEncOtherChk->isChecked())) {
629             mSigChk->setChecked(false);
630         }
631     }
632 }
633 
validate()634 bool SignEncryptWidget::validate()
635 {
636     QStringList unresolvedRecipients;
637     for (const auto edit: std::as_const(mRecpWidgets)) {
638         if (edit->isEnabled() && !edit->isEmpty() && edit->key().isNull() && edit->group().isNull()) {
639             unresolvedRecipients.push_back(edit->text().toHtmlEscaped());
640         }
641     }
642     if (!unresolvedRecipients.isEmpty()) {
643         KMessageBox::errorList(this,
644                                i18n("Could not find a key for the following recipients:"),
645                                unresolvedRecipients,
646                                i18n("Failed to find some keys"));
647     }
648     return unresolvedRecipients.isEmpty();
649 }
650 
updateCheckBoxes()651 void SignEncryptWidget::updateCheckBoxes()
652 {
653     const bool haveSecretKeys = !KeyCache::instance()->secretKeys().empty();
654     const bool havePublicKeys = !KeyCache::instance()->keys().empty();
655     const bool symmetricOnly = FileOperationsPreferences().symmetricEncryptionOnly();
656     mSigChk->setEnabled(haveSecretKeys);
657     mEncSelfChk->setEnabled(haveSecretKeys && !symmetricOnly);
658     mEncOtherChk->setEnabled(havePublicKeys && !symmetricOnly);
659     if (symmetricOnly) {
660         mEncSelfChk->setChecked(false);
661         mEncOtherChk->setChecked(false);
662         mSymmetric->setChecked(true);
663     }
664 }
665