File indexing completed on 2023-12-03 09:19:01
0001 /* 0002 SPDX-FileCopyrightText: 2002 Jean-Baptiste Mardelle <bj@altern.org> 0003 SPDX-FileCopyrightText: 2006, 2007, 2008, 2009, 2010, 2012, 2013, 2014, 2016, 2017 Rolf Eike Beer <kde@opensource.sf-tec.de> 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "keyservers.h" 0008 0009 #include "core/convert.h" 0010 #include "detailedconsole.h" 0011 #include "gpgproc.h" 0012 #include "kgpgsettings.h" 0013 #include "model/keylistproxymodel.h" 0014 #include "model/kgpgitemmodel.h" 0015 #include "transactions/kgpgimport.h" 0016 #include "transactions/kgpgkeyservergettransaction.h" 0017 #include "transactions/kgpgkeyserversearchtransaction.h" 0018 #include "transactions/kgpgsendkeys.h" 0019 0020 #include <algorithm> 0021 0022 #include <KLocalizedString> 0023 #include <KMessageBox> 0024 #include <QCursor> 0025 #include <QRegularExpression> 0026 0027 KeyServer::KeyServer(QWidget *parent, KGpgItemModel *model, const bool autoclose) 0028 : QDialog(parent), 0029 m_dialogserver(nullptr), 0030 m_searchproc(nullptr), 0031 page(new keyServerWidget()), 0032 m_listpop(nullptr), 0033 m_itemmodel(new KeyListProxyModel(this, KeyListProxyModel::SingleColumnIdFirst)) 0034 { 0035 setWindowTitle(i18n("Key Server")); 0036 0037 m_autoclose = autoclose; 0038 m_resultmodel.setSortCaseSensitivity(Qt::CaseInsensitive); 0039 m_resultmodel.setDynamicSortFilter(true); 0040 m_resultmodel.setFilterKeyColumn(0); 0041 0042 QVBoxLayout *mainLayout = new QVBoxLayout(this); 0043 setLayout(mainLayout); 0044 mainLayout->addWidget(page); 0045 0046 const QStringList serverlist(getServerList()); 0047 page->kCBexportks->addItems(serverlist); 0048 page->kCBimportks->addItems(serverlist); 0049 page->qLEimportid->setFocus(); 0050 page->Buttonsearch->setDefault(true); 0051 0052 connect(page->buttonBox, &QDialogButtonBox::rejected, this, &KeyServer::accept); 0053 connect(page->Buttonimport, &QPushButton::clicked, this, &KeyServer::slotImport); 0054 connect(page->Buttonsearch, &QPushButton::clicked, this, &KeyServer::slotSearch); 0055 connect(page->Buttonexport, &QPushButton::clicked, this, &KeyServer::slotPreExport); 0056 connect(page->buttonBox, &QDialogButtonBox::accepted, this, &KeyServer::slotOk); 0057 connect(page->cBproxyI, &QCheckBox::toggled, this, &KeyServer::slotEnableProxyI); 0058 connect(page->cBproxyE, &QCheckBox::toggled, this, &KeyServer::slotEnableProxyE); 0059 connect(page->qLEimportid, &QLineEdit::textChanged, this, &KeyServer::slotTextChanged); 0060 0061 page->cBproxyI->setChecked(KGpgSettings::useProxy()); 0062 page->cBproxyE->setChecked(KGpgSettings::useProxy()); 0063 0064 const QString httpproxy(QLatin1String( qgetenv("http_proxy") )); 0065 if (!httpproxy.isEmpty()) { 0066 page->cBproxyI->setEnabled(true); 0067 page->cBproxyE->setEnabled(true); 0068 page->kLEproxyI->setText(httpproxy); 0069 page->kLEproxyE->setText(httpproxy); 0070 } 0071 0072 page->Buttonimport->setEnabled(!page->qLEimportid->text().isEmpty()); 0073 page->Buttonsearch->setEnabled(!page->qLEimportid->text().isEmpty()); 0074 setMinimumSize(sizeHint()); 0075 0076 m_itemmodel->setKeyModel(model); 0077 m_itemmodel->setTrustFilter(KgpgCore::TRUST_UNDEFINED); 0078 page->kCBexportkey->setModel(m_itemmodel); 0079 } 0080 0081 KeyServer::~KeyServer() 0082 { 0083 delete page; 0084 } 0085 0086 void KeyServer::slotImport() 0087 { 0088 if (page->kCBimportks->currentText().isEmpty()) 0089 return; 0090 0091 if (page->qLEimportid->text().isEmpty()) { 0092 KMessageBox::error(this, i18n("You must enter a search string.")); 0093 return; 0094 } 0095 0096 startImport(page->qLEimportid->text().simplified().split(QLatin1Char( ' ' )), page->kCBimportks->currentText(), page->kLEproxyI->text()); 0097 } 0098 0099 void KeyServer::startImport(const QStringList &keys, QString server, const QString &proxy) 0100 { 0101 if (server.isEmpty()) { 0102 const QStringList kservers = KeyServer::getServerList(); 0103 if (kservers.isEmpty()) { 0104 KMessageBox::error(this, i18n("You need to configure keyservers before trying to download keys."), 0105 i18n("No keyservers defined")); 0106 return; 0107 } 0108 0109 server = kservers.first(); 0110 } 0111 0112 QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); 0113 0114 KGpgReceiveKeys *proc = new KGpgReceiveKeys(this, server, keys, true, proxy); 0115 connect(proc, &KGpgReceiveKeys::done, this, &KeyServer::slotDownloadKeysFinished); 0116 0117 proc->start(); 0118 } 0119 0120 void KeyServer::slotDownloadKeysFinished(int resultcode) 0121 { 0122 QApplication::restoreOverrideCursor(); 0123 0124 KGpgKeyserverGetTransaction *t = qobject_cast<KGpgKeyserverGetTransaction *>(sender()); 0125 const QStringList log(t->getLog()); 0126 0127 t->deleteLater(); 0128 0129 if (resultcode == KGpgTransaction::TS_USER_ABORTED) { 0130 Q_EMIT importFailed(); 0131 return; 0132 } 0133 0134 const QStringList keys(KGpgImport::getImportedIds(log)); 0135 const QString resultmessage(KGpgImport::getImportMessage(log)); 0136 0137 if (!keys.empty()) 0138 Q_EMIT importFinished(keys); 0139 0140 (void) new KgpgDetailedInfo(this, resultmessage, log.join(QLatin1String("\n")), 0141 KGpgImport::getDetailedImportMessage(log).split(QLatin1Char( '\n' )), 0142 i18nc("Caption of message box", "Key Import Finished")); 0143 } 0144 0145 void KeyServer::slotExport(const QStringList &keyIds) 0146 { 0147 if (page->kCBexportks->currentText().isEmpty()) 0148 return; 0149 0150 QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); 0151 0152 KGpgSendKeys *nk = new KGpgSendKeys(this, page->kCBexportks->currentText(), keyIds, expattr, true, page->kLEproxyI->text()); 0153 connect(nk, &KGpgSendKeys::done, this, &KeyServer::slotUploadKeysFinished); 0154 0155 nk->start(); 0156 } 0157 0158 void KeyServer::slotUploadKeysFinished(int resultcode) 0159 { 0160 KGpgSendKeys *nk = qobject_cast<KGpgSendKeys *>(sender()); 0161 Q_ASSERT(nk != nullptr); 0162 0163 const QStringList message(nk->getLog()); 0164 nk->deleteLater(); 0165 0166 QApplication::restoreOverrideCursor(); 0167 0168 QString title; 0169 if (resultcode == KGpgTransaction::TS_OK) 0170 title = i18n("Upload to keyserver finished without errors"); 0171 else 0172 title = i18n("Upload to keyserver failed"); 0173 KMessageBox::informationList(this, title, message); 0174 } 0175 0176 void KeyServer::slotSearch() 0177 { 0178 if (page->kCBimportks->currentText().isEmpty()) 0179 return; 0180 0181 if (page->qLEimportid->text().isEmpty()) { 0182 KMessageBox::error(this, i18n("You must enter a search string.")); 0183 return; 0184 } 0185 0186 page->Buttonsearch->setEnabled(false); 0187 if (m_searchproc) 0188 return; 0189 0190 m_resultmodel.resetSourceModel(); 0191 m_resultmodel.setFilterRegularExpression(QRegularExpression()); 0192 m_resultmodel.setFilterByValidity(true); 0193 0194 m_dialogserver = new QDialog(this); 0195 m_dialogserver->setWindowTitle(i18nc("Window title", "Import Key From Keyserver")); 0196 0197 QVBoxLayout *mainLayout = new QVBoxLayout(m_dialogserver); 0198 m_dialogserver->setLayout(mainLayout); 0199 0200 m_listpop = new searchRes(m_dialogserver); 0201 m_listpop->buttonBox->button(QDialogButtonBox::Ok)->setText(i18n("&Import")); 0202 m_listpop->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); 0203 m_listpop->kLVsearch->setModel(&m_resultmodel); 0204 m_listpop->kLVsearch->setColumnWidth(0, 180); 0205 m_listpop->validFilterCheckbox->setChecked(m_resultmodel.filterByValidity()); 0206 m_listpop->statusText->setText(i18n("Connecting to the server...")); 0207 0208 connect(m_listpop->filterEdit, &QLineEdit::textChanged, this, &KeyServer::slotSetFilterString); 0209 connect(m_listpop->kLVsearch->selectionModel(), &QItemSelectionModel::selectionChanged, this, &KeyServer::transferKeyID); 0210 connect(m_listpop->validFilterCheckbox, &QCheckBox::toggled, &m_resultmodel, &KGpgSearchResultModel::setFilterByValidity); 0211 connect(m_listpop->validFilterCheckbox, &QCheckBox::toggled, this, &KeyServer::slotUpdateLabelOnFilterChange); 0212 connect(m_listpop->buttonBox, &QDialogButtonBox::accepted, this, &KeyServer::slotPreImport); 0213 connect(m_listpop->kLVsearch, &QTreeView::activated, m_dialogserver, &QDialog::accepted); 0214 connect(m_listpop->buttonBox, &QDialogButtonBox::rejected, this, &KeyServer::handleQuit); 0215 connect(m_listpop->qLEID, &QLineEdit::textChanged, this, [&] (const QString & text) { 0216 if (text.isEmpty()) 0217 m_listpop->kLVsearch->selectionModel()->clearSelection(); 0218 }); 0219 0220 m_listpop->kLVsearch->setSelectionMode(QAbstractItemView::ExtendedSelection); 0221 0222 m_readmessage.clear(); 0223 0224 const QString keyserv(page->kCBimportks->currentText()); 0225 0226 bool useproxy = page->cBproxyI->isChecked(); 0227 QString proxy; 0228 if (useproxy) 0229 proxy = page->kLEproxyI->text(); 0230 0231 m_searchproc = new KGpgKeyserverSearchTransaction(this, keyserv, page->qLEimportid->text().simplified(), 0232 true, proxy); 0233 connect(m_searchproc, &KGpgKeyserverSearchTransaction::done, this, &KeyServer::slotSearchResult); 0234 connect(m_searchproc, &KGpgKeyserverSearchTransaction::newKey, &m_resultmodel, &KGpgSearchResultModel::slotAddKey); 0235 m_searchproc->start(); 0236 0237 QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); 0238 mainLayout->addWidget(m_listpop); 0239 m_listpop->setMinimumSize(m_listpop->sizeHint()); 0240 m_dialogserver->exec(); 0241 } 0242 0243 void KeyServer::slotSearchResult(int result) 0244 { 0245 Q_ASSERT(sender() == m_searchproc); 0246 m_searchproc->deleteLater(); 0247 m_searchproc = nullptr; 0248 page->Buttonsearch->setEnabled(true); 0249 QApplication::restoreOverrideCursor(); 0250 0251 if (result == KGpgTransaction::TS_USER_ABORTED) { 0252 delete m_dialogserver; 0253 m_dialogserver = nullptr; 0254 return; 0255 } 0256 0257 m_listpop->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); 0258 0259 const int keys = m_resultmodel.sourceRowCount(QModelIndex()); 0260 if (keys > 0) { 0261 m_listpop->kLVsearch->selectionModel()->setCurrentIndex(m_resultmodel.index(0, 0), 0262 QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); 0263 } 0264 slotUpdateLabelOnFilterChange(); 0265 } 0266 0267 void KeyServer::slotSetText(const QString &text) 0268 { 0269 page->qLEimportid->setText(text); 0270 } 0271 0272 void KeyServer::slotTextChanged(const QString &text) 0273 { 0274 page->Buttonimport->setEnabled(!text.isEmpty()); 0275 page->Buttonsearch->setEnabled(!text.isEmpty() && (m_searchproc == nullptr)); 0276 } 0277 0278 void KeyServer::slotSetExportAttribute(const QString &state) 0279 { 0280 if (!state.isEmpty()) 0281 expattr = state; 0282 else 0283 expattr.clear(); 0284 } 0285 0286 void KeyServer::slotEnableProxyI(const bool on) 0287 { 0288 page->kLEproxyI->setEnabled(on); 0289 } 0290 0291 void KeyServer::slotEnableProxyE(const bool on) 0292 { 0293 page->kLEproxyE->setEnabled(on); 0294 } 0295 0296 void KeyServer::transferKeyID() 0297 { 0298 QSet<QString> ids; 0299 0300 const QModelIndexList indexes = m_listpop->kLVsearch->selectionModel()->selectedIndexes(); 0301 for (const QModelIndex &index : indexes) 0302 ids << m_resultmodel.idForIndex(index); 0303 0304 const QStringList idlist(ids.values()); 0305 m_listpop->qLEID->setText(idlist.join( QLatin1String( " " ))); 0306 } 0307 0308 void KeyServer::slotPreImport() 0309 { 0310 transferKeyID(); 0311 if (m_listpop->qLEID->text().isEmpty()) { 0312 KMessageBox::error(this, i18n("You must choose a key.")); 0313 return; 0314 } 0315 const QStringList keys = m_listpop->qLEID->text().simplified().split(QLatin1Char(' ')); 0316 m_dialogserver->close(); 0317 startImport(keys, page->kCBimportks->currentText(), page->kLEproxyI->text()); 0318 } 0319 0320 void KeyServer::slotPreExport() 0321 { 0322 slotExport(QStringList(page->kCBexportkey->currentText().section(QLatin1Char( ':' ), 0, 0))); 0323 } 0324 0325 void KeyServer::slotOk() 0326 { 0327 accept(); 0328 } 0329 0330 QStringList KeyServer::getServerList() 0331 { 0332 QStringList serverList(KGpgSettings::keyServers()); // From kgpg config 0333 if (!serverList.isEmpty()) { 0334 const QString defaultServer(serverList.takeFirst()); 0335 std::sort(serverList.begin(), serverList.end()); 0336 serverList.prepend(defaultServer); 0337 } 0338 0339 return serverList; 0340 } 0341 0342 void KeyServer::handleQuit() 0343 { 0344 if (m_searchproc != nullptr) { 0345 QApplication::restoreOverrideCursor(); 0346 disconnect(m_searchproc, nullptr, nullptr, nullptr); 0347 m_searchproc->deleteLater(); 0348 m_searchproc = nullptr; 0349 } 0350 m_dialogserver->close(); 0351 page->Buttonsearch->setEnabled(true); 0352 } 0353 0354 void KeyServer::slotSetKeyserver(const QString &server) 0355 { 0356 page->kCBimportks->setCurrentIndex(page->kCBimportks->findText(server)); 0357 } 0358 0359 void KeyServer::slotSetFilterString(const QString &expression) 0360 { 0361 m_resultmodel.setFilterRegularExpression(QRegularExpression(expression, QRegularExpression::CaseInsensitiveOption)); 0362 slotUpdateLabelOnFilterChange(); 0363 } 0364 0365 void KeyServer::slotUpdateLabelOnFilterChange() 0366 { 0367 const int keys = m_resultmodel.sourceRowCount(QModelIndex()); 0368 const int keysShown = m_resultmodel.rowCount(QModelIndex()); 0369 Q_ASSERT(keysShown <= keys); 0370 0371 if (keys == 0) { 0372 m_listpop->statusText->setText(i18n("No matching keys found")); 0373 } else { 0374 if (keysShown == keys) { 0375 m_listpop->statusText->setText(i18np("Found 1 matching key", "Found %1 matching keys", keys)); 0376 } else { 0377 if (keys == 1 && keysShown == 0) { 0378 m_listpop->statusText->setText(i18n("Found 1 matching key (not shown)")); 0379 } else { 0380 m_listpop->statusText->setText(i18n("Found %1 matching keys (%2 shown)", keys, keysShown)); 0381 } 0382 } 0383 } 0384 }