signencryptwidget.cpp 21.6 KB
Newer Older
1
/*  crypto/gui/signencryptwidget.cpp
2
3

    This file is part of Kleopatra, the KDE keymanager
4
5
    SPDX-FileCopyrightText: 2016 Bundesamt für Sicherheit in der Informationstechnik
    SPDX-FileContributor: Intevation GmbH
6

7
    SPDX-License-Identifier: GPL-2.0-or-later
8
9
10
11
12
13
*/

#include "signencryptwidget.h"

#include "kleopatra_debug.h"

14
#include "certificatelineedit.h"
15
#include "fileoperationspreferences.h"
16
#include "kleopatraapplication.h"
17
#include "settings.h"
18
#include "unknownrecipientwidget.h"
19

20
21
22
#include "commands/detailscommand.h"

#include "dialogs/certificateselectiondialog.h"
23
#include "dialogs/groupdetailsdialog.h"
24

25
26
27
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGroupBox>
28
29
#include <QCheckBox>
#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
47
48
49

using namespace Kleo;
using namespace Kleo::Dialogs;
using namespace GpgME;

50
51
52
53
namespace {
class SignCertificateFilter: public DefaultKeyFilter
{
public:
54
    SignCertificateFilter(GpgME::Protocol proto) : DefaultKeyFilter()
55
56
57
58
59
    {
        setRevoked(DefaultKeyFilter::NotSet);
        setExpired(DefaultKeyFilter::NotSet);
        setHasSecret(DefaultKeyFilter::Set);
        setCanSign(DefaultKeyFilter::Set);
60
61
62
63
64
65

        if (proto == GpgME::OpenPGP) {
            setIsOpenPGP(DefaultKeyFilter::Set);
        } else if (proto == GpgME::CMS) {
            setIsOpenPGP(DefaultKeyFilter::NotSet);
        }
66
67
68
69
70
    }
};
class EncryptCertificateFilter: public DefaultKeyFilter
{
public:
71
    EncryptCertificateFilter(GpgME::Protocol proto): DefaultKeyFilter()
72
73
74
75
    {
        setRevoked(DefaultKeyFilter::NotSet);
        setExpired(DefaultKeyFilter::NotSet);
        setCanEncrypt(DefaultKeyFilter::Set);
76
77
78
79
80
81

        if (proto == GpgME::OpenPGP) {
            setIsOpenPGP(DefaultKeyFilter::Set);
        } else if (proto == GpgME::CMS) {
            setIsOpenPGP(DefaultKeyFilter::NotSet);
        }
82
83
84
85
86
    }
};
class EncryptSelfCertificateFilter: public EncryptCertificateFilter
{
public:
87
    EncryptSelfCertificateFilter(GpgME::Protocol proto): EncryptCertificateFilter(proto)
88
89
90
91
92
93
94
95
96
    {
        setRevoked(DefaultKeyFilter::NotSet);
        setExpired(DefaultKeyFilter::NotSet);
        setCanEncrypt(DefaultKeyFilter::Set);
        setHasSecret(DefaultKeyFilter::Set);
    }
};
}

97
SignEncryptWidget::SignEncryptWidget(QWidget *parent, bool sigEncExclusive)
98
    : QWidget(parent),
99
      mModel(AbstractKeyListModel::createFlatKeyListModel(this)),
100
      mIsExclusive(sigEncExclusive)
