File indexing completed on 2024-04-14 05:43:37

0001 /*
0002     SPDX-FileCopyrightText: 2002 Jean-Baptiste Mardelle <bj@altern.org>
0003     SPDX-FileCopyrightText: 2007, 2008, 2009, 2010, 2011, 2012 Rolf Eike Beer <kde@opensource.sf-tec.de>
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "selectpublickeydialog.h"
0008 
0009 #include "kgpgsettings.h"
0010 #include "core/images.h"
0011 #include "core/KGpgRootNode.h"
0012 #include "model/kgpgitemmodel.h"
0013 #include "model/selectkeyproxymodel.h"
0014 
0015 #include <QAction>
0016 #include <QCheckBox>
0017 #include <QDialogButtonBox>
0018 #include <QHBoxLayout>
0019 #include <QLabel>
0020 #include <QLineEdit>
0021 #include <QPushButton>
0022 #include <QTableView>
0023 
0024 #include <KActionCollection>
0025 #include <KConfigGroup>
0026 #include <KLocalizedString>
0027 
0028 using namespace KgpgCore;
0029 
0030 KgpgSelectPublicKeyDlg::KgpgSelectPublicKeyDlg(QWidget *parent, KGpgItemModel *model, const QKeySequence &goDefaultKey, const bool hideasciioption, const QList<QUrl> &files)
0031     : QDialog(parent),
0032     m_customoptions(nullptr),
0033     imodel(model),
0034     m_files(files),
0035     m_hideasciioption(hideasciioption)
0036 {
0037     QWidget *mainWidget = new QWidget(this);
0038     QVBoxLayout *mainLayout = new QVBoxLayout(this);
0039     setLayout(mainLayout);
0040     mainLayout->setSizeConstraint(QLayout::SetMinimumSize);
0041     mainLayout->addWidget(mainWidget);
0042 
0043     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel);
0044     m_okButton = buttonBox->button(QDialogButtonBox::Ok);
0045     m_okButton->setDefault(true);
0046     m_okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
0047     m_detailsButton = new QPushButton(this);
0048     m_detailsButton->setText(i18n("&Options") + QStringLiteral(" >>"));
0049     m_detailsButton->setIcon(QIcon::fromTheme(QStringLiteral("help-about")));
0050     connect(m_detailsButton, &QPushButton::clicked, this, &KgpgSelectPublicKeyDlg::toggleDetails);
0051     buttonBox->addButton(m_detailsButton, QDialogButtonBox::ActionRole);
0052     connect(buttonBox, &QDialogButtonBox::accepted, this, &KgpgSelectPublicKeyDlg::accept);
0053     connect(buttonBox, &QDialogButtonBox::rejected, this, &KgpgSelectPublicKeyDlg::reject);
0054     m_okButton->setDefault(true);
0055 
0056     int fcount = files.count();
0057     bool fmode = (fcount > 0);
0058 
0059     switch (fcount) {
0060     case 0:
0061     setWindowTitle(i18n("Select Public Key"));
0062     break;
0063     case 1:
0064     setWindowTitle(i18n("Select Public Key for %1", files.first().fileName()));
0065     break;
0066     default:
0067     setWindowTitle(i18np("Select Public Key for %2 and one more file", "Select Public Key for %2 and %1 more files", files.count() - 1, files.first().fileName()));
0068     }
0069 
0070     QWidget *page = new QWidget(this);
0071 
0072     m_searchbar = new QWidget(page);
0073     QHBoxLayout *searchbarHBoxLayout = new QHBoxLayout(m_searchbar);
0074     searchbarHBoxLayout->setContentsMargins(0, 0, 0, 0);
0075     QLabel *searchlabel = new QLabel(i18n("&Search: "), m_searchbar);
0076     searchbarHBoxLayout->addWidget(searchlabel);
0077 
0078     m_searchlineedit = new QLineEdit(m_searchbar);
0079     searchbarHBoxLayout->addWidget(m_searchlineedit);
0080     m_searchlineedit->setClearButtonEnabled(true);
0081     searchlabel->setBuddy(m_searchlineedit);
0082 
0083     iproxy = new SelectKeyProxyModel(this);
0084     iproxy->setKeyModel(imodel);
0085 
0086     m_keyslist = new QTableView(page);
0087     m_keyslist->setSortingEnabled(true);
0088     m_keyslist->setSelectionMode(QAbstractItemView::ExtendedSelection);
0089     m_keyslist->setSelectionBehavior(QAbstractItemView::SelectRows);
0090     m_keyslist->setModel(iproxy);
0091     m_keyslist->resizeColumnsToContents();
0092     m_keyslist->setWhatsThis(i18n("<b>Public keys list</b>: select the key that will be used for encryption."));
0093     connect(m_searchlineedit, &QLineEdit::textChanged, iproxy, &SelectKeyProxyModel::setFilterFixedString);
0094 
0095     optionsbox = new QWidget();
0096     QVBoxLayout *optionsboxVBoxLayout = new QVBoxLayout(optionsbox);
0097     optionsboxVBoxLayout->setContentsMargins(0, 0, 0, 0);
0098     optionsbox->hide();
0099 
0100     if (m_hideasciioption)
0101         m_cbarmor = nullptr;
0102     else
0103     {
0104         m_cbarmor = new QCheckBox(i18n("ASCII armored encryption"), optionsbox);
0105         optionsboxVBoxLayout->addWidget(m_cbarmor);
0106         m_cbarmor->setChecked(KGpgSettings::asciiArmor());
0107         m_cbarmor->setWhatsThis(i18n("<b>ASCII encryption</b>: makes it possible to open the encrypted file/message in a text editor"));
0108     }
0109 
0110     m_cbuntrusted = new QCheckBox(i18n("Allow encryption with untrusted keys"), optionsbox);
0111     optionsboxVBoxLayout->addWidget(m_cbuntrusted);
0112     // connect before setting the state so the model gets the right state from the start
0113     connect(m_cbuntrusted, &QCheckBox::toggled, this, &KgpgSelectPublicKeyDlg::slotUntrusted);
0114     m_cbuntrusted->setChecked(KGpgSettings::allowUntrustedKeys());
0115     m_cbuntrusted->setWhatsThis(i18n("<b>Allow encryption with untrusted keys</b>: when you import a public key, it is usually "
0116                     "marked as untrusted and you cannot use it unless you sign it in order to make it 'trusted'. Checking this "
0117                     "box enables you to use any key, even if it has not be signed."));
0118 
0119     m_cbhideid = new QCheckBox(i18n("Hide user id"), optionsbox);
0120     optionsboxVBoxLayout->addWidget(m_cbhideid);
0121     m_cbhideid->setChecked(KGpgSettings::hideUserID());
0122     m_cbhideid->setWhatsThis(i18n("<b>Hide user ID</b>: Do not put the keyid into encrypted packets. This option hides the receiver "
0123                     "of the message and is a countermeasure against traffic analysis. It may slow down the decryption process because "
0124                     "all available secret keys are tried."));
0125 
0126     m_cbsymmetric = new QCheckBox(i18n("Symmetrical encryption"), optionsbox);
0127     optionsboxVBoxLayout->addWidget(m_cbsymmetric);
0128     m_cbsymmetric->setWhatsThis(i18n("<b>Symmetrical encryption</b>: encryption does not use keys. You just need to give a password "
0129                                      "to encrypt/decrypt the file"));
0130 
0131     QVBoxLayout *dialoglayout = new QVBoxLayout(page);
0132     dialoglayout->setContentsMargins(0, 0, 0, 0);
0133     dialoglayout->addWidget(m_searchbar);
0134     dialoglayout->addWidget(m_keyslist);
0135     page->setLayout(dialoglayout);
0136 
0137     if (KGpgSettings::allowCustomEncryptionOptions())
0138     {
0139         QWidget *expertbox = new QWidget(page);
0140         QHBoxLayout *expertboxHBoxLayout = new QHBoxLayout(expertbox);
0141         expertboxHBoxLayout->setContentsMargins(0, 0, 0, 0);
0142         (void) new QLabel(i18n("Custom option:"), expertbox);
0143 
0144         m_customoptions = new QLineEdit(expertbox);
0145         expertboxHBoxLayout->addWidget(m_customoptions);
0146         m_customoptions->setText(KGpgSettings::customEncryptionOptions());
0147         m_customoptions->setWhatsThis(i18n("<b>Custom option</b>: for experienced users only, allows you to enter a gpg command line option, like: '--armor'"));
0148 
0149         dialoglayout->addWidget(expertbox);
0150     }
0151 
0152     KActionCollection *actcol = new KActionCollection(this);
0153     QAction *action = actcol->addAction(QLatin1String( "go_default_key" ));
0154     action->setText(i18n("&Go to Default Key"));
0155     actcol->setDefaultShortcut(action, goDefaultKey);
0156 
0157     connect(action, &QAction::triggered, this, &KgpgSelectPublicKeyDlg::slotGotoDefaultKey);
0158     connect(m_cbsymmetric, &QCheckBox::toggled, this, &KgpgSelectPublicKeyDlg::slotSymmetric);
0159     connect(m_keyslist->selectionModel(), &QItemSelectionModel::selectionChanged, this, &KgpgSelectPublicKeyDlg::slotSelectionChanged);
0160     connect(m_keyslist, &QTableView::doubleClicked, this, &KgpgSelectPublicKeyDlg::slotOk);
0161 
0162     setMinimumSize(550, 200);
0163     updateGeometry();
0164 
0165     mainLayout->addWidget(page);
0166     mainLayout->addWidget(optionsbox);
0167     mainLayout->addWidget(buttonBox);
0168     slotSelectionChanged();
0169 
0170     if (fmode)
0171         slotGotoDefaultKey();
0172 }
0173 
0174 QStringList KgpgSelectPublicKeyDlg::selectedKeys() const
0175 {
0176     if (getSymmetric())
0177         return QStringList();
0178 
0179     QStringList selectedKeys;
0180 
0181     const QModelIndexList indexes = m_keyslist->selectionModel()->selectedIndexes();
0182     for (const QModelIndex &idx : indexes) {
0183         if (idx.column() != 0)
0184             continue;
0185         KGpgNode *nd = iproxy->nodeForIndex(idx);
0186         if (nd->getType() == ITYPE_GROUP)
0187             selectedKeys << nd->getName();
0188         else
0189             selectedKeys << nd->getId();
0190     }
0191 
0192     return selectedKeys;
0193 }
0194 
0195 bool KgpgSelectPublicKeyDlg::getSymmetric() const
0196 {
0197     return m_cbsymmetric->isChecked();
0198 }
0199 
0200 QString KgpgSelectPublicKeyDlg::getCustomOptions() const
0201 {
0202     if (m_customoptions == nullptr)
0203         return QString();
0204     return m_customoptions->text().simplified();
0205 }
0206 
0207 bool KgpgSelectPublicKeyDlg::getUntrusted() const
0208 {
0209     return m_cbuntrusted->isChecked();
0210 }
0211 
0212 bool KgpgSelectPublicKeyDlg::getArmor() const
0213 {
0214     return m_hideasciioption || m_cbarmor->isChecked();
0215 }
0216 
0217 const QList<QUrl> &KgpgSelectPublicKeyDlg::getFiles() const
0218 {
0219     return m_files;
0220 }
0221 
0222 bool KgpgSelectPublicKeyDlg::getHideId() const
0223 {
0224     return m_cbhideid->isChecked();
0225 }
0226 
0227 void KgpgSelectPublicKeyDlg::slotOk()
0228 {
0229     if (getSymmetric() || m_keyslist->selectionModel()->hasSelection())
0230         accept();
0231 }
0232 
0233 void KgpgSelectPublicKeyDlg::slotSelectionChanged()
0234 {
0235     m_okButton->setEnabled(getSymmetric() || m_keyslist->selectionModel()->hasSelection());
0236 }
0237 
0238 void KgpgSelectPublicKeyDlg::slotSymmetric(const bool state)
0239 {
0240     m_keyslist->setDisabled(state);
0241     m_cbuntrusted->setDisabled(state);
0242     m_cbhideid->setDisabled(state);
0243     m_searchbar->setDisabled(state);
0244     slotSelectionChanged();
0245 }
0246 
0247 void KgpgSelectPublicKeyDlg::slotUntrusted(const bool state)
0248 {
0249     iproxy->setShowUntrusted(state);
0250 }
0251 
0252 void KgpgSelectPublicKeyDlg::slotGotoDefaultKey()
0253 {
0254     KGpgNode *nd = imodel->getRootNode()->findKey(KGpgSettings::defaultKey());
0255     if (nd == nullptr)
0256         return;
0257     QModelIndex sidx = imodel->nodeIndex(nd);
0258     QModelIndex pidx = iproxy->mapFromSource(sidx);
0259     m_keyslist->selectionModel()->setCurrentIndex(pidx, QItemSelectionModel::Clear | QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
0260 }
0261 
0262 void KgpgSelectPublicKeyDlg::toggleDetails()
0263 {
0264     const bool isVisible = optionsbox->isVisible();
0265     optionsbox->setVisible(!isVisible);
0266     m_detailsButton->setText(i18n("&Options") + (isVisible ? QStringLiteral(" >>") : QStringLiteral(" <<")));
0267 }