101
{
Laurent Montel's avatar
Laurent Montel committed
102
    auto lay = new QVBoxLayout(this);
Laurent Montel's avatar
Laurent Montel committed
103
    lay->setContentsMargins(0, 0, 0, 0);
104

105
    mModel->useKeyCache(true, KeyList::IncludeGroups);
106

107
108
    const bool haveSecretKeys = !KeyCache::instance()->secretKeys().empty();
    const bool havePublicKeys = !KeyCache::instance()->keys().empty();
109
    const bool symmetricOnly = FileOperationsPreferences().symmetricEncryptionOnly();
110

111
    /* The signature selection */
Laurent Montel's avatar
Laurent Montel committed
112
    auto sigLay = new QHBoxLayout;
113
    auto sigGrp = new QGroupBox(i18nc("@title:group", "Prove authenticity (sign)"));
114
    mSigChk = new QCheckBox(i18n("Sign as:"));
115
116
    mSigChk->setEnabled(haveSecretKeys);
    mSigChk->setChecked(haveSecretKeys);
117

118
    mSigSelect = new KeySelectionCombo();
119
    mSigSelect->setEnabled(mSigChk->isChecked());
120

121
    sigLay->addWidget(mSigChk);
122
    sigLay->addWidget(mSigSelect, 1);
123
124
    sigGrp->setLayout(sigLay);
    lay->addWidget(sigGrp);
125

126
127
    connect(mSigChk, &QCheckBox::toggled, mSigSelect, &QWidget::setEnabled);
    connect(mSigChk, &QCheckBox::toggled, this, &SignEncryptWidget::updateOp);
128
    connect(mSigSelect, &KeySelectionCombo::currentKeyChanged,
129
130
            this, &SignEncryptWidget::updateOp);

131
    // Recipient selection
Laurent Montel's avatar
Laurent Montel committed
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
140
    mEncSelfChk->setEnabled(haveSecretKeys && !symmetricOnly);
    mEncSelfChk->setChecked(haveSecretKeys && !symmetricOnly);
141
    mSelfSelect = new KeySelectionCombo();
142
    mSelfSelect->setEnabled(mEncSelfChk->isChecked());
143
144
    recipientGrid->addWidget(mEncSelfChk, 0, 0);
    recipientGrid->addWidget(mSelfSelect, 0, 1);
145
146

    // Checkbox for other keys
147
    mEncOtherChk = new QCheckBox(i18n("Encrypt for others:"));
148
149
    mEncOtherChk->setEnabled(havePublicKeys && !symmetricOnly);
    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
155
156
157
                edit->setEnabled(toggled);
            }
            updateOp();
        });
158
159
    mRecpLayout = new QVBoxLayout;
    recipientGrid->addLayout(mRecpLayout, 1, 1);
160
    recipientGrid->setRowStretch(2, 1);
161
162

    // Scroll area for other keys
Laurent Montel's avatar
Laurent Montel committed
163
164
    auto recipientWidget = new QWidget;
    auto recipientScroll = new QScrollArea;
165
    recipientWidget->setLayout(recipientGrid);
166
167
168
    recipientScroll->setWidget(recipientWidget);
    recipientScroll->setWidgetResizable(true);
    recipientScroll->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow);
169
    recipientScroll->setFrameStyle(QFrame::NoFrame);
170
    recipientScroll->setFocusPolicy(Qt::NoFocus);
171
    recipientGrid->setContentsMargins(0, 0, 0, 0);
172
173
    encBoxLay->addWidget(recipientScroll, 1);

174
175
176
177
178
    auto bar = recipientScroll->verticalScrollBar();
    connect (bar, &QScrollBar::rangeChanged, this, [bar] (int, int max) {
            bar->setValue(max);
        });

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. "
Yuri Chornoivan's avatar
Yuri Chornoivan committed
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
192
    connect(mEncSelfChk, &QCheckBox::toggled, mSelfSelect, &QWidget::setEnabled);
    connect(mEncSelfChk, &QCheckBox::toggled, this, &SignEncryptWidget::updateOp);
193
    connect(mSymmetric, &QCheckBox::toggled, this, &SignEncryptWidget::updateOp);
194
    connect(mSelfSelect, &KeySelectionCombo::currentKeyChanged,
195
196
            this, &SignEncryptWidget::updateOp);

197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
    if (mIsExclusive) {
        connect(mEncOtherChk, &QCheckBox::toggled, this, [this](bool value) {
            if (mCurrentProto != GpgME::CMS) {
                return;
            }
            if (value) {
                mSigChk->setChecked(false);
            }
        });
        connect(mEncSelfChk, &QCheckBox::toggled, this, [this](bool value) {
            if (mCurrentProto != GpgME::CMS) {
                return;
            }
            if (value) {
                mSigChk->setChecked(false);
            }
        });
        connect(mSigChk, &QCheckBox::toggled, this, [this](bool value) {
            if (mCurrentProto != GpgME::CMS) {
                return;
            }
            if (value) {
                mEncSelfChk->setChecked(false);
                mEncOtherChk->setChecked(false);
            }
        });
    }

225
226
    // Ensure that the mSigChk is aligned togehter with the encryption check boxes.
    mSigChk->setMinimumWidth(qMax(mEncOtherChk->width(), mEncSelfChk->width()));
227

228
229
    lay->addWidget(encBox);

230
    connect(KeyCache::instance().get(), &Kleo::KeyCache::keysMayHaveChanged,
231
232
233
            this, &SignEncryptWidget::updateCheckBoxes);
    connect(KleopatraApplication::instance(), &KleopatraApplication::configurationChanged,
            this, &SignEncryptWidget::updateCheckBoxes);
234

235
    loadKeys();
236
    onProtocolChanged();
237
238
239
    updateOp();
}

240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
void SignEncryptWidget::setSignAsText(const QString &text)
{
    mSigChk->setText(text);
}

void SignEncryptWidget::setEncryptForMeText(const QString &text)
{
    mEncSelfChk->setText(text);
}

void SignEncryptWidget::setEncryptForOthersText(const QString &text)
{
    mEncOtherChk->setText(text);
}

void SignEncryptWidget::setEncryptWithPasswordText(const QString& text)
{
    mSymmetric->setText(text);
}

260
CertificateLineEdit *SignEncryptWidget::addRecipientWidget()
261
{
262
263
264
    auto certSel = new CertificateLineEdit(mModel,
                                           new EncryptCertificateFilter(mCurrentProto),
                                           this);
265
    certSel->setAccessibleName(i18nc("text for screen readers", "recipient key"));
266
    certSel->setEnabled(mEncOtherChk->isChecked());
267
    mRecpWidgets << certSel;
268

269
270
271
272
    if (mRecpLayout->count() > 0) {
        auto lastWidget = mRecpLayout->itemAt(mRecpLayout->count() - 1)->widget();
        setTabOrder(lastWidget, certSel);
    }
273
    mRecpLayout->addWidget(certSel);
274

275
    connect(certSel, &CertificateLineEdit::keyChanged,
276
            this, &SignEncryptWidget::recipientsChanged);
277
278
279
    connect(certSel, &CertificateLineEdit::wantsRemoval,
            this, &SignEncryptWidget::recpRemovalRequested);
    connect(certSel, &CertificateLineEdit::editingStarted,
280
            this, &SignEncryptWidget::recipientsChanged);
281
282
    connect(certSel, &CertificateLineEdit::dialogRequested,
            this, [this, certSel] () { dialogRequested(certSel); });
283
284
    connect(certSel, &CertificateLineEdit::certificateSelectionRequested,
            this, [this, certSel]() { certificateSelectionRequested(certSel); });
285

286
287
288
289
290
291
    return certSel;
}

void SignEncryptWidget::addRecipient(const Key &key)
{
    CertificateLineEdit *certSel = addRecipientWidget();
292
293
    if (!key.isNull()) {
        certSel->setKey(key);
294
        mAddedKeys << key;
295
    }
296
297
}

298
299
300
301
302
303
304
305
306
void SignEncryptWidget::addRecipient(const KeyGroup &group)
{
    CertificateLineEdit *certSel = addRecipientWidget();
    if (!group.isNull()) {
        certSel->setGroup(group);
        mAddedGroups << group;
    }
}

307
308
309
310
311
312
313
void SignEncryptWidget::dialogRequested(CertificateLineEdit *certificateLineEdit)
{
    if (!certificateLineEdit->key().isNull()) {
        auto cmd = new Commands::DetailsCommand(certificateLineEdit->key(), nullptr);
        cmd->start();
        return;
    }
314
    if (!certificateLineEdit->group().isNull()) {
Laurent Montel's avatar
Laurent Montel committed
315
        auto dlg = new GroupDetailsDialog;
316
317
318
319
320
        dlg->setAttribute(Qt::WA_DeleteOnClose);
        dlg->setGroup(certificateLineEdit->group());
        dlg->show();
        return;
    }
321

322
323
324
325
326
327
    certificateSelectionRequested(certificateLineEdit);
}

void SignEncryptWidget::certificateSelectionRequested(CertificateLineEdit *certificateLineEdit)
{
    CertificateSelectionDialog dlg{this};
328

329
    dlg.setOptions(CertificateSelectionDialog::Options(
330
331
332
333
        CertificateSelectionDialog::MultiSelection |
        CertificateSelectionDialog::EncryptOnly |
        CertificateSelectionDialog::optionsFromProtocol(mCurrentProto) |
        CertificateSelectionDialog::IncludeGroups));
334
    dlg.setStringFilter(certificateLineEdit->text());
335

336
337
338
    if (dlg.exec()) {
        const std::vector<Key> keys = dlg.selectedCertificates();
        const std::vector<KeyGroup> groups = dlg.selectedGroups();
339
        if (keys.size() == 0 && groups.size() == 0) {
340
341
            return;
        }
342
343
344
345
346
        bool isFirstItem = true;
        for (const Key &key : keys) {
            if (isFirstItem) {
                certificateLineEdit->setKey(key);
                isFirstItem = false;
347
            } else {
348
349
350
351
352
353
354
355
356
                addRecipient(key);
            }
        }
        for (const KeyGroup &group : groups) {
            if (isFirstItem) {
                certificateLineEdit->setGroup(group);
                isFirstItem = false;
            } else {
                addRecipient(group);
357
358
359
            }
        }
    }
360

361
362
363
    recipientsChanged();
}

364
365
void SignEncryptWidget::clearAddedRecipients()
{
366
    for (auto w: std::as_const(mUnknownWidgets)) {
367
368
369
370
        mRecpLayout->removeWidget(w);
        delete w;
    }

371
    for (auto &key: std::as_const(mAddedKeys)) {
372
373
        removeRecipient(key);
    }
374

375
    for (auto &group: std::as_const(mAddedGroups)) {
376
377
        removeRecipient(group);
    }
378
379
380
381
382
383
384
}

void SignEncryptWidget::addUnknownRecipient(const char *keyID)
{
    auto unknownWidget = new UnknownRecipientWidget(keyID);
    mUnknownWidgets << unknownWidget;

385
386
387
388
    if (mRecpLayout->count() > 0) {
        auto lastWidget = mRecpLayout->itemAt(mRecpLayout->count() - 1)->widget();
        setTabOrder(lastWidget, unknownWidget);
    }
389
    mRecpLayout->addWidget(unknownWidget);
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415

    connect(KeyCache::instance().get(), &Kleo::KeyCache::keysMayHaveChanged,
            this, [this] () {
        // Check if any unknown recipient can now be found.
        for (auto w: mUnknownWidgets) {
            auto key = KeyCache::instance()->findByKeyIDOrFingerprint(w->keyID().toLatin1().constData());
            if (key.isNull()) {
                std::vector<std::string> subids;
                subids.push_back(std::string(w->keyID().toLatin1().constData()));
                for (const auto &subkey: KeyCache::instance()->findSubkeysByKeyID(subids)) {
                    key = subkey.parent();
                }
            }
            if (key.isNull()) {
                continue;
            }
            // Key is now available replace by line edit.
            qCDebug(KLEOPATRA_LOG) << "Removing widget for keyid: " << w->keyID();
            mRecpLayout->removeWidget(w);
            mUnknownWidgets.removeAll(w);
            delete w;
            addRecipient(key);
        }
    });
}

416
417
void SignEncryptWidget::recipientsChanged()
{
418
419
420
421
    const bool hasEmptyRecpWidget =
        std::any_of(std::cbegin(mRecpWidgets), std::cend(mRecpWidgets),
                    [](auto w) { return w->isEmpty(); });
    if (!hasEmptyRecpWidget) {
422
        addRecipientWidget();
423
    }
424
    updateOp();
425
426
427
428
429
}

Key SignEncryptWidget::signKey() const
{
    if (mSigSelect->isEnabled()) {
430
        return mSigSelect->currentKey();
431
432
433
434
435
436
    }
    return Key();
}

Key SignEncryptWidget::selfKey() const
{
437
    if (mSelfSelect->isEnabled()) {
438
        return mSelfSelect->currentKey();
439
    }
440
441
442
    return Key();
}

443
std::vector<Key> SignEncryptWidget::recipients() const
444
{
445
    std::vector<Key> ret;
446
    for (const CertificateLineEdit *w : std::as_const(mRecpWidgets)) {
447
448
449
450
451
        if (!w->isEnabled()) {
            // If one is disabled, all are disabled.
            break;
        }
        const Key k = w->key();
452
        const KeyGroup g = w->group();
453
        if (!k.isNull()) {
454
            ret.push_back(k);
455
456
457
        } else if (!g.isNull()) {
            const auto keys = g.keys();
            std::copy(keys.begin(), keys.end(), std::back_inserter(ret));
458
459
460
461
        }
    }
    const Key k = selfKey();
    if (!k.isNull()) {
462
        ret.push_back(k);
463
464
    }
    return ret;
465
466
}

467
468
469
470
471
472
473
474
bool SignEncryptWidget::isDeVsAndValid() const
{
    if (!signKey().isNull()
        && (!IS_DE_VS(signKey()) || keyValidity(signKey()) < GpgME::UserID::Validity::Full)) {
        return false;
    }

    if (!selfKey().isNull()
Andre Heinecke's avatar
Andre Heinecke committed
475
        && (!IS_DE_VS(selfKey()) || keyValidity(selfKey()) < GpgME::UserID::Validity::Full)) {
476
477
478
479
        return false;
    }

    for (const auto &key: recipients()) {
480
        if (!IS_DE_VS(key) || keyValidity(key) < GpgME::UserID::Validity::Full) {
481
482
483
484
485
486
487
            return false;
        }
    }

    return true;
}

488
489
void SignEncryptWidget::updateOp()
{
490
    const Key sigKey = signKey();
491
    const std::vector<Key> recp = recipients();
492

493
    QString newOp;
494
    if (!sigKey.isNull() && (!recp.empty() || encryptSymmetric())) {
495
        newOp = i18nc("@action", "Sign / Encrypt");
496
    } else if (!recp.empty() || encryptSymmetric()) {
497
498
499
        newOp = i18nc("@action", "Encrypt");
    } else if (!sigKey.isNull()) {
        newOp = i18nc("@action", "Sign");
500
    } else {
501
502
        newOp = QString();
    }
503
504
    mOp = newOp;
    Q_EMIT operationChanged(mOp);
505
    Q_EMIT keysChanged();
506
507
508
509
510
511
}

QString SignEncryptWidget::currentOp() const
{
    return mOp;
}
512
513
514
515
516
517

void SignEncryptWidget::recpRemovalRequested(CertificateLineEdit *w)
{
    if (!w) {
        return;
    }
518
519
520
521
522
523
524
525
526
527
    const int emptyEdits =
        std::count_if(std::cbegin(mRecpWidgets), std::cend(mRecpWidgets),
                      [](auto w) { return w->isEmpty(); });
    if (emptyEdits > 1) {
        if (w->hasFocus()) {
            const int index = mRecpLayout->indexOf(w);
            const auto focusWidget = (index < mRecpLayout->count() - 1) ?
                mRecpLayout->itemAt(index + 1)->widget() :
                mRecpLayout->itemAt(mRecpLayout->count() - 2)->widget();
            focusWidget->setFocus();
528
        }
529
530
531
        mRecpLayout->removeWidget(w);
        mRecpWidgets.removeAll(w);
        w->deleteLater();
532
533
    }
}
534

535
536
void SignEncryptWidget::removeRecipient(const GpgME::Key &key)
{
537
    for (CertificateLineEdit *edit: std::as_const(mRecpWidgets)) {
538
539
540
541
542
543
544
545
546
547
548
549
550
551
        const auto editKey = edit->key();
        if (key.isNull() && editKey.isNull()) {
            recpRemovalRequested(edit);
            return;
        }
        if (editKey.primaryFingerprint() &&
            key.primaryFingerprint() &&
            !strcmp(editKey.primaryFingerprint(), key.primaryFingerprint())) {
            recpRemovalRequested(edit);
            return;
        }
    }
}

552
553
void SignEncryptWidget::removeRecipient(const KeyGroup &group)
{
554
    for (CertificateLineEdit *edit: std::as_const(mRecpWidgets)) {
555
556
557
558
559
560
561
562
563
564
565
566
        const auto editGroup = edit->group();
        if (group.isNull() && editGroup.isNull()) {
            recpRemovalRequested(edit);
            return;
        }
        if (editGroup.name() == group.name()) {
            recpRemovalRequested(edit);
            return;
        }
    }
}

567
bool SignEncryptWidget::encryptSymmetric() const
568
{
569
    return mSymmetric->isChecked();
570
}
571
572
573
574
575

void SignEncryptWidget::loadKeys()
{
    KConfigGroup keys(KSharedConfig::openConfig(), "SignEncryptKeys");
    auto cache = KeyCache::instance();
576
577
    mSigSelect->setDefaultKey(keys.readEntry("SigningKey", QString()));
    mSelfSelect->setDefaultKey(keys.readEntry("EncryptKey", QString()));
578
579
580
581
582
583
584
585
586
587
588
589
590
591
}

void SignEncryptWidget::saveOwnKeys() const
{
    KConfigGroup keys(KSharedConfig::openConfig(), "SignEncryptKeys");
    auto sigKey = mSigSelect->currentKey();
    auto encKey = mSelfSelect->currentKey();
    if (!sigKey.isNull()) {
        keys.writeEntry("SigningKey", sigKey.primaryFingerprint());
    }
    if (!encKey.isNull()) {
        keys.writeEntry("EncryptKey", encKey.primaryFingerprint());
    }
}
592
593
594

void SignEncryptWidget::setSigningChecked(bool value)
{
595
    mSigChk->setChecked(value && !KeyCache::instance()->secretKeys().empty());
596
597
}

598
void SignEncryptWidget::setEncryptionChecked(bool checked)
599
{
600
    if (checked) {
601
602
        const bool haveSecretKeys = !KeyCache::instance()->secretKeys().empty();
        const bool havePublicKeys = !KeyCache::instance()->keys().empty();
603
604
605
606
        const bool symmetricOnly = FileOperationsPreferences().symmetricEncryptionOnly();
        mEncSelfChk->setChecked(haveSecretKeys && !symmetricOnly);
        mEncOtherChk->setChecked(havePublicKeys && !symmetricOnly);
        mSymmetric->setChecked(symmetricOnly || !havePublicKeys);
607
608
609
610
611
    } else {
        mEncSelfChk->setChecked(false);
        mEncOtherChk->setChecked(false);
        mSymmetric->setChecked(false);
    }
612
}
613
614
615
616
617
618
619

void SignEncryptWidget::setProtocol(GpgME::Protocol proto)
{
    if (mCurrentProto == proto) {
        return;
    }
    mCurrentProto = proto;
620
621
622
623
624
625
626
627
    onProtocolChanged();
}

void Kleo::SignEncryptWidget::onProtocolChanged()
{
    mSigSelect->setKeyFilter(std::shared_ptr<KeyFilter>(new SignCertificateFilter(mCurrentProto)));
    mSelfSelect->setKeyFilter(std::shared_ptr<KeyFilter>(new EncryptSelfCertificateFilter(mCurrentProto)));
    const auto encFilter = std::shared_ptr<KeyFilter>(new EncryptCertificateFilter(mCurrentProto));
628
    for (CertificateLineEdit *edit : std::as_const(mRecpWidgets)) {
629
630
        edit->setKeyFilter(encFilter);
    }
631
632

    if (mIsExclusive) {
633
634
        mSymmetric->setDisabled(mCurrentProto == GpgME::CMS);
        if (mSymmetric->isChecked() && mCurrentProto == GpgME::CMS) {
635
636
            mSymmetric->setChecked(false);
        }
637
        if (mSigChk->isChecked() && mCurrentProto == GpgME::CMS &&
638
639
640
641
                (mEncSelfChk->isChecked() || mEncOtherChk->isChecked())) {
            mSigChk->setChecked(false);
        }
    }
642
}
643
644
645

bool SignEncryptWidget::validate()
{
646
    QStringList unresolvedRecipients;
647
    for (const auto edit: std::as_const(mRecpWidgets)) {
648
649
        if (edit->isEnabled() && !edit->isEmpty() && edit->key().isNull() && edit->group().isNull()) {
            unresolvedRecipients.push_back(edit->text().toHtmlEscaped());
650
651
        }
    }
652
653
654
655
656
657
658
    if (!unresolvedRecipients.isEmpty()) {
        KMessageBox::errorList(this,
                               i18n("Could not find a key for the following recipients:"),
                               unresolvedRecipients,
                               i18n("Failed to find some keys"));
    }
    return unresolvedRecipients.isEmpty();
659
}
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674

void SignEncryptWidget::updateCheckBoxes()
{
    const bool haveSecretKeys = !KeyCache::instance()->secretKeys().empty();
    const bool havePublicKeys = !KeyCache::instance()->keys().empty();
    const bool symmetricOnly = FileOperationsPreferences().symmetricEncryptionOnly();
    mSigChk->setEnabled(haveSecretKeys);
    mEncSelfChk->setEnabled(haveSecretKeys && !symmetricOnly);
    mEncOtherChk->setEnabled(havePublicKeys && !symmetricOnly);
    if (symmetricOnly) {
        mEncSelfChk->setChecked(false);
        mEncOtherChk->setChecked(false);
        mSymmetric->setChecked(true);
    }
}