File indexing completed on 2024-04-21 05:50:47
0001 /* 0002 SPDX-FileCopyrightText: 2002 Jean-Baptiste Mardelle <bj@altern.org> 0003 SPDX-FileCopyrightText: 2007-2022 Rolf Eike Beer <kde@opensource.sf-tec.de> 0004 SPDX-FileCopyrightText: 2011 Luis Ángel Fernández Fernández <laffdez@gmail.com> 0005 SPDX-FileCopyrightText: 2016 Andrius Štikonas <andrius@stikonas.eu> 0006 SPDX-FileCopyrightText: 2022 Dmitrii Fomchenkov <fomchenkovda@basealt.ru> 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "keysmanager.h" 0011 0012 #include "caff.h" 0013 #include "core/images.h" 0014 #include "detailedconsole.h" 0015 #include "gpgproc.h" 0016 #include "groupedit.h" 0017 #include "keyadaptor.h" 0018 #include "keyexport.h" 0019 #include "keyinfodialog.h" 0020 #include "keyservers.h" 0021 #include "keytreeview.h" 0022 #include "kgpg_general_debug.h" 0023 #include "kgpg.h" 0024 #include "kgpgchangekey.h" 0025 #include "kgpgkeygenerate.h" 0026 #include "kgpgoptions.h" 0027 #include "kgpgrevokewidget.h" 0028 #include "kgpgsettings.h" 0029 #include "newkey.h" 0030 #include "selectpublickeydialog.h" 0031 #include "selectsecretkey.h" 0032 #include "sourceselect.h" 0033 #include "editor/kgpgeditor.h" 0034 #include "editor/kgpgtextedit.h" 0035 #include "model/keylistproxymodel.h" 0036 #include "transactions/kgpgaddphoto.h" 0037 #include "transactions/kgpgadduid.h" 0038 #include "transactions/kgpgdecrypt.h" 0039 #include "transactions/kgpgdelkey.h" 0040 #include "transactions/kgpgdelsign.h" 0041 #include "transactions/kgpgdeluid.h" 0042 #include "transactions/kgpgencrypt.h" 0043 #include "transactions/kgpgexport.h" 0044 #include "transactions/kgpggeneratekey.h" 0045 #include "transactions/kgpggeneraterevoke.h" 0046 #include "transactions/kgpgimport.h" 0047 #include "transactions/kgpgkeyservergettransaction.h" 0048 #include "transactions/kgpgprimaryuid.h" 0049 #include "transactions/kgpgsignkey.h" 0050 #include "transactions/kgpgsignuid.h" 0051 #include "transactions/kgpgtransactionjob.h" 0052 #include "transactions/customstyleditemdelegate.h" 0053 0054 #include <algorithm> 0055 #include <Akonadi/ContactEditor> 0056 #include <Akonadi/ContactEditorDialog> 0057 #include <Akonadi/ContactSearchJob> 0058 #include <KActionCollection> 0059 #include <KContacts/AddresseeList> 0060 // #include <KContacts/Key> TODO 0061 #include <kmessagebox.h> 0062 #include <kwidgetsaddons_version.h> 0063 #include <KIO/Global> 0064 #include <KIO/ApplicationLauncherJob> 0065 #include <KIO/OpenUrlJob> 0066 #include <KIO/JobTracker> 0067 #include <kio_version.h> 0068 #include <KIO/JobUiDelegateFactory> 0069 #include <KJobTrackerInterface> 0070 #include <KLocalizedString> 0071 #include <KMessageBox> 0072 #include <KProcess> 0073 #include <KSelectAction> 0074 #include <KService> 0075 #include <KSharedConfig> 0076 #include <KStandardAction> 0077 #include <KStandardGuiItem> 0078 #include <KStandardShortcut> 0079 #include <KStatusNotifierItem> 0080 #include <KToggleAction> 0081 0082 #include <QApplication> 0083 #include <QDBusConnection> 0084 0085 #include <QDesktopServices> 0086 #include <QDir> 0087 #include <QEvent> 0088 #include <QFileDialog> 0089 #include <QIcon> 0090 #include <QInputDialog> 0091 #include <QKeySequence> 0092 #include <QLabel> 0093 #include <QLineEdit> 0094 #include <QList> 0095 #include <QMenu> 0096 #include <QMetaObject> 0097 #include <QNetworkInformation> 0098 #include <QPainter> 0099 #include <QPrintDialog> 0100 #include <QPrinter> 0101 #include <QProcess> 0102 #include <QRegularExpression> 0103 #include <QStatusBar> 0104 #include <QUrl> 0105 #include <QWidget> 0106 #include <QWidgetAction> 0107 0108 using namespace Qt::Literals::StringLiterals; 0109 0110 using namespace KgpgCore; 0111 0112 KeysManager::KeysManager(QWidget *parent) 0113 : KXmlGuiWindow(parent), 0114 imodel(new KGpgItemModel(this)), 0115 m_adduid(nullptr), 0116 m_genkey(nullptr), 0117 m_delkey(nullptr), 0118 terminalkey(nullptr), 0119 m_trayicon(nullptr) 0120 { 0121 new KeyAdaptor(this); 0122 QDBusConnection::sessionBus().registerObject(QLatin1String( "/KeyInterface" ), this); 0123 0124 setAttribute(Qt::WA_DeleteOnClose, false); 0125 setWindowTitle(i18n("Key Management")); 0126 0127 KStandardAction::quit(this, &KeysManager::quitApp, actionCollection()); 0128 actionCollection()->addAction(KStandardAction::Preferences, QLatin1String( "options_configure" ), this, SLOT(showOptions())); 0129 0130 openEditor = actionCollection()->addAction(QLatin1String("kgpg_editor"), this, &KeysManager::slotOpenEditor); 0131 openEditor->setIcon(QIcon::fromTheme( QLatin1String( "accessories-text-editor" ))); 0132 openEditor->setText(i18n("&Open Editor")); 0133 0134 kserver = actionCollection()->addAction( QLatin1String("key_server"), this, &KeysManager::showKeyServer); 0135 kserver->setText( i18n("&Key Server Dialog") ); 0136 kserver->setIcon( QIcon::fromTheme( QLatin1String( "network-server" )) ); 0137 0138 goToDefaultKey = actionCollection()->addAction(QLatin1String("go_default_key"), this, &KeysManager::slotGotoDefaultKey); 0139 goToDefaultKey->setIcon(QIcon::fromTheme( QLatin1String( "go-home" ))); 0140 goToDefaultKey->setText(i18n("&Go to Default Key")); 0141 actionCollection()->setDefaultShortcut(goToDefaultKey, QKeySequence(Qt::CTRL | Qt::Key_Home)); 0142 0143 s_kgpgEditor = new KgpgEditor(this, imodel, Qt::Dialog); 0144 s_kgpgEditor->setAttribute(Qt::WA_DeleteOnClose, false); 0145 0146 // this must come after kserver, preferences, and openEditor are created 0147 // because they are used to set up the tray icon context menu 0148 readOptions(); 0149 0150 QAction *action; 0151 0152 action = actionCollection()->addAction(QLatin1String("gpg_man"), this, &KeysManager::slotManpage); 0153 action->setText( i18n("View GnuPG Manual") ); 0154 action->setIcon( QIcon::fromTheme( QLatin1String( "help-contents" )) ); 0155 0156 action = actionCollection()->addAction(QLatin1String("key_refresh"), this, &KeysManager::refreshkey); 0157 action->setIcon(QIcon::fromTheme( QLatin1String( "view-refresh" ))); 0158 action->setText(i18n("&Refresh List")); 0159 actionCollection()->setDefaultShortcuts(action, KStandardShortcut::reload()); 0160 0161 longId = actionCollection()->add<KToggleAction>(QLatin1String("show_long_keyid"), this, &KeysManager::slotShowLongId); 0162 longId->setText(i18n("Show &Long Key Id")); 0163 longId->setChecked(KGpgSettings::showLongKeyId()); 0164 0165 QAction *infoKey = actionCollection()->addAction(QLatin1String("key_info"), this, &KeysManager::keyproperties); 0166 infoKey->setIcon(QIcon::fromTheme( QLatin1String( "document-properties-key" ))); 0167 infoKey->setText(i18n("K&ey Properties")); 0168 0169 QAction *openKeyUrl = actionCollection()->addAction(QLatin1String("key_url"), this, &KeysManager::slotOpenKeyUrl); 0170 openKeyUrl->setIcon(QIcon::fromTheme(QLatin1String("internet-services"))); 0171 openKeyUrl->setText(i18n("&Open Key URL")); 0172 0173 editKey = actionCollection()->addAction(QLatin1String("key_edit"), this, &KeysManager::slotedit); 0174 editKey->setIcon(QIcon::fromTheme( QLatin1String( "utilities-terminal" ))); 0175 editKey->setText(i18n("Edit Key in &Terminal")); 0176 actionCollection()->setDefaultShortcut(editKey, QKeySequence(Qt::ALT | Qt::Key_Return)); 0177 0178 QAction *generateKey = actionCollection()->addAction(QLatin1String("key_gener"), this, &KeysManager::slotGenerateKey); 0179 generateKey->setIcon(QIcon::fromTheme( QLatin1String( "key-generate-pair" ))); 0180 generateKey->setText(i18n("&Generate Key Pair...")); 0181 actionCollection()->setDefaultShortcuts(generateKey, KStandardShortcut::shortcut(KStandardShortcut::New)); 0182 0183 exportPublicKey = actionCollection()->addAction(QLatin1String("key_export"), this, &KeysManager::slotexport); 0184 exportPublicKey->setIcon(QIcon::fromTheme( QLatin1String( "document-export-key" ))); 0185 actionCollection()->setDefaultShortcuts(exportPublicKey, KStandardShortcut::shortcut(KStandardShortcut::Copy)); 0186 0187 QAction *importKey = actionCollection()->addAction(QLatin1String("key_import"), this, &KeysManager::slotPreImportKey); 0188 importKey->setIcon(QIcon::fromTheme( QLatin1String( "document-import-key" ))); 0189 importKey->setText(i18n("&Import Key...")); 0190 actionCollection()->setDefaultShortcuts(importKey, KStandardShortcut::shortcut(KStandardShortcut::Paste)); 0191 0192 m_sendEmail = actionCollection()->addAction(QLatin1String("send_mail"), this, &KeysManager::slotSendEmail); 0193 m_sendEmail->setIcon(QIcon::fromTheme(QLatin1String("mail-send"))); 0194 m_sendEmail->setText(i18n("Send Ema&il")); 0195 0196 QAction *newContact = actionCollection()->addAction(QLatin1String("add_kab"), this, &KeysManager::addToKAB); 0197 newContact->setIcon(QIcon::fromTheme( QLatin1String( "contact-new" ))); 0198 newContact->setText(i18n("&Create New Contact in Address Book")); 0199 0200 createGroup = actionCollection()->addAction(QLatin1String("create_group"), this, &KeysManager::createNewGroup); 0201 createGroup->setIcon(Images::group()); 0202 0203 editCurrentGroup = actionCollection()->addAction(QLatin1String("edit_group"), this, &KeysManager::editGroup); 0204 editCurrentGroup->setText(i18n("&Edit Group...")); 0205 0206 delGroup = actionCollection()->addAction(QLatin1String("delete_group"), this, &KeysManager::deleteGroup); 0207 delGroup->setText(i18n("&Delete Group")); 0208 delGroup->setIcon(QIcon::fromTheme( QLatin1String( "edit-delete" ))); 0209 0210 m_groupRename = actionCollection()->addAction(QLatin1String("rename_group"), this, &KeysManager::renameGroup); 0211 m_groupRename->setText(i18n("&Rename Group")); 0212 m_groupRename->setIcon(QIcon::fromTheme( QLatin1String( "edit-rename" ))); 0213 actionCollection()->setDefaultShortcut(m_groupRename, QKeySequence(Qt::Key_F2)); 0214 0215 deleteKey = actionCollection()->addAction(QLatin1String("key_delete"), this, &KeysManager::confirmdeletekey); 0216 deleteKey->setIcon(QIcon::fromTheme( QLatin1String( "edit-delete" ))); 0217 actionCollection()->setDefaultShortcut(deleteKey, QKeySequence(Qt::Key_Delete)); 0218 0219 setDefaultKey = actionCollection()->addAction(QLatin1String("key_default"), this, &KeysManager::slotSetDefKey); 0220 setDefaultKey->setText(i18n("Set as De&fault Key")); 0221 0222 QAction *addPhoto = actionCollection()->addAction(QLatin1String("add_photo"), this, &KeysManager::slotAddPhoto); 0223 addPhoto->setText(i18n("&Add Photo...")); 0224 0225 QAction *addUid = actionCollection()->addAction(QLatin1String("add_uid"), this, &KeysManager::slotAddUid); 0226 addUid->setText(i18n("&Add User Id...")); 0227 0228 QAction *exportSecretKey = actionCollection()->addAction(QLatin1String("key_sexport"), this, &KeysManager::slotexportsec); 0229 exportSecretKey->setText(i18n("Export Secret Key...")); 0230 0231 QAction *deleteKeyPair = actionCollection()->addAction(QLatin1String("key_pdelete"), this, &KeysManager::deleteseckey); 0232 deleteKeyPair->setText(i18n("Delete Key Pair")); 0233 deleteKeyPair->setIcon(QIcon::fromTheme( QLatin1String( "edit-delete" ))); 0234 0235 m_revokeKey = actionCollection()->addAction(QLatin1String("key_revoke"), this, &KeysManager::revokeWidget); 0236 m_revokeKey->setText(i18n("Revoke Key...")); 0237 0238 QAction *regeneratePublic = actionCollection()->addAction(QLatin1String("key_regener"), this, &KeysManager::slotregenerate); 0239 regeneratePublic->setText(i18n("&Regenerate Public Key")); 0240 0241 delUid = actionCollection()->addAction(QLatin1String("del_uid"), this, &KeysManager::slotDelUid); 0242 delUid->setIcon(QIcon::fromTheme( QLatin1String( "edit-delete" ))); 0243 0244 setPrimUid = actionCollection()->addAction(QLatin1String("prim_uid"), this, &KeysManager::slotPrimUid); 0245 setPrimUid->setText(i18n("Set User Id as &Primary")); 0246 0247 QAction *openPhoto = actionCollection()->addAction(QLatin1String("key_photo"), this, &KeysManager::slotShowPhoto); 0248 openPhoto->setIcon(QIcon::fromTheme( QLatin1String( "image-x-generic" ))); 0249 openPhoto->setText(i18n("&Open Photo")); 0250 0251 QAction *deletePhoto = actionCollection()->addAction(QLatin1String("delete_photo"), this, &KeysManager::slotDeletePhoto); 0252 deletePhoto->setIcon(QIcon::fromTheme( QLatin1String( "edit-delete" ))); 0253 deletePhoto->setText(i18n("&Delete Photo")); 0254 0255 delSignKey = actionCollection()->addAction(QLatin1String("key_delsign"), this, &KeysManager::delsignkey); 0256 delSignKey->setIcon(QIcon::fromTheme( QLatin1String( "edit-delete" ))); 0257 delSignKey->setEnabled(false); 0258 0259 importAllSignKeys = actionCollection()->addAction(QLatin1String("key_importallsign"), this, &KeysManager::importallsignkey); 0260 importAllSignKeys->setIcon(QIcon::fromTheme( QLatin1String( "document-import" ))); 0261 importAllSignKeys->setText(i18n("Import &Missing Signatures From Keyserver")); 0262 0263 refreshKey = actionCollection()->addAction(QLatin1String("key_server_refresh"), this, &KeysManager::refreshKeyFromServer); 0264 refreshKey->setIcon(QIcon::fromTheme( QLatin1String( "view-refresh" ))); 0265 0266 signKey = actionCollection()->addAction(QLatin1String("key_sign"), this, &KeysManager::signkey); 0267 signKey->setIcon(QIcon::fromTheme( QLatin1String( "document-sign-key" ))); 0268 0269 signUid = actionCollection()->addAction(QLatin1String("key_sign_uid"), this, &KeysManager::signuid); 0270 signUid->setIcon(QIcon::fromTheme( QLatin1String( "document-sign-key" ))); 0271 0272 signMailUid = actionCollection()->addAction(QLatin1String("key_sign_mail_uid"), this, &KeysManager::caff); 0273 signMailUid->setIcon(QIcon::fromTheme( QLatin1String( "document-sign-key" ))); 0274 0275 importSignatureKey = actionCollection()->addAction(QLatin1String("key_importsign"), this, &KeysManager::preimportsignkey); 0276 importSignatureKey->setIcon(QIcon::fromTheme( QLatin1String( "document-import-key" ))); 0277 0278 sTrust = actionCollection()->add<KToggleAction>(QLatin1String("show_trust"), this, &KeysManager::slotShowTrust); 0279 sTrust->setText(i18n("Trust")); 0280 0281 sSize = actionCollection()->add<KToggleAction>(QLatin1String("show_size"), this, &KeysManager::slotShowSize); 0282 sSize->setText(i18n("Size")); 0283 0284 sCreat = actionCollection()->add<KToggleAction>(QLatin1String("show_creat"), this, &KeysManager::slotShowCreation); 0285 sCreat->setText(i18n("Creation")); 0286 0287 sExpi = actionCollection()->add<KToggleAction>(QLatin1String("show_expi"), this, &KeysManager::slotShowExpiration); 0288 sExpi->setText(i18n("Expiration")); 0289 0290 photoProps = actionCollection()->add<KSelectAction>(QLatin1String( "photo_settings" )); 0291 photoProps->setIcon(QIcon::fromTheme( QLatin1String( "image-x-generic" ))); 0292 photoProps->setText(i18n("&Photo ID's")); 0293 0294 // Keep the list in kgpg.kcfg in sync with this one! 0295 QStringList list; 0296 list.append(i18n("Disable")); 0297 list.append(i18nc("small picture", "Small")); 0298 list.append(i18nc("medium picture", "Medium")); 0299 list.append(i18nc("large picture", "Large")); 0300 photoProps->setItems(list); 0301 0302 trustProps = actionCollection()->add<KSelectAction>(QLatin1String( "trust_filter_settings" )); 0303 trustProps->setText(i18n("Minimum &Trust")); 0304 0305 QStringList tlist; 0306 tlist.append(i18nc("no filter: show all keys", "&None")); 0307 tlist.append(i18nc("show only active keys", "&Active")); 0308 tlist.append(i18nc("show only keys with at least marginal trust", "&Marginal")); 0309 tlist.append(i18nc("show only keys with at least full trust", "&Full")); 0310 tlist.append(i18nc("show only ultimately trusted keys", "&Ultimate")); 0311 0312 trustProps->setItems(tlist); 0313 0314 iproxy = new KeyListProxyModel(this); 0315 iproxy->setKeyModel(imodel); 0316 connect(this, &KeysManager::readAgainOptions, iproxy, &KeyListProxyModel::settingsChanged); 0317 0318 iview = new KeyTreeView(this, iproxy); 0319 iview->setItemDelegate(new CustomStyledItemDelegate(iview)); 0320 connect(iview, &KeyTreeView::doubleClicked, this, QOverload<const QModelIndex &>::of(&KeysManager::defaultAction)); 0321 connect(iview, &KeyTreeView::importDrop, this, QOverload<const QList<QUrl> &>::of(&KeysManager::slotImport)); 0322 iview->setSelectionMode(QAbstractItemView::ExtendedSelection); 0323 setCentralWidget(iview); 0324 iview->resizeColumnsToContents(); 0325 iview->setAlternatingRowColors(true); 0326 iview->setSortingEnabled(true); 0327 connect(iview, &KeyTreeView::customContextMenuRequested, this, &KeysManager::slotMenu); 0328 iview->setContextMenuPolicy(Qt::CustomContextMenu); 0329 connect(iview->selectionModel(), &QItemSelectionModel::selectionChanged, this, &KeysManager::checkList); 0330 0331 connect(iview, &KeyTreeView::returnPressed, this, &KeysManager::slotDefaultAction); 0332 0333 hPublic = actionCollection()->add<KToggleAction>(QLatin1String("show_secret"), iproxy, &KeyListProxyModel::setOnlySecret); 0334 hPublic->setIcon(QIcon::fromTheme( QLatin1String( "view-key-secret" ))); 0335 hPublic->setText(i18n("&Show Only Secret Keys")); 0336 hPublic->setChecked(KGpgSettings::showSecret()); 0337 0338 int psize = KGpgSettings::photoProperties(); 0339 photoProps->setCurrentItem(psize); 0340 slotSetPhotoSize(psize); 0341 psize = KGpgSettings::trustLevel(); 0342 trustProps->setCurrentItem(psize); 0343 slotSetTrustFilter(psize); 0344 slotShowLongId(KGpgSettings::showLongKeyId()); 0345 0346 m_popuppub = new QMenu(this); 0347 m_popuppub->addAction(exportPublicKey); 0348 m_popuppub->addAction(m_sendEmail); 0349 m_popuppub->addAction(signMailUid); 0350 m_popuppub->addAction(signKey); 0351 m_popuppub->addAction(signUid); 0352 m_popuppub->addAction(deleteKey); 0353 m_popuppub->addAction(infoKey); 0354 m_popuppub->addAction(openKeyUrl); 0355 m_popuppub->addAction(editKey); 0356 m_popuppub->addAction(refreshKey); 0357 m_popuppub->addAction(createGroup); 0358 m_popuppub->addSeparator(); 0359 m_popuppub->addAction(importAllSignKeys); 0360 0361 m_popupsec = new QMenu(this); 0362 m_popupsec->addAction(exportPublicKey); 0363 m_popupsec->addAction(m_sendEmail); 0364 m_popupsec->addAction(signKey); 0365 m_popupsec->addAction(signUid); 0366 m_popupsec->addAction(signMailUid); 0367 m_popupsec->addAction(infoKey); 0368 m_popupsec->addAction(openKeyUrl); 0369 m_popupsec->addAction(editKey); 0370 m_popupsec->addAction(refreshKey); 0371 m_popupsec->addAction(setDefaultKey); 0372 m_popupsec->addSeparator(); 0373 m_popupsec->addAction(importAllSignKeys); 0374 m_popupsec->addSeparator(); 0375 m_popupsec->addAction(addPhoto); 0376 m_popupsec->addAction(addUid); 0377 m_popupsec->addAction(exportSecretKey); 0378 m_popupsec->addAction(deleteKeyPair); 0379 0380 m_popupgroup = new QMenu(this); 0381 m_popupgroup->addAction(editCurrentGroup); 0382 m_popupgroup->addAction(m_groupRename); 0383 m_popupgroup->addAction(delGroup); 0384 m_popupgroup->addAction(refreshKey); 0385 0386 m_popupout = new QMenu(this); 0387 m_popupout->addAction(importKey); 0388 0389 m_popupsig = new QMenu(this); 0390 m_popupsig->addAction(importSignatureKey); 0391 m_popupsig->addAction(delSignKey); 0392 0393 m_popupphoto = new QMenu(this); 0394 m_popupphoto->addAction(openPhoto); 0395 m_popupphoto->addAction(signUid); 0396 m_popupphoto->addAction(signMailUid); 0397 m_popupphoto->addAction(deletePhoto); 0398 0399 m_popupuid = new QMenu(this); 0400 m_popupuid->addAction(m_sendEmail); 0401 m_popupuid->addAction(signMailUid); 0402 m_popupuid->addAction(signUid); 0403 m_popupuid->addAction(delUid); 0404 m_popupuid->addAction(setPrimUid); 0405 0406 m_popuporphan = new QMenu(this); 0407 m_popuporphan->addAction(regeneratePublic); 0408 m_popuporphan->addAction(deleteKeyPair); 0409 0410 exportPublicKey->setEnabled(false); 0411 0412 KConfigGroup cg = KConfigGroup(KSharedConfig::openConfig().data(), u"KeyView"_s); 0413 iview->restoreLayout(cg); 0414 0415 connect(photoProps, &KSelectAction::indexTriggered, this, &KeysManager::slotSetPhotoSize); 0416 connect(trustProps, &KSelectAction::indexTriggered, this, &KeysManager::slotSetTrustFilter); 0417 0418 QLabel *searchLabel = new QLabel(i18n("Search:"), this); 0419 m_listviewsearch = new QLineEdit(this); 0420 m_listviewsearch->setClearButtonEnabled(true); 0421 0422 QWidget *searchWidget = new QWidget(this); 0423 QHBoxLayout *searchLayout = new QHBoxLayout(searchWidget); 0424 searchLayout->setContentsMargins(0, 0, 0, 0); 0425 searchLayout->addWidget(searchLabel); 0426 searchLayout->addWidget(m_listviewsearch); 0427 searchLayout->addStretch(); 0428 0429 QWidgetAction *searchLineAction = new QWidgetAction(/*i18nc("Name of the action that is a search line, shown for example in the toolbar configuration dialog", 0430 "Search Line"), */this); 0431 actionCollection()->addAction(QLatin1String( "search_line" ), searchLineAction); 0432 searchLineAction->setDefaultWidget(searchWidget); 0433 0434 action = actionCollection()->addAction(QLatin1String("search_focus"), m_listviewsearch, QOverload<>::of(&QWidget::setFocus)); 0435 action->setText(i18nc("Name of the action that gives the focus to the search line", "Focus Search Line")); 0436 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::Key_F6)); 0437 connect(m_listviewsearch, &QLineEdit::textChanged, iproxy, &KeyListProxyModel::setFilterFixedString); 0438 0439 setActionDescriptions(1); 0440 0441 // get all keys data 0442 setupGUI(KXmlGuiWindow::Create | Save | ToolBar | StatusBar | Keys, QLatin1String( "keysmanager.rc" )); 0443 0444 sTrust->setChecked(KGpgSettings::showTrust()); 0445 iview->setColumnHidden(2, !KGpgSettings::showTrust()); 0446 sSize->setChecked(KGpgSettings::showSize()); 0447 iview->setColumnHidden(3, !KGpgSettings::showSize()); 0448 sCreat->setChecked(KGpgSettings::showCreat()); 0449 iview->setColumnHidden(4, !KGpgSettings::showCreat()); 0450 sExpi->setChecked(KGpgSettings::showExpi()); 0451 iview->setColumnHidden(5, !KGpgSettings::showExpi()); 0452 iproxy->setOnlySecret(KGpgSettings::showSecret()); 0453 0454 m_statusBarLabel.setAlignment(Qt::AlignCenter); 0455 statusBar()->addPermanentWidget(&m_statusBarLabel); 0456 0457 cg = KConfigGroup(KSharedConfig::openConfig().data(), u"MainWindow"_s); 0458 setAutoSaveSettings(cg, true); 0459 applyMainWindowSettings(cg); 0460 0461 connect(this, &KeysManager::fontChanged, s_kgpgEditor, &KgpgEditor::slotSetFont); 0462 QNetworkInformation::loadDefaultBackend(); 0463 auto networkInformation = QNetworkInformation::instance(); 0464 if (networkInformation) { 0465 Q_ASSERT(networkInformation); 0466 connect(networkInformation, &QNetworkInformation::reachabilityChanged, this, [this](QNetworkInformation::Reachability reachability) { 0467 toggleNetworkActions(reachability == QNetworkInformation::Reachability::Online); 0468 }); 0469 0470 toggleNetworkActions(networkInformation->reachability() == QNetworkInformation::Reachability::Online); 0471 } 0472 importSignatureKey->setEnabled(false); 0473 0474 stateChanged(QStringLiteral("empty_list")); 0475 0476 QMetaObject::invokeMethod(this, "refreshkey", Qt::QueuedConnection); 0477 } 0478 0479 void KeysManager::slotGenerateKey() 0480 { 0481 if (m_genkey) { 0482 KMessageBox::error(this, 0483 i18n("Another key generation operation is still in progress.\nPlease wait a moment until this operation is complete."), 0484 i18n("Generating new key pair")); 0485 return; 0486 } 0487 0488 QPointer<KgpgKeyGenerate> kg = new KgpgKeyGenerate(this); 0489 if (kg->exec() == QDialog::Accepted) { 0490 if (!kg->isExpertMode()) { 0491 KGpgGenerateKey *genkey = new KGpgGenerateKey(this, kg->name(), kg->email(), 0492 kg->comment(), kg->algo(), kg->size(), kg->days(), kg->expiration(), 0493 kg->caps()); 0494 0495 m_genkey = new KGpgTransactionJob(genkey); 0496 connect(m_genkey, &KGpgTransactionJob::result, this, &KeysManager::slotGenerateKeyDone); 0497 0498 KIO::getJobTracker()->registerJob(m_genkey); 0499 m_genkey->start(); 0500 QApplication::setOverrideCursor(Qt::BusyCursor); 0501 } else { 0502 KConfigGroup config(KSharedConfig::openConfig(), u"General"_s); 0503 0504 QString terminalApp(config.readPathEntry("TerminalApplication", QLatin1String( "konsole" ))); 0505 0506 const QString gpgbin = KGpgSettings::gpgBinaryPath(); 0507 QString gpg_args = gpgbin + QLatin1String(" --expert"); 0508 if (GPGProc::gpgVersion(GPGProc::gpgVersionString(gpgbin)) > 0x20100) 0509 gpg_args += QLatin1String(" --full-gen-key "); 0510 else 0511 gpg_args += QLatin1String(" --gen-key "); 0512 0513 gpg_args += GPGProc::getGpgHomeArguments(gpgbin).join(QLatin1Char(' ')); 0514 0515 QStringList args; 0516 args << QLatin1String( "-e" ) 0517 << gpg_args; 0518 0519 QProcess *genKeyProc = new QProcess(this); 0520 genKeyProc->start(terminalApp, args); 0521 if (!genKeyProc->waitForStarted(-1)) { 0522 KMessageBox::error(this, i18n("Generating new key pair"), 0523 i18n("Can not start \"konsole\" application for expert mode.")); 0524 } else { 0525 genKeyProc->waitForFinished(-1); 0526 refreshkey(); 0527 } 0528 } 0529 } 0530 0531 delete kg; 0532 } 0533 0534 void KeysManager::showKeyManager() 0535 { 0536 show(); 0537 } 0538 0539 void KeysManager::slotOpenEditor() 0540 { 0541 KgpgEditor *kgpgtxtedit = new KgpgEditor(this, imodel, Qt::Window); 0542 0543 connect(this, &KeysManager::fontChanged, kgpgtxtedit, &KgpgEditor::slotSetFont); 0544 0545 kgpgtxtedit->show(); 0546 } 0547 0548 void KeysManager::changeMessage(const QString &msg, const bool keep) 0549 { 0550 int timeout = keep ? 0 : 10000; 0551 0552 statusBar()->showMessage(msg, timeout); 0553 } 0554 0555 void KeysManager::updateStatusCounter() 0556 { 0557 m_statusBarLabel.setText(imodel->statusCountMessage()); 0558 } 0559 0560 void KeysManager::slotGenerateKeyDone(KJob *job) 0561 { 0562 changeMessage(i18nc("Application ready for user input", "Ready")); 0563 QApplication::restoreOverrideCursor(); 0564 0565 KGpgTransactionJob *tjob = qobject_cast<KGpgTransactionJob *>(job); 0566 0567 const KGpgGenerateKey * const genkey = qobject_cast<const KGpgGenerateKey *>(tjob->getTransaction()); 0568 int res = tjob->getResultCode(); 0569 0570 const QString infomessage(i18n("Generating new key pair")); 0571 0572 switch (res) { 0573 case KGpgTransaction::TS_BAD_PASSPHRASE: 0574 KMessageBox::error(this, i18n("Bad passphrase. Cannot generate a new key pair."), infomessage); 0575 break; 0576 case KGpgTransaction::TS_USER_ABORTED: 0577 KMessageBox::error(this, i18n("Aborted by the user. Cannot generate a new key pair."), infomessage); 0578 break; 0579 case KGpgTransaction::TS_INVALID_EMAIL: 0580 KMessageBox::error(this, i18n("The email address is not valid. Cannot generate a new key pair."), infomessage); 0581 break; 0582 case KGpgGenerateKey::TS_INVALID_NAME: 0583 KMessageBox::error(this, i18n("The name is not accepted by gpg. Cannot generate a new key pair."), infomessage); 0584 break; 0585 case KGpgTransaction::TS_OK: { 0586 updateStatusCounter(); 0587 0588 QPointer<QDialog> keyCreated = new QDialog(this); 0589 keyCreated->setWindowTitle(i18n("New Key Pair Created")); 0590 0591 QVBoxLayout *mainLayout = new QVBoxLayout(keyCreated); 0592 keyCreated->setLayout(mainLayout); 0593 0594 newKey *page = new newKey(keyCreated); 0595 page->TLname->setText(QLatin1String( "<b>" ) + genkey->getName() + QLatin1String( "</b>" )); 0596 0597 const QString email(genkey->getEmail()); 0598 page->TLemail->setText(QLatin1String( "<b>" ) + email + QLatin1String( "</b>" )); 0599 0600 page->kURLRequester1->setUrl(KGpgRevokeDialog::revokeUrl(genkey->getName(), email)); 0601 0602 const QString fingerprint(genkey->getFingerprint()); 0603 page->TLid->setText(QLatin1String( "<b>" ) % fingerprint.right(8) % QLatin1String( "</b>" )); 0604 page->LEfinger->setText(fingerprint); 0605 page->CBdefault->setChecked(true); 0606 page->show(); 0607 mainLayout->addWidget(page); 0608 page->buttonBox->button(QDialogButtonBox::Ok)->setShortcut(Qt::CTRL | Qt::Key_Return); 0609 connect(page->buttonBox, &QDialogButtonBox::accepted, keyCreated.data(), &QDialog::accept); 0610 0611 keyCreated->exec(); 0612 if (keyCreated.isNull()) 0613 return; 0614 0615 imodel->refreshKey(fingerprint); 0616 KGpgKeyNode *knode = imodel->getRootNode()->findKey(fingerprint); 0617 if (page->CBdefault->isChecked()) 0618 imodel->setDefaultKey(knode); 0619 0620 iview->selectNode(knode); 0621 0622 if (page->CBsave->isChecked() || page->CBprint->isChecked()) { 0623 QUrl revurl; 0624 if (page->CBsave->isChecked()) 0625 revurl = page->kURLRequester1->url(); 0626 0627 KGpgGenerateRevoke *genRev = new KGpgGenerateRevoke(this, fingerprint, revurl, 0628 0, i18n("backup copy")); 0629 0630 connect(genRev, &KGpgGenerateRevoke::done, this, &KeysManager::slotRevokeGenerated); 0631 0632 if (page->CBprint->isChecked()) 0633 connect(genRev, &KGpgGenerateRevoke::revokeCertificate, this, &KeysManager::doPrint); 0634 0635 genRev->start(); 0636 } 0637 delete keyCreated; 0638 break; 0639 } 0640 default: 0641 KMessageBox::detailedError(this, 0642 i18n("gpg process did not finish. Cannot generate a new key pair."), 0643 genkey->gpgErrorMessage(), infomessage); 0644 } 0645 0646 m_genkey = nullptr; 0647 } 0648 0649 void KeysManager::slotShowTrust() 0650 { 0651 bool b = !sTrust->isChecked(); 0652 iview->setColumnHidden(KEYCOLUMN_TRUST, b); 0653 if (!b && (iview->columnWidth(KEYCOLUMN_TRUST) == 0)) 0654 iview->resizeColumnToContents(KEYCOLUMN_TRUST); 0655 } 0656 0657 void KeysManager::slotShowExpiration() 0658 { 0659 bool b = !sExpi->isChecked(); 0660 iview->setColumnHidden(KEYCOLUMN_EXPIR, b); 0661 if (!b && (iview->columnWidth(KEYCOLUMN_EXPIR) == 0)) 0662 iview->resizeColumnToContents(KEYCOLUMN_EXPIR); 0663 } 0664 0665 void KeysManager::slotShowSize() 0666 { 0667 bool b = !sSize->isChecked(); 0668 iview->setColumnHidden(KEYCOLUMN_SIZE, b); 0669 if (!b && (iview->columnWidth(KEYCOLUMN_SIZE) == 0)) 0670 iview->resizeColumnToContents(KEYCOLUMN_SIZE); 0671 } 0672 0673 void KeysManager::slotShowCreation() 0674 { 0675 bool b = !sCreat->isChecked(); 0676 iview->setColumnHidden(KEYCOLUMN_CREAT, b); 0677 if (!b && (iview->columnWidth(KEYCOLUMN_CREAT) == 0)) 0678 iview->resizeColumnToContents(KEYCOLUMN_CREAT); 0679 } 0680 0681 void KeysManager::slotShowLongId(bool b) 0682 { 0683 iproxy->setIdLength(b ? 16 : 8); 0684 } 0685 0686 void KeysManager::slotSetTrustFilter(int i) 0687 { 0688 KgpgCore::KgpgKeyTrustFlag t; 0689 0690 Q_ASSERT((i >= 0) && (i < 5)); 0691 switch (i) { 0692 case 0: 0693 t = TRUST_MINIMUM; 0694 break; 0695 case 1: 0696 t = TRUST_UNDEFINED; 0697 break; 0698 case 2: 0699 t = TRUST_MARGINAL; 0700 break; 0701 case 3: 0702 t = TRUST_FULL; 0703 break; 0704 default: 0705 t = TRUST_ULTIMATE; 0706 } 0707 0708 iproxy->setTrustFilter(t); 0709 } 0710 0711 void KeysManager::slotGotoDefaultKey() 0712 { 0713 iview->selectNode(imodel->getRootNode()->findKey(KGpgSettings::defaultKey())); 0714 } 0715 0716 void KeysManager::refreshKeyFromServer() 0717 { 0718 const auto keysList = iview->selectedNodes(); 0719 if (keysList.empty()) 0720 return; 0721 0722 QStringList keyIDS; 0723 0724 for (KGpgNode *item : keysList) { 0725 if (item->getType() == ITYPE_GROUP) 0726 { 0727 for (int j = 0; j < item->getChildCount(); j++) 0728 keyIDS << item->getChild(j)->getId(); 0729 0730 continue; 0731 } 0732 0733 if (item->getType() & ITYPE_PAIR) { 0734 keyIDS << item->getId(); 0735 } else { 0736 KMessageBox::error(this, i18n("You can only refresh primary keys. Please check your selection.")); 0737 return; 0738 } 0739 } 0740 0741 QString proxy; 0742 if (KGpgSettings::useProxy()) 0743 proxy = QLatin1String( qgetenv("http_proxy") ); 0744 0745 KGpgRefreshKeys *t = new KGpgRefreshKeys(this, KGpgSettings::keyServers().first(), keyIDS, true, proxy); 0746 connect(t, &KGpgRefreshKeys::done, this, &KeysManager::slotKeyRefreshDone); 0747 QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); 0748 t->start(); 0749 } 0750 0751 void KeysManager::slotKeyRefreshDone(int result) 0752 { 0753 KGpgRefreshKeys *t = qobject_cast<KGpgRefreshKeys *>(sender()); 0754 Q_ASSERT(t != nullptr); 0755 0756 if (result == KGpgTransaction::TS_USER_ABORTED) { 0757 t->deleteLater(); 0758 QApplication::restoreOverrideCursor(); 0759 return; 0760 } 0761 0762 const QStringList log(t->getLog()); 0763 const QStringList keys = KGpgImport::getImportedIds(log, 0xffff); 0764 const QStringList message(KGpgImport::getImportMessage(log)); 0765 0766 t->deleteLater(); 0767 0768 if (!keys.empty()) 0769 imodel->refreshKeys(keys); 0770 0771 QApplication::restoreOverrideCursor(); 0772 (void) new KgpgDetailedInfo(this, message.join(QLatin1String("\n")), log.join(QLatin1String("<br/>")), 0773 KGpgImport::getDetailedImportMessage(log, imodel).split(QLatin1Char('\n'))); 0774 } 0775 0776 void KeysManager::slotDelUid() 0777 { 0778 KGpgUidNode *nd = iview->selectedNode()->toUidNode(); 0779 0780 KGpgDelUid *deluid = new KGpgDelUid(this, nd); 0781 0782 connect(deluid, &KGpgDelUid::done, this, &KeysManager::slotDelUidDone); 0783 deluid->start(); 0784 } 0785 0786 void KeysManager::slotDelUidDone(int result) 0787 { 0788 KGpgDelUid * const deluid = qobject_cast<KGpgDelUid *>(sender()); 0789 Q_ASSERT(deluid != nullptr); 0790 0791 sender()->deleteLater(); 0792 if (result == KGpgTransaction::TS_OK) 0793 imodel->refreshKey(deluid->getKeyId()); 0794 // FIXME: do something useful with result if it is a failure 0795 } 0796 0797 void KeysManager::slotPrimUid() 0798 { 0799 KGpgPrimaryUid *puid = new KGpgPrimaryUid(this, iview->selectedNode()->toUidNode()); 0800 0801 connect(puid, &KGpgPrimaryUid::done, this, &KeysManager::slotPrimUidDone); 0802 0803 puid->start(); 0804 } 0805 0806 void KeysManager::slotPrimUidDone(int result) 0807 { 0808 const QString kid(qobject_cast<KGpgPrimaryUid *>(sender())->getKeyId()); 0809 0810 sender()->deleteLater(); 0811 0812 if (result == KGpgTransaction::TS_OK) 0813 imodel->refreshKey(kid); 0814 // FIXME: some error reporting 0815 } 0816 0817 void KeysManager::slotregenerate() 0818 { 0819 QString regID = iview->selectedNode()->getId(); 0820 KProcess *p1, *p2, *p3; 0821 0822 p1 = new KProcess(this); 0823 *p1 << KGpgSettings::gpgBinaryPath() 0824 << QLatin1String("--no-secmem-warning") 0825 << QLatin1String("--export-secret-key") 0826 << regID; 0827 p1->setOutputChannelMode(KProcess::OnlyStdoutChannel); 0828 0829 p2 = new KProcess(this); 0830 *p2 << QLatin1String("gpgsplit") 0831 << QLatin1String("--no-split") 0832 << QLatin1String("--secret-to-public"); 0833 p2->setOutputChannelMode(KProcess::OnlyStdoutChannel); 0834 0835 p3 = new KProcess(this); 0836 *p3 << KGpgSettings::gpgBinaryPath() 0837 << QLatin1String("--import"); 0838 0839 p1->setStandardOutputProcess(p2); 0840 p2->setStandardOutputProcess(p3); 0841 0842 p1->start(); 0843 p2->start(); 0844 p3->start(); 0845 0846 p1->waitForFinished(); 0847 p2->waitForFinished(); 0848 p3->waitForFinished(); 0849 0850 delete p1; 0851 delete p2; 0852 delete p3; 0853 0854 imodel->refreshKey(regID); 0855 } 0856 0857 void KeysManager::slotAddUid() 0858 { 0859 if (m_adduid) { 0860 KMessageBox::error(this, i18n("Another operation is still in progress.\nPlease wait a moment until this operation is complete."), 0861 i18n("Add New User Id")); 0862 return; 0863 } 0864 0865 addUidWidget = new QDialog(this); 0866 addUidWidget->setWindowTitle(i18n("Add New User Id")); 0867 QVBoxLayout *mainLayout = new QVBoxLayout(addUidWidget); 0868 addUidWidget->setLayout(mainLayout); 0869 keyUid = new AddUid(addUidWidget); 0870 mainLayout->addWidget(keyUid); 0871 0872 keyUid->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); 0873 keyUid->buttonBox->button(QDialogButtonBox::Ok)->setShortcut(Qt::CTRL | Qt::Key_Return); 0874 connect(keyUid->buttonBox, &QDialogButtonBox::accepted, addUidWidget, &QDialog::accept); 0875 connect(keyUid->buttonBox, &QDialogButtonBox::rejected, addUidWidget, &QDialog::reject); 0876 0877 //keyUid->setMinimumSize(keyUid->sizeHint()); 0878 keyUid->setMinimumWidth(300); 0879 0880 connect(keyUid->qLineEdit1, &QLineEdit::textChanged, this, &KeysManager::slotAddUidEnable); 0881 if (addUidWidget->exec() != QDialog::Accepted) 0882 return; 0883 0884 m_adduid = new KGpgAddUid(this, iview->selectedNode()->getId(), keyUid->qLineEdit1->text(), 0885 keyUid->qLineEdit2->text(), keyUid->qLineEdit3->text()); 0886 connect(m_adduid, &KGpgAddUid::done, this, &KeysManager::slotAddUidFin); 0887 m_adduid->start(); 0888 } 0889 0890 void KeysManager::slotAddUidFin(int res) 0891 { 0892 // TODO error reporting 0893 if (res == 0) 0894 imodel->refreshKey(m_adduid->getKeyid()); 0895 m_adduid->deleteLater(); 0896 m_adduid = nullptr; 0897 } 0898 0899 void KeysManager::slotAddUidEnable(const QString & name) 0900 { 0901 keyUid->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(name.length() > 4); 0902 } 0903 0904 void KeysManager::slotAddPhoto() 0905 { 0906 QString mess = i18n("The image must be a JPEG file. Remember that the image is stored within your public key, so " 0907 "if you use a very large picture, your key will become very large as well. The size should not exceed 6 KiB. " 0908 "An image size of around 240x288 is a good size to use."); 0909 0910 if (KMessageBox::warningContinueCancel(nullptr, mess) != KMessageBox::Continue) 0911 return; 0912 0913 QString imagepath = QFileDialog::getOpenFileName(nullptr, QString(), QString(), QLatin1String( "image/jpeg" )); 0914 if (imagepath.isEmpty()) 0915 return; 0916 0917 KGpgAddPhoto *addphoto = new KGpgAddPhoto(this, iview->selectedNode()->getId(), imagepath); 0918 connect(addphoto, &KGpgAddPhoto::done, this, &KeysManager::slotAddPhotoFinished); 0919 addphoto->start(); 0920 } 0921 0922 void KeysManager::slotAddPhotoFinished(int res) 0923 { 0924 sender()->deleteLater(); 0925 0926 // TODO : add res == 3 (bad passphrase) 0927 0928 if (res == 0) 0929 slotUpdatePhoto(); 0930 } 0931 0932 void KeysManager::slotDeletePhoto() 0933 { 0934 KGpgNode *nd = iview->selectedNode(); 0935 KGpgUatNode *und = nd->toUatNode(); 0936 KGpgKeyNode *parent = und->getParentKeyNode(); 0937 0938 QString mess = i18n("<qt>Are you sure you want to delete Photo id <b>%1</b><br/>from key <b>%2 <%3></b>?</qt>", 0939 und->getId(), parent->getName(), parent->getEmail()); 0940 0941 if (KMessageBox::warningContinueCancel(this, mess) != KMessageBox::Continue) 0942 return; 0943 0944 KGpgDelUid *deluid = new KGpgDelUid(this, und); 0945 connect(deluid, &KGpgDelUid::done, this, &KeysManager::slotDelPhotoFinished); 0946 0947 deluid->start(); 0948 } 0949 0950 void KeysManager::slotDelPhotoFinished(int res) 0951 { 0952 sender()->deleteLater(); 0953 0954 // TODO : add res == 3 (bad passphrase) 0955 0956 if (res == 0) { 0957 KGpgNode *nd = iview->selectedNode(); 0958 imodel->refreshKey(nd->getParentKeyNode()->toKeyNode()); 0959 } 0960 } 0961 0962 void KeysManager::slotUpdatePhoto() 0963 { 0964 KGpgNode *nd = iview->selectedNode(); 0965 imodel->refreshKey(nd->toKeyNode()); 0966 } 0967 0968 void KeysManager::slotSetPhotoSize(int size) 0969 { 0970 switch(size) { 0971 case 1: 0972 iproxy->setPreviewSize(22); 0973 break; 0974 case 2: 0975 iproxy->setPreviewSize(42); 0976 break; 0977 case 3: 0978 iproxy->setPreviewSize(65); 0979 break; 0980 default: 0981 iproxy->setPreviewSize(0); 0982 break; 0983 } 0984 } 0985 0986 void KeysManager::addToKAB() 0987 { 0988 KGpgNode *nd = iview->selectedNode(); 0989 if (nd == nullptr) 0990 return; 0991 0992 Akonadi::ContactSearchJob * const job = new Akonadi::ContactSearchJob(); 0993 job->setLimit(1); 0994 job->setQuery(Akonadi::ContactSearchJob::Email, nd->getEmail()); 0995 connect(job, &Akonadi::ContactSearchJob::result, this, &KeysManager::slotAddressbookSearchResult); 0996 0997 m_addIds[job] = nd; 0998 } 0999 1000 void KeysManager::slotAddressbookSearchResult(KJob *job) 1001 { 1002 KGpgNode * const nd = m_addIds.value(job, nullptr); 1003 1004 if (!nd) 1005 return; 1006 1007 Akonadi::ContactSearchJob *searchJob = qobject_cast<Akonadi::ContactSearchJob*>(job); 1008 Q_ASSERT(searchJob); 1009 const KContacts::Addressee::List addresseeList = searchJob->contacts(); 1010 1011 m_addIds.take(job); 1012 1013 Akonadi::ContactEditorDialog *dlg; 1014 // KContacts::Key key; TODO 1015 if (!addresseeList.isEmpty()) { 1016 dlg = new Akonadi::ContactEditorDialog(Akonadi::ContactEditorDialog::EditMode, this); 1017 dlg->setContact(searchJob->items().at(0)); 1018 } else { 1019 KContacts::Addressee addressee; 1020 addressee.setNameFromString(nd->getName()); 1021 addressee.setEmails(QStringList(nd->getEmail())); 1022 dlg = new Akonadi::ContactEditorDialog(Akonadi::ContactEditorDialog::CreateMode, this); 1023 dlg->editor()->setContactTemplate(addressee); 1024 } 1025 1026 connect(dlg, &Akonadi::ContactEditorDialog::finished, dlg, &Akonadi::ContactEditorDialog::deleteLater); 1027 dlg->show(); 1028 } 1029 1030 void KeysManager::slotManpage() 1031 { 1032 const KService::Ptr helpCenter = KService::serviceByDesktopName(QStringLiteral("org.kde.khelpcenter")); 1033 auto job = new KIO::ApplicationLauncherJob(helpCenter); 1034 job->setUrls({QUrl(QStringLiteral("man:/gpg"))}); 1035 job->start(); 1036 } 1037 1038 void KeysManager::showKeyServer() 1039 { 1040 QPointer<KeyServer> ks = new KeyServer(this, imodel); 1041 connect(ks.data(), &KeyServer::importFinished, imodel, QOverload<const QStringList &>::of(&KGpgItemModel::refreshKeys)); 1042 ks->exec(); 1043 1044 delete ks; 1045 refreshkey(); 1046 } 1047 1048 void KeysManager::checkList() 1049 { 1050 const auto exportList = iview->selectedNodes(); 1051 1052 switch (exportList.size()) { 1053 case 0: 1054 stateChanged(QStringLiteral("empty_list")); 1055 return; 1056 case 1: 1057 if (exportList.at(0)->getType() == ITYPE_GROUP) { 1058 stateChanged(QLatin1String( "group_selected" )); 1059 } else { 1060 stateChanged(QLatin1String( "single_selected" )); 1061 m_revokeKey->setEnabled(exportList.at(0)->getType() == ITYPE_PAIR); 1062 if (terminalkey) 1063 editKey->setEnabled(false); 1064 m_sendEmail->setEnabled(!exportList[0]->getEmail().isEmpty()); 1065 setDefaultKey->setEnabled(!imodel->isDefaultKey(exportList[0])); 1066 } 1067 break; 1068 default: 1069 stateChanged(QLatin1String( "multi_selected" )); 1070 } 1071 if (!m_online) 1072 refreshKey->setEnabled(false); 1073 1074 switch (exportList.at(0)->getType()) { 1075 case ITYPE_PUBLIC: 1076 changeMessage(i18n("Public Key")); 1077 break; 1078 case ITYPE_SUB: 1079 changeMessage(i18n("Sub Key")); 1080 break; 1081 case ITYPE_PAIR: 1082 changeMessage(i18n("Secret Key Pair")); 1083 break; 1084 case ITYPE_GROUP: 1085 changeMessage(i18n("Key Group")); 1086 break; 1087 case ITYPE_SIGN: 1088 changeMessage(i18n("Signature")); 1089 break; 1090 case ITYPE_UID: 1091 changeMessage(i18n("User ID")); 1092 break; 1093 case ITYPE_REVSIGN: 1094 changeMessage(i18n("Revocation Signature")); 1095 break; 1096 case ITYPE_UAT: 1097 changeMessage(i18n("Photo ID")); 1098 break; 1099 case ITYPE_SECRET: 1100 changeMessage(i18n("Orphaned Secret Key")); 1101 break; 1102 case ITYPE_GPUBLIC: 1103 case ITYPE_GSECRET: 1104 case ITYPE_GPAIR: 1105 changeMessage(i18n("Group member")); 1106 break; 1107 default: 1108 qCDebug(KGPG_LOG_GENERAL) << "Oops, unmatched type value" << exportList.at(0)->getType(); 1109 } 1110 } 1111 1112 void KeysManager::quitApp() 1113 { 1114 // close window 1115 saveToggleOpts(); 1116 qApp->quit(); 1117 } 1118 1119 void KeysManager::saveToggleOpts(void) 1120 { 1121 KConfigGroup cg = KConfigGroup(KSharedConfig::openConfig().data(), u"KeyView"_s); 1122 iview->saveLayout(cg); 1123 KGpgSettings::setPhotoProperties(photoProps->currentItem()); 1124 KGpgSettings::setShowTrust(sTrust->isChecked()); 1125 KGpgSettings::setShowExpi(sExpi->isChecked()); 1126 KGpgSettings::setShowCreat(sCreat->isChecked()); 1127 KGpgSettings::setShowSize(sSize->isChecked()); 1128 KGpgSettings::setTrustLevel(trustProps->currentItem()); 1129 KGpgSettings::setShowSecret(hPublic->isChecked()); 1130 KGpgSettings::setShowLongKeyId(longId->isChecked()); 1131 KGpgSettings::self()->save(); 1132 } 1133 1134 void KeysManager::readOptions() 1135 { 1136 m_clipboardmode = QClipboard::Clipboard; 1137 if (KGpgSettings::useMouseSelection() && (qApp->clipboard()->supportsSelection())) 1138 m_clipboardmode = QClipboard::Selection; 1139 1140 if (imodel != nullptr) 1141 updateStatusCounter(); 1142 1143 if (KGpgSettings::showSystray()) { 1144 setupTrayIcon(); 1145 } else { 1146 delete m_trayicon; 1147 m_trayicon = nullptr; 1148 } 1149 } 1150 1151 void KeysManager::showOptions() 1152 { 1153 if (KConfigDialog::showDialog(QLatin1String( "settings" ))) 1154 return; 1155 1156 QPointer<kgpgOptions> optionsDialog = new kgpgOptions(this, imodel); 1157 connect(optionsDialog.data(), &kgpgOptions::settingsUpdated, this, &KeysManager::readAllOptions); 1158 connect(optionsDialog.data(), &kgpgOptions::homeChanged, imodel, &KGpgItemModel::refreshAllKeys); 1159 connect(optionsDialog.data(), &kgpgOptions::homeChanged, imodel, &KGpgItemModel::refreshGroups); 1160 connect(optionsDialog.data(), &kgpgOptions::refreshTrust, imodel, &KGpgItemModel::refreshTrust); 1161 connect(optionsDialog.data(), &kgpgOptions::changeFont, this, &KeysManager::fontChanged); 1162 optionsDialog->exec(); 1163 delete optionsDialog; 1164 1165 s_kgpgEditor->m_recentfiles->setMaxItems(KGpgSettings::recentFiles()); 1166 } 1167 1168 void KeysManager::readAllOptions() 1169 { 1170 readOptions(); 1171 Q_EMIT readAgainOptions(); 1172 } 1173 1174 void KeysManager::slotSetDefKey() 1175 { 1176 setDefaultKeyNode(iview->selectedNode()->toKeyNode()); 1177 } 1178 1179 void KeysManager::slotSetDefaultKey(const QString &newID) 1180 { 1181 KGpgKeyNode *ndef = imodel->getRootNode()->findKey(newID); 1182 1183 if (ndef == nullptr) { 1184 KGpgSettings::setDefaultKey(newID); 1185 KGpgSettings::self()->save(); 1186 return; 1187 } 1188 1189 setDefaultKeyNode(ndef); 1190 } 1191 1192 void KeysManager::setDefaultKeyNode(KGpgKeyNode *key) 1193 { 1194 const QString &newID(key->getId()); 1195 1196 if (newID == KGpgSettings::defaultKey()) 1197 return; 1198 1199 KGpgSettings::setDefaultKey(newID); 1200 KGpgSettings::self()->save(); 1201 1202 imodel->setDefaultKey(key); 1203 } 1204 1205 void 1206 KeysManager::setActionDescriptions(int cnt) 1207 { 1208 signUid->setText(i18np("&Sign User ID ...", "&Sign User IDs ...", cnt)); 1209 signMailUid->setText(i18np("Sign and &Mail User ID ...", "Sign and &Mail User IDs ...", cnt)); 1210 exportPublicKey->setText(i18np("E&xport Public Key...", "E&xport Public Keys...", cnt)); 1211 refreshKey->setText(i18np("&Refresh Key From Keyserver", "&Refresh Keys From Keyserver", cnt)); 1212 createGroup->setText(i18np("&Create Group with Selected Key...", "&Create Group with Selected Keys...", cnt)); 1213 signKey->setText(i18np("&Sign Key...", "&Sign Keys...", cnt)); 1214 delUid->setText(i18np("&Delete User ID", "&Delete User IDs", cnt)); 1215 delSignKey->setText(i18np("Delete Sign&ature", "Delete Sign&atures", cnt)); 1216 importSignatureKey->setText(i18np("Import Key From Keyserver", "Import Keys From Keyserver", cnt)); 1217 deleteKey->setText(i18np("&Delete Key", "&Delete Keys", cnt)); 1218 } 1219 1220 void 1221 KeysManager::slotMenu(const QPoint &pos) 1222 { 1223 QPoint globpos = iview->mapToGlobal(pos); 1224 bool sametype; 1225 KgpgItemType itype; 1226 const auto ndlist = iview->selectedNodes(&sametype, &itype); 1227 bool unksig = false; 1228 QSet<QString> l; 1229 const int cnt = ndlist.size(); 1230 1231 // find out if an item has unknown signatures. Only check if the item has been 1232 // expanded before as expansion is very expensive and can take several seconds 1233 // that will freeze the UI meanwhile. 1234 for (KGpgNode *nd : ndlist) { 1235 if (!nd->hasChildren()) 1236 continue; 1237 1238 KGpgExpandableNode *exnd = nd->toExpandableNode(); 1239 if (!exnd->wasExpanded()) { 1240 unksig = true; 1241 break; 1242 } 1243 getMissingSigs(l, exnd); 1244 if (!l.isEmpty()) { 1245 unksig = true; 1246 break; 1247 } 1248 } 1249 importAllSignKeys->setEnabled(unksig && m_online); 1250 1251 signUid->setEnabled(!(itype & ~(ITYPE_PAIR | ITYPE_UID | ITYPE_UAT))); 1252 signMailUid->setEnabled(signUid->isEnabled()); 1253 setActionDescriptions(cnt); 1254 1255 if (itype == ITYPE_SIGN) { 1256 bool allunksig = true; 1257 for (KGpgNode *nd : ndlist) { 1258 allunksig = nd->toSignNode()->isUnknown(); 1259 if (!allunksig) 1260 break; 1261 } 1262 1263 importSignatureKey->setEnabled(allunksig && m_online); 1264 delSignKey->setEnabled( (cnt == 1) ); 1265 m_popupsig->exec(globpos); 1266 } else if (itype == ITYPE_UID) { 1267 if (cnt == 1) { 1268 KGpgKeyNode *knd = ndlist.at(0)->toUidNode()->getParentKeyNode(); 1269 setPrimUid->setEnabled(knd->getType() & ITYPE_SECRET); 1270 } 1271 m_popupuid->exec(globpos); 1272 } else if ((itype == ITYPE_UAT) && (cnt == 1)) { 1273 m_popupphoto->exec(globpos); 1274 } else if ((itype == ITYPE_PAIR) && (cnt == 1)) { 1275 m_popupsec->exec(globpos); 1276 } else if ((itype == ITYPE_SECRET) && (cnt == 1)) { 1277 m_popuporphan->exec(globpos); 1278 } else if (itype == ITYPE_GROUP) { 1279 delGroup->setEnabled( (cnt == 1) ); 1280 editCurrentGroup->setEnabled( (cnt == 1) ); 1281 m_groupRename->setEnabled( (cnt == 1) ); 1282 m_popupgroup->exec(globpos); 1283 } else if (!(itype & ~(ITYPE_PAIR | ITYPE_GROUP))) { 1284 signKey->setEnabled(!(itype & ITYPE_GROUP)); 1285 deleteKey->setEnabled(!(itype & ITYPE_GROUP)); 1286 setDefaultKey->setEnabled( (cnt == 1) ); 1287 m_popuppub->exec(globpos); 1288 } else if (!(itype & ~(ITYPE_UID | ITYPE_PAIR | ITYPE_UAT))) { 1289 setPrimUid->setEnabled(false); 1290 delUid->setEnabled(false); 1291 m_popupuid->exec(globpos); 1292 } else { 1293 m_popupout->exec(globpos); 1294 } 1295 } 1296 1297 void KeysManager::revokeWidget() 1298 { 1299 KGpgNode *nd = iview->selectedNode(); 1300 QDialog *keyRevokeDialog = new KGpgRevokeDialog(this, nd->toKeyNode()); 1301 1302 connect(keyRevokeDialog, &QDialog::finished, this, &KeysManager::slotRevokeDialogFinished); 1303 1304 keyRevokeDialog->open(); 1305 } 1306 1307 void KeysManager::slotRevokeDialogFinished(int result) 1308 { 1309 sender()->deleteLater(); 1310 1311 if (result != QDialog::Accepted) 1312 return; 1313 1314 KGpgRevokeDialog *keyRevokeDialog = qobject_cast<KGpgRevokeDialog *>(sender()); 1315 1316 KGpgGenerateRevoke *genRev = new KGpgGenerateRevoke(this, keyRevokeDialog->getId(), keyRevokeDialog->saveUrl(), 1317 keyRevokeDialog->getReason(), keyRevokeDialog->getDescription()); 1318 1319 connect(genRev, &KGpgGenerateRevoke::done, this, &KeysManager::slotRevokeGenerated); 1320 1321 if (keyRevokeDialog->printChecked()) 1322 connect(genRev, &KGpgGenerateRevoke::revokeCertificate, this, &KeysManager::doPrint); 1323 if (keyRevokeDialog->importChecked()) 1324 connect(genRev, &KGpgGenerateRevoke::revokeCertificate, this, &KeysManager::slotImportRevokeTxt); 1325 1326 genRev->start(); 1327 } 1328 1329 void KeysManager::slotRevokeGenerated(int result) 1330 { 1331 KGpgGenerateRevoke *genRev = qobject_cast<KGpgGenerateRevoke *>(sender()); 1332 1333 genRev->deleteLater(); 1334 1335 switch (result) { 1336 case KGpgTransaction::TS_OK: 1337 case KGpgTransaction::TS_USER_ABORTED: 1338 break; 1339 default: 1340 KMessageBox::detailedError(this, i18n("Creation of the revocation certificate failed..."), genRev->getOutput()); 1341 break; 1342 } 1343 } 1344 1345 void KeysManager::slotImportRevokeTxt(const QString &revokeText) 1346 { 1347 KGpgImport *import = new KGpgImport(this, revokeText); 1348 connect(import, &KGpgImport::done, this, &KeysManager::slotImportDone); 1349 import->start(); 1350 } 1351 1352 void KeysManager::slotexportsec() 1353 { 1354 // export secret key 1355 const QString warn(i18n("<qt>Secret keys <b>should not</b> be saved in an unsafe place.<br/>" 1356 "If someone else can access this file, encryption with this key will be compromised.<br/>Continue key export?</qt>")); 1357 int result = KMessageBox::warningContinueCancel(this, warn); 1358 if (result != KMessageBox::Continue) 1359 return; 1360 KGpgNode *nd = iview->selectedNode(); 1361 1362 QString sname(nd->getEmail().section(QLatin1Char( '@' ), 0, 0).section(QLatin1Char( '.' ), 0, 0)); 1363 if (sname.isEmpty()) 1364 sname = nd->getName().section(QLatin1Char( ' ' ), 0, 0); 1365 sname.append(QLatin1String( ".asc" )); 1366 sname.prepend(QDir::homePath() + QLatin1Char( '/' )); 1367 QUrl url(QFileDialog::getSaveFileUrl(this, i18n("Export PRIVATE KEY As"), QUrl(sname), i18n( "*.asc|*.asc Files" ))); 1368 1369 if(!url.isEmpty()) { 1370 KGpgExport *exp = new KGpgExport(this, QStringList(nd->getId()), url.path(), QStringList(QLatin1String( "--armor" )), true); 1371 1372 connect(exp, &KGpgExport::done, this, &KeysManager::slotExportSecFinished); 1373 1374 exp->start(); 1375 } 1376 } 1377 1378 void KeysManager::slotExportSecFinished(int result) 1379 { 1380 KGpgExport *exp = qobject_cast<KGpgExport *>(sender()); 1381 Q_ASSERT(exp != nullptr); 1382 1383 if (result == KGpgTransaction::TS_OK) { 1384 KMessageBox::information(this, 1385 i18n("<qt>Your <b>private</b> key \"%1\" was successfully exported to<br/>%2.<br/><b>Do not</b> leave it in an insecure place.</qt>", 1386 exp->getKeyIds().first(), exp->getOutputFile())); 1387 } else { 1388 KMessageBox::error(this, i18n("Your secret key could not be exported.\nCheck the key.")); 1389 } 1390 } 1391 1392 void KeysManager::slotexport() 1393 { 1394 bool same; 1395 KgpgItemType tp; 1396 1397 const auto ndlist = iview->selectedNodes(&same, &tp); 1398 if (ndlist.empty()) 1399 return; 1400 if (!(tp & ITYPE_PUBLIC) || (tp & ~ITYPE_GPAIR)) 1401 return; 1402 1403 QString sname; 1404 1405 if (ndlist.size() == 1) { 1406 sname = ndlist.at(0)->getEmail().section(QLatin1Char( '@' ), 0, 0).section(QLatin1Char( '.' ), 0, 0); 1407 if (sname.isEmpty()) 1408 sname = ndlist.at(0)->getName().section(QLatin1Char(' '), 0, 0); 1409 } else 1410 sname = QLatin1String( "keyring" ); 1411 1412 QStringList klist; 1413 for (const auto k : ndlist) 1414 klist << k->getId(); 1415 1416 sname.append(QLatin1String( ".asc" )); 1417 sname.prepend(QDir::homePath() + QLatin1Char( '/' )); 1418 1419 QStringList serverList(KGpgSettings::keyServers()); 1420 serverList.replaceInStrings(QRegularExpression(QStringLiteral(" .*")), QString()); // Remove kde 3.5 (Default) tag. 1421 if (!serverList.isEmpty()) { 1422 QString defaultServer = serverList.takeFirst(); 1423 std::sort(serverList.begin(), serverList.end()); 1424 serverList.prepend(defaultServer); 1425 } 1426 1427 QPointer<KeyExport> page = new KeyExport(this, serverList); 1428 1429 page->newFilename->setUrl(QUrl(sname)); 1430 1431 if (!m_online) 1432 page->checkServer->setEnabled(false); 1433 1434 if (page->exec() == QDialog::Accepted) { 1435 // export to file 1436 QString exportAttr; 1437 1438 if (page->checkAttrAll->isChecked()) { 1439 // nothing 1440 } else if (page->checkAttrPhoto->isChecked()) { 1441 exportAttr = QLatin1String( "no-export-attributes" ); 1442 } else { 1443 exportAttr = QLatin1String( "export-minimal" ); 1444 } 1445 QStringList expopts; 1446 1447 if (!exportAttr.isEmpty()) 1448 expopts << QLatin1String( "--export-options" ) << exportAttr; 1449 1450 if (page->checkServer->isChecked()) { 1451 KeyServer *expServer = new KeyServer(nullptr, imodel); 1452 expServer->slotSetExportAttribute(exportAttr); 1453 expServer->slotSetKeyserver(page->destServer->currentText()); 1454 1455 expServer->slotExport(klist); 1456 } else if (page->checkFile->isChecked()) { 1457 const QString expname(page->newFilename->url().path().simplified()); 1458 if (!expname.isEmpty()) { 1459 1460 expopts.append(QLatin1String( "--armor" )); 1461 1462 KGpgExport *exp = new KGpgExport(this, klist, expname, expopts); 1463 1464 connect(exp, &KGpgExport::done, this, &KeysManager::slotExportFinished); 1465 1466 exp->start(); 1467 } 1468 } else { 1469 KGpgExport *exp = new KGpgExport(this, klist, expopts); 1470 1471 if (page->checkClipboard->isChecked()) 1472 connect(exp, &KGpgExport::done, this, &KeysManager::slotProcessExportClip); 1473 else 1474 connect(exp, &KGpgExport::done, this, &KeysManager::slotProcessExportMail); 1475 1476 exp->start(); 1477 } 1478 } 1479 1480 delete page; 1481 } 1482 1483 void KeysManager::slotExportFinished(int result) 1484 { 1485 KGpgExport *exp = qobject_cast<KGpgExport *>(sender()); 1486 Q_ASSERT(exp != nullptr); 1487 1488 if (result == KGpgTransaction::TS_OK) { 1489 KMessageBox::information(this, 1490 i18np("<qt>The public key was successfully exported to<br/>%2</qt>", 1491 "<qt>The %1 public keys were successfully exported to<br/>%2</qt>", 1492 exp->getKeyIds().count(), exp->getOutputFile())); 1493 } else { 1494 KMessageBox::error(this, i18n("Your public key could not be exported\nCheck the key.")); 1495 } 1496 1497 exp->deleteLater(); 1498 } 1499 1500 void KeysManager::slotProcessExportMail(int result) 1501 { 1502 KGpgExport *exp = qobject_cast<KGpgExport *>(sender()); 1503 Q_ASSERT(exp != nullptr); 1504 1505 // start default Mail application 1506 if (result == KGpgTransaction::TS_OK) { 1507 QDesktopServices::openUrl(QUrl(QLatin1String("mailto:?body=") + QLatin1String(exp->getOutputData()))); 1508 } else { 1509 KMessageBox::error(this, i18n("Your public key could not be exported\nCheck the key.")); 1510 } 1511 1512 exp->deleteLater(); 1513 } 1514 1515 void KeysManager::slotProcessExportClip(int result) 1516 { 1517 KGpgExport *exp = qobject_cast<KGpgExport *>(sender()); 1518 Q_ASSERT(exp != nullptr); 1519 1520 if (result == KGpgTransaction::TS_OK) { 1521 qApp->clipboard()->setText(QLatin1String( exp->getOutputData() ), m_clipboardmode); 1522 } else { 1523 KMessageBox::error(this, i18n("Your public key could not be exported\nCheck the key.")); 1524 } 1525 1526 exp->deleteLater(); 1527 } 1528 1529 void KeysManager::showKeyInfo(const QString &keyID) 1530 { 1531 KGpgKeyNode *key = imodel->getRootNode()->findKey(keyID); 1532 1533 if (key == nullptr) 1534 return; 1535 1536 showProperties(key); 1537 } 1538 1539 void KeysManager::slotShowPhoto() 1540 { 1541 KGpgNode *nd = iview->selectedNode(); 1542 KGpgUatNode *und = nd->toUatNode(); 1543 KGpgKeyNode *parent = und->getParentKeyNode(); 1544 1545 KProcess p; 1546 p << KGpgSettings::gpgBinaryPath() 1547 << QLatin1String("--no-tty") 1548 << QLatin1String("--edit-key") 1549 << parent->getId() 1550 << QLatin1String("uid") 1551 << und->getId() 1552 << QLatin1String("showphoto") 1553 << QLatin1String("quit"); 1554 p.startDetached(); 1555 } 1556 1557 void KeysManager::defaultAction(const QModelIndex &index) 1558 { 1559 KGpgNode *nd = iproxy->nodeForIndex(index); 1560 1561 defaultAction(nd); 1562 } 1563 1564 void KeysManager::slotDefaultAction() 1565 { 1566 defaultAction(iview->selectedNode()); 1567 } 1568 1569 void KeysManager::defaultAction(KGpgNode *nd) 1570 { 1571 if (nd == nullptr) 1572 return; 1573 1574 if (iview->isEditing()) 1575 return; 1576 1577 switch (nd->getType()) { 1578 case ITYPE_GROUP: 1579 editGroup(); 1580 break; 1581 case ITYPE_UAT: 1582 slotShowPhoto(); 1583 break; 1584 case ITYPE_SIGN: 1585 case ITYPE_GPUBLIC: 1586 case ITYPE_GSECRET: 1587 case ITYPE_GPAIR: 1588 iview->selectNode(nd->toRefNode()->getRefNode()); 1589 break; 1590 case ITYPE_SECRET: 1591 slotregenerate(); 1592 break; 1593 case ITYPE_PAIR: 1594 case ITYPE_PUBLIC: 1595 showProperties(nd); 1596 return; 1597 } 1598 } 1599 1600 void 1601 KeysManager::showProperties(KGpgNode *n) 1602 { 1603 switch (n->getType()) { 1604 case ITYPE_UAT: 1605 return; 1606 case ITYPE_PUBLIC: 1607 case ITYPE_PAIR: { 1608 KGpgKeyNode *k = n->toKeyNode(); 1609 QPointer<KgpgKeyInfo> opts = new KgpgKeyInfo(k, imodel, this); 1610 connect(opts.data(), &KgpgKeyInfo::keyNeedsRefresh, imodel, QOverload<KGpgKeyNode *>::of(&KGpgItemModel::refreshKey)); 1611 connect(opts->keychange, &KGpgChangeKey::keyNeedsRefresh, imodel, QOverload<KGpgKeyNode *>::of(&KGpgItemModel::refreshKey)); 1612 opts->exec(); 1613 delete opts; 1614 } 1615 default: 1616 return; 1617 } 1618 } 1619 1620 void KeysManager::keyproperties() 1621 { 1622 KGpgNode *cur = iview->selectedNode(); 1623 if (cur == nullptr) 1624 return; 1625 1626 KGpgKeyNode *kn; 1627 1628 switch (cur->getType()) { 1629 case ITYPE_SECRET: 1630 case ITYPE_GSECRET: 1631 if (KMessageBox::questionTwoActions(this, 1632 i18n("<p>This key is an orphaned secret key (secret key without public key.) It is currently not usable.</p>" 1633 "<p>Would you like to regenerate the public key?</p>"), 1634 QString(), KGuiItem(i18n("Generate")), KGuiItem(i18n("Do Not Generate"))) == KMessageBox::PrimaryAction) 1635 slotregenerate(); 1636 return; 1637 case ITYPE_PAIR: 1638 case ITYPE_PUBLIC: { 1639 kn = cur->toKeyNode(); 1640 break; 1641 } 1642 case ITYPE_GPAIR: 1643 case ITYPE_GPUBLIC: { 1644 kn = cur->toGroupMemberNode()->getRefNode(); 1645 break; 1646 } 1647 default: 1648 qCDebug(KGPG_LOG_GENERAL) << "Oops, called with invalid item type" << cur->getType(); 1649 return; 1650 } 1651 1652 QPointer<KgpgKeyInfo> opts = new KgpgKeyInfo(kn, imodel, this); 1653 connect(opts.data(), &KgpgKeyInfo::keyNeedsRefresh, imodel, QOverload<KGpgKeyNode *>::of(&KGpgItemModel::refreshKey)); 1654 opts->exec(); 1655 delete opts; 1656 } 1657 1658 void KeysManager::deleteGroup() 1659 { 1660 KGpgNode *nd = iview->selectedNode(); 1661 if (!nd || (nd->getType() != ITYPE_GROUP)) 1662 return; 1663 1664 int result = KMessageBox::warningContinueCancel(this, i18n("<qt>Are you sure you want to delete group <b>%1</b> ?</qt>", 1665 nd->getName()), QString(), KGuiItem(i18n("Delete"), QLatin1String("edit-delete"))); 1666 if (result != KMessageBox::Continue) 1667 return; 1668 1669 nd->toGroupNode()->remove(); 1670 imodel->delNode(nd); 1671 1672 updateStatusCounter(); 1673 } 1674 1675 void KeysManager::renameGroup() 1676 { 1677 if (iview->selectionModel()->selectedIndexes().isEmpty()) 1678 return; 1679 1680 QModelIndex selectedNodeIndex = iview->selectionModel()->selectedIndexes().at(0); 1681 1682 iview->edit(selectedNodeIndex); 1683 } 1684 1685 void KeysManager::createNewGroup() 1686 { 1687 QStringList badkeys; 1688 KGpgKeyNode::List keysList; 1689 KgpgItemType tp; 1690 const auto ndlist = iview->selectedNodes(nullptr, &tp); 1691 1692 if (ndlist.empty()) 1693 return; 1694 if (tp & ~ITYPE_PAIR) { 1695 KMessageBox::error(this, i18n("<qt>You cannot create a group containing signatures, subkeys or other groups.</qt>")); 1696 return; 1697 } 1698 1699 KgpgKeyTrustFlag mintrust; 1700 if (KGpgSettings::allowUntrustedGroupMembers()) { 1701 mintrust = KgpgCore::TRUST_UNDEFINED; 1702 } else { 1703 mintrust = KgpgCore::TRUST_FULL; 1704 } 1705 1706 for (KGpgNode *nd : ndlist) { 1707 if (nd->getTrust() >= mintrust) { 1708 keysList.append(nd->toKeyNode()); 1709 } else { 1710 badkeys += i18nc("<Name> (<Email>) ID: <KeyId>", "%1 (%2) ID: %3", 1711 nd->getName(), nd->getEmail(), nd->getId()); 1712 } 1713 } 1714 1715 QString groupName(QInputDialog::getText(this, i18n("Create New Group"), 1716 i18nc("Enter the name of the group you are creating now", "Enter new group name:"))); 1717 if (groupName.isEmpty()) 1718 return; 1719 if (!keysList.isEmpty()) { 1720 if (!badkeys.isEmpty()) 1721 KMessageBox::informationList(this, i18n("Following keys are not valid or not trusted and will not be added to the group:"), badkeys); 1722 1723 iview->selectNode(imodel->addGroup(groupName, keysList)); 1724 updateStatusCounter(); 1725 } else { 1726 KMessageBox::error(this, 1727 i18n("<qt>No valid or trusted key was selected. The group <b>%1</b> will not be created.</qt>", 1728 groupName)); 1729 } 1730 } 1731 1732 void KeysManager::editGroup() 1733 { 1734 KGpgNode *nd = iview->selectedNode(); 1735 if (!nd || (nd->getType() != ITYPE_GROUP)) 1736 return; 1737 KGpgGroupNode *gnd = nd->toGroupNode(); 1738 QPointer<QDialog> dialogGroupEdit = new QDialog(this ); 1739 dialogGroupEdit->setWindowTitle(i18n("Group Properties")); 1740 QVBoxLayout *mainLayout = new QVBoxLayout(dialogGroupEdit); 1741 QWidget *mainWidget = new QWidget(this); 1742 mainLayout->addWidget(mainWidget); 1743 dialogGroupEdit->setLayout(mainLayout); 1744 1745 1746 QList<KGpgNode *> members(gnd->getChildren()); 1747 1748 groupEdit *gEdit = new groupEdit(dialogGroupEdit, &members, imodel); 1749 1750 mainLayout->addWidget(gEdit); 1751 gEdit->buttonBox->button(QDialogButtonBox::Ok)->setShortcut(Qt::CTRL | Qt::Key_Return); 1752 connect(gEdit->buttonBox, &QDialogButtonBox::accepted, dialogGroupEdit.data(), &QDialog::accept); 1753 connect(gEdit->buttonBox, &QDialogButtonBox::rejected, dialogGroupEdit.data(), &QDialog::reject); 1754 1755 gEdit->show(); 1756 1757 if (dialogGroupEdit->exec() == QDialog::Accepted) 1758 imodel->changeGroup(gnd, members); 1759 1760 delete dialogGroupEdit; 1761 } 1762 1763 void KeysManager::signkey() 1764 { 1765 // another sign operation is still running 1766 if (!signList.isEmpty()) 1767 return; 1768 1769 KgpgItemType tp; 1770 const auto tmplist = iview->selectedNodes(nullptr, &tp); 1771 if (tmplist.empty()) 1772 return; 1773 1774 if (tp & ~ITYPE_PAIR) { 1775 KMessageBox::error(this, i18n("You can only sign primary keys. Please check your selection.")); 1776 return; 1777 } 1778 1779 if (tmplist.size() == 1) { 1780 KGpgKeyNode *nd = tmplist.at(0)->toKeyNode(); 1781 QString opt; 1782 1783 if (nd->getEmail().isEmpty()) 1784 opt = i18n("<qt>You are about to sign key:<br /><br />%1<br />ID: %2<br />Fingerprint: <br /><b>%3</b>.<br /><br />" 1785 "You should check the key fingerprint by phoning or meeting the key owner to be sure that someone " 1786 "is not trying to intercept your communications.</qt>", 1787 nd->getName(), nd->getId().right(8), nd->getBeautifiedFingerprint()); 1788 else 1789 opt = i18n("<qt>You are about to sign key:<br /><br />%1 (%2)<br />ID: %3<br />Fingerprint: <br /><b>%4</b>.<br /><br />" 1790 "You should check the key fingerprint by phoning or meeting the key owner to be sure that someone " 1791 "is not trying to intercept your communications.</qt>", 1792 nd->getName(), nd->getEmail(), nd->getId().right(8), nd->getBeautifiedFingerprint()); 1793 1794 if (KMessageBox::warningContinueCancel(this, opt) != KMessageBox::Continue) { 1795 return; 1796 } 1797 signList.append(nd); 1798 } else { 1799 QStringList signKeyList; 1800 for (KGpgNode *n : tmplist) { 1801 const KGpgKeyNode *nd = n->toKeyNode(); 1802 1803 if (nd->getEmail().isEmpty()) 1804 signKeyList += i18nc("Name: ID", "%1: %2", nd->getName(), nd->getBeautifiedFingerprint()); 1805 else 1806 signKeyList += i18nc("Name (Email): ID", "%1 (%2): %3", nd->getName(), nd->getEmail(), nd->getBeautifiedFingerprint()); 1807 1808 signList.append(n->toSignableNode()); 1809 } 1810 1811 if (KMessageBox::Continue != KMessageBox::warningContinueCancelList(this, 1812 i18n("<qt>You are about to sign the following keys in one pass.<br/><b>If you have not carefully checked all fingerprints," 1813 " the security of your communications may be compromised.</b></qt>"), 1814 signKeyList)) 1815 return; 1816 } 1817 1818 QPointer<KgpgSelectSecretKey> opts = new KgpgSelectSecretKey(this, imodel, signList.count()); 1819 if (opts->exec() != QDialog::Accepted) { 1820 delete opts; 1821 signList.clear(); 1822 return; 1823 } 1824 1825 globalkeyID = QString(opts->getKeyID()); 1826 const bool localsign = opts->isLocalSign(); 1827 const int checklevel = opts->getSignTrust(); 1828 bool isterminal = opts->isTerminalSign(); 1829 delete opts; 1830 1831 if (isterminal) { 1832 const QString keyid(signList.at(0)->getId()); 1833 signList.clear(); 1834 signKeyOpenConsole(globalkeyID, keyid, checklevel, localsign); 1835 } else { 1836 keyCount = 0; 1837 m_signuids = false; 1838 signLoop(localsign, checklevel); 1839 } 1840 } 1841 1842 void KeysManager::signuid() 1843 { 1844 // another sign operation is still running 1845 if (!signList.isEmpty()) 1846 return; 1847 1848 KgpgItemType tp; 1849 const auto tmplist = iview->selectedNodes(nullptr, &tp); 1850 if (tmplist.empty()) 1851 return; 1852 1853 if (tp & ~(ITYPE_PAIR | ITYPE_UID | ITYPE_UAT)) { 1854 KMessageBox::error(this, i18n("You can only sign user ids and photo ids. Please check your selection.")); 1855 return; 1856 } 1857 1858 if (tmplist.size() == 1) { 1859 KGpgSignableNode *nd = tmplist.at(0)->toSignableNode(); 1860 KGpgKeyNode *pnd; 1861 if (tp & ITYPE_PUBLIC) 1862 pnd = nd->toKeyNode(); 1863 else 1864 pnd = nd->getParentKeyNode()->toKeyNode(); 1865 QString opt; 1866 1867 if (nd->getEmail().isEmpty()) 1868 opt = i18n("<qt>You are about to sign user id:<br /><br />%1<br />ID: %2<br />Fingerprint: <br /><b>%3</b>.<br /><br />" 1869 "You should check the key fingerprint by phoning or meeting the key owner to be sure that someone " 1870 "is not trying to intercept your communications.</qt>", nd->getName(), nd->getId(), pnd->getBeautifiedFingerprint()); 1871 else 1872 opt = i18n("<qt>You are about to sign user id:<br /><br />%1 (%2)<br />ID: %3<br />Fingerprint: <br /><b>%4</b>.<br /><br />" 1873 "You should check the key fingerprint by phoning or meeting the key owner to be sure that someone " 1874 "is not trying to intercept your communications.</qt>", nd->getName(), nd->getEmail(), nd->getId(), pnd->getBeautifiedFingerprint()); 1875 1876 if (KMessageBox::warningContinueCancel(this, opt) != KMessageBox::Continue) { 1877 return; 1878 } 1879 signList.append(nd); 1880 } else { 1881 QStringList signKeyList; 1882 1883 for (KGpgNode *nd : tmplist) { 1884 const KGpgKeyNode *pnd = (nd->getType() & (ITYPE_UID | ITYPE_UAT)) ? 1885 nd->getParentKeyNode()->toKeyNode() : nd->toKeyNode(); 1886 1887 if (nd->getEmail().isEmpty()) 1888 signKeyList += i18nc("Name: ID", "%1: %2", 1889 nd->getName(), pnd->getBeautifiedFingerprint()); 1890 else 1891 signKeyList += i18nc("Name (Email): ID", "%1 (%2): %3", 1892 nd->getName(), nd->getEmail(), pnd->getBeautifiedFingerprint()); 1893 1894 signList.append(nd->toSignableNode()); 1895 } 1896 1897 if (KMessageBox::warningContinueCancelList(this, 1898 i18n("<qt>You are about to sign the following user ids in one pass.<br/><b>If you have not carefully checked all fingerprints," 1899 " the security of your communications may be compromised.</b></qt>"), 1900 signKeyList) != KMessageBox::Continue) 1901 return; 1902 } 1903 1904 QPointer<KgpgSelectSecretKey> opts = new KgpgSelectSecretKey(this, imodel, signList.count()); 1905 if (opts->exec() != QDialog::Accepted) { 1906 delete opts; 1907 signList.clear(); 1908 return; 1909 } 1910 1911 globalkeyID = QString(opts->getKeyID()); 1912 const bool localsign = opts->isLocalSign(); 1913 const int checklevel = opts->getSignTrust(); 1914 bool isterminal = opts->isTerminalSign(); 1915 delete opts; 1916 1917 if (isterminal) { 1918 const QString keyid(signList.at(0)->getId()); 1919 signList.clear(); 1920 signKeyOpenConsole(globalkeyID, keyid, checklevel, localsign); 1921 } else { 1922 keyCount = 0; 1923 m_signuids = true; 1924 signLoop(localsign, checklevel); 1925 } 1926 } 1927 1928 void KeysManager::signLoop(const bool localsign, const int checklevel) 1929 { 1930 Q_ASSERT(keyCount < signList.count()); 1931 1932 KGpgSignableNode *nd = signList.at(keyCount); 1933 const KGpgSignTransactionHelper::carefulCheck cc = static_cast<KGpgSignTransactionHelper::carefulCheck>(checklevel); 1934 KGpgTransaction *sta; 1935 1936 if (m_signuids) { 1937 sta = new KGpgSignUid(this, globalkeyID, nd, localsign, cc); 1938 } else { 1939 sta = new KGpgSignKey(this, globalkeyID, nd->toKeyNode(), localsign, cc); 1940 } 1941 1942 connect(sta, &KGpgTransaction::done, this, &KeysManager::signatureResult); 1943 sta->start(); 1944 } 1945 1946 void KeysManager::signatureResult(int success) 1947 { 1948 KGpgSignTransactionHelper *ta; 1949 KGpgSignUid *suid = qobject_cast<KGpgSignUid *>(sender()); 1950 if (suid != nullptr) { 1951 ta = static_cast<KGpgSignTransactionHelper *>(suid); 1952 } else { 1953 ta = static_cast<KGpgSignTransactionHelper *>(static_cast<KGpgSignKey *>(sender())); 1954 } 1955 KGpgKeyNode *nd = const_cast<KGpgKeyNode *>(ta->getKey()); 1956 const bool localsign = ta->getLocal(); 1957 const int checklevel = ta->getChecking(); 1958 const QString signer(ta->getSigner()); 1959 sender()->deleteLater(); 1960 1961 switch (success) { 1962 case KGpgTransaction::TS_OK: 1963 if (refreshList.indexOf(nd) == -1) 1964 refreshList.append(nd); 1965 break; 1966 case KGpgTransaction::TS_BAD_PASSPHRASE: 1967 KMessageBox::error(this, i18n("<qt>Bad passphrase, key <b>%1 (%2)</b> not signed.</qt>", 1968 nd->getName(), nd->getEmail())); 1969 break; 1970 case KGpgSignTransactionHelper::TS_ALREADY_SIGNED: 1971 KMessageBox::error(this, i18n("<qt>The key <b>%1 (%2)</b> is already signed.</qt>", 1972 nd->getName(), nd->getEmail())); 1973 break; 1974 default: 1975 if (KMessageBox::questionTwoActions(this, 1976 i18n("<qt>Signing key <b>%1</b> with key <b>%2</b> failed.<br />" 1977 "Do you want to try signing the key in console mode?</qt>", 1978 nd->getId(), signer), QString{}, KGuiItem(i18nc("@action:button", "Sign")), KStandardGuiItem::cancel()) == KMessageBox::PrimaryAction) 1979 signKeyOpenConsole(signer, nd->getId(), checklevel, localsign); 1980 } 1981 1982 if (++keyCount == signList.count()) { 1983 signList.clear(); 1984 if (!refreshList.isEmpty()) 1985 imodel->refreshKeys(refreshList); 1986 refreshList.clear(); 1987 } else { 1988 signLoop(localsign, checklevel); 1989 } 1990 } 1991 1992 void KeysManager::caff() 1993 { 1994 KgpgItemType tp; 1995 const auto tmplist = iview->selectedNodes(nullptr, &tp); 1996 KGpgSignableNode::List slist; 1997 if (tmplist.empty()) 1998 return; 1999 2000 if (tp & ~(ITYPE_PAIR | ITYPE_UID | ITYPE_UAT)) { 2001 KMessageBox::error(this, i18n("You can only sign user ids and photo ids. Please check your selection.")); 2002 return; 2003 } 2004 2005 for (KGpgNode *nd : tmplist) { 2006 switch (nd->getType()) { 2007 case KgpgCore::ITYPE_PAIR: 2008 case KgpgCore::ITYPE_PUBLIC: { 2009 KGpgKeyNode *knd = qobject_cast<KGpgKeyNode *>(nd); 2010 if (!knd->wasExpanded()) 2011 knd->getChildCount(); 2012 } 2013 } 2014 slist.append(nd->toSignableNode()); 2015 } 2016 2017 QPointer<KgpgSelectSecretKey> opts = new KgpgSelectSecretKey(this, imodel, slist.count(), false, false); 2018 if (opts->exec() != QDialog::Accepted) { 2019 delete opts; 2020 return; 2021 } 2022 2023 KGpgCaff *ca = new KGpgCaff(this, slist, QStringList(opts->getKeyID()), opts->getSignTrust(), KGpgCaff::IgnoreAlreadySigned); 2024 delete opts; 2025 2026 connect(ca, &KGpgCaff::done, this, &KeysManager::slotCaffDone); 2027 connect(ca, &KGpgCaff::aborted, this, &KeysManager::slotCaffDone); 2028 2029 ca->run(); 2030 } 2031 2032 void KeysManager::slotCaffDone() 2033 { 2034 Q_ASSERT(qobject_cast<KGpgCaff *>(sender()) != nullptr); 2035 2036 sender()->deleteLater(); 2037 } 2038 2039 void KeysManager::signKeyOpenConsole(const QString &signer, const QString &keyid, const int checking, const bool local) 2040 { 2041 KConfigGroup config(KSharedConfig::openConfig(), u"General"_s); 2042 2043 KProcess process; 2044 process << config.readPathEntry("TerminalApplication", QLatin1String("konsole")) 2045 << QLatin1String("-e") 2046 << KGpgSettings::gpgBinaryPath() 2047 << QLatin1String("--no-secmem-warning") 2048 << QLatin1String("-u") << signer 2049 << QLatin1String("--default-cert-level") 2050 << QString::number(checking); 2051 2052 if (!local) 2053 process << QLatin1String( "--sign-key" ) << keyid; 2054 else 2055 process << QLatin1String( "--lsign-key" ) << keyid; 2056 2057 process.execute(); 2058 } 2059 2060 void KeysManager::getMissingSigs(QSet<QString> &missingKeys, const KGpgExpandableNode *nd) 2061 { 2062 for (const KGpgNode *ch : nd->getChildren()) { 2063 if (ch->hasChildren()) { 2064 getMissingSigs(missingKeys, ch->toExpandableNode()); 2065 continue; 2066 } else if (ch->getType() == ITYPE_SIGN) { 2067 if (ch->toSignNode()->isUnknown()) 2068 missingKeys << ch->getId(); 2069 } 2070 } 2071 } 2072 2073 void KeysManager::importallsignkey() 2074 { 2075 const auto sel = iview->selectedNodes(); 2076 QSet<QString> missingKeys; 2077 2078 if (sel.empty()) 2079 return; 2080 2081 for (const KGpgNode *nd : sel) { 2082 if (nd->hasChildren()) { 2083 getMissingSigs(missingKeys, nd->toExpandableNode()); 2084 } else if (nd->getType() == ITYPE_SIGN) { 2085 const KGpgSignNode *sn = nd->toSignNode(); 2086 2087 if (sn->isUnknown()) 2088 missingKeys << sn->getId(); 2089 } 2090 } 2091 2092 if (missingKeys.isEmpty()) { 2093 KMessageBox::information(this, 2094 i18np("All signatures for this key are already in your keyring", 2095 "All signatures for this keys are already in your keyring", sel.size())); 2096 return; 2097 } 2098 2099 importRemoteKeys(missingKeys.values()); 2100 } 2101 2102 void KeysManager::preimportsignkey() 2103 { 2104 const auto exportList = iview->selectedNodes(); 2105 QStringList idlist; 2106 2107 if (exportList.empty()) 2108 return; 2109 2110 for (const KGpgNode *nd : exportList) 2111 idlist << nd->getId(); 2112 2113 importRemoteKeys(idlist); 2114 } 2115 2116 bool KeysManager::importRemoteKey(const QString &keyIDs) 2117 { 2118 return importRemoteKeys(keyIDs.simplified().split(QLatin1Char( ' ' )), false); 2119 } 2120 2121 bool KeysManager::importRemoteKeys(const QStringList &keyIDs, const bool dialog) 2122 { 2123 const QStringList kservers = KeyServer::getServerList(); 2124 if (kservers.isEmpty()) 2125 return false; 2126 2127 KGpgReceiveKeys *proc = new KGpgReceiveKeys(this, kservers.first(), keyIDs, dialog, QLatin1String( qgetenv("http_proxy") )); 2128 connect(proc, &KGpgReceiveKeys::done, this, &KeysManager::importRemoteFinished); 2129 2130 proc->start(); 2131 2132 return true; 2133 } 2134 2135 void KeysManager::importRemoteFinished(int result) 2136 { 2137 KGpgReceiveKeys *t = qobject_cast<KGpgReceiveKeys *>(sender()); 2138 Q_ASSERT(t != nullptr); 2139 2140 const QStringList keys = KGpgImport::getImportedIds(t->getLog()); 2141 2142 t->deleteLater(); 2143 2144 if ((result == KGpgTransaction::TS_OK) && !keys.isEmpty()) 2145 imodel->refreshKeys(keys); 2146 } 2147 2148 void KeysManager::delsignkey() 2149 { 2150 KGpgNode *nd = iview->selectedNode(); 2151 if (nd == nullptr) 2152 return; 2153 2154 QString parentKey; 2155 2156 KGpgExpandableNode *parent = nd->getParentKeyNode(); 2157 switch (parent->getType()) { 2158 case ITYPE_PAIR: 2159 case ITYPE_PUBLIC: 2160 parentKey = parent->getId(); 2161 break; 2162 case ITYPE_UID: 2163 case ITYPE_UAT: 2164 parentKey = parent->getParentKeyNode()->getId(); 2165 break; 2166 default: 2167 Q_ASSERT(0); 2168 return; 2169 } 2170 2171 const QString signID(nd->getId()); 2172 QString signMail(nd->getNameComment()); 2173 QString parentMail(parent->getNameComment()); 2174 2175 if (!parent->getEmail().isEmpty()) 2176 parentMail += QLatin1String( " <" ) + parent->getEmail() + QLatin1String( ">" ); 2177 if (!nd->getEmail().isEmpty()) 2178 signMail += QLatin1String( " <" ) + nd->getEmail() + QLatin1String( ">" ); 2179 2180 if (parentKey == signID) { 2181 KMessageBox::error(this, i18n("Edit key manually to delete a self-signature.")); 2182 return; 2183 } 2184 2185 QString ask = i18n("<qt>Are you sure you want to delete signature<br /><b>%1</b><br />from user id <b>%2</b><br />of key: <b>%3</b>?</qt>", 2186 signMail, parentMail, parentKey); 2187 2188 if (KMessageBox::questionTwoActions(this, ask, QString(), KStandardGuiItem::del(), KStandardGuiItem::cancel()) != KMessageBox::PrimaryAction) 2189 return; 2190 2191 KGpgDelSign *delsig = new KGpgDelSign(this, nd->toSignNode()); 2192 connect(delsig, &KGpgDelSign::done, this, &KeysManager::delsignatureResult); 2193 delsig->start(); 2194 } 2195 2196 void KeysManager::delsignatureResult(int success) 2197 { 2198 sender()->deleteLater(); 2199 2200 if (success == KGpgTransaction::TS_OK) { 2201 KGpgNode *nd = iview->selectedNode()->getParentKeyNode(); 2202 2203 while (!(nd->getType() & ITYPE_PAIR)) 2204 nd = nd->getParentKeyNode(); 2205 imodel->refreshKey(nd->toKeyNode()); 2206 } else { 2207 KMessageBox::error(this, i18n("Requested operation was unsuccessful, please edit the key manually.")); 2208 } 2209 } 2210 2211 void KeysManager::slotSendEmail() 2212 { 2213 QStringList maillist; 2214 2215 const auto nodes = iview->selectedNodes(); 2216 for (const KGpgNode *nd : nodes) { 2217 if (nd->getEmail().isEmpty()) 2218 continue; 2219 2220 maillist << QLatin1Char('"') + nd->getName() + QLatin1String("\" <") + nd->getEmail() + QLatin1Char('>'); 2221 } 2222 2223 if (maillist.isEmpty()) 2224 return; 2225 2226 QDesktopServices::openUrl(QUrl(QLatin1String("mailto:") + maillist.join(QLatin1String(", ")))); 2227 } 2228 2229 void KeysManager::slotedit() 2230 { 2231 KGpgNode *nd = iview->selectedNode(); 2232 Q_ASSERT(nd != nullptr); 2233 2234 if (!(nd->getType() & ITYPE_PAIR)) 2235 return; 2236 if (terminalkey) 2237 return; 2238 if ((m_delkey != nullptr) && m_delkey->keys.contains(nd->toKeyNode())) 2239 return; 2240 2241 KProcess *kp = new KProcess(this); 2242 KConfigGroup config(KSharedConfig::openConfig(), u"General"_s); 2243 *kp << config.readPathEntry("TerminalApplication", QLatin1String("konsole")) 2244 << QLatin1String("-e") 2245 << KGpgSettings::gpgBinaryPath() 2246 << QLatin1String("--no-secmem-warning") 2247 << QLatin1String("--edit-key") 2248 << nd->getId() 2249 << QLatin1String("help"); 2250 terminalkey = nd->toKeyNode(); 2251 editKey->setEnabled(false); 2252 2253 connect(kp, &KProcess::finished, this, &KeysManager::slotEditDone); 2254 kp->start(); 2255 } 2256 2257 void KeysManager::slotEditDone(int exitcode) 2258 { 2259 if (exitcode == 0) 2260 imodel->refreshKey(terminalkey); 2261 2262 terminalkey = nullptr; 2263 editKey->setEnabled(true); 2264 } 2265 2266 void KeysManager::doPrint(const QString &txt) 2267 { 2268 QPrinter prt; 2269 //qCDebug(KGPG_LOG_GENERAL) << "Printing..." ; 2270 QPointer<QPrintDialog> printDialog = new QPrintDialog(&prt, this); 2271 if (printDialog->exec() == QDialog::Accepted) { 2272 QPainter painter(&prt); 2273 int width = painter.device()->width(); 2274 int height = painter.device()->height(); 2275 painter.drawText(0, 0, width, height, Qt::AlignLeft|Qt::AlignTop|Qt::TextDontClip, txt); 2276 } 2277 delete printDialog; 2278 } 2279 2280 void KeysManager::removeFromGroups(KGpgKeyNode *node) 2281 { 2282 QStringList groupNames; 2283 2284 const auto groups = node->getGroups(); 2285 for (const KGpgGroupNode *gnd : groups) 2286 groupNames << gnd->getName(); 2287 2288 if (groupNames.isEmpty()) 2289 return; 2290 2291 const QString ask = i18np("<qt>The key you are deleting is a member of the following key group. Do you want to remove it from this group?</qt>", 2292 "<qt>The key you are deleting is a member of the following key groups. Do you want to remove it from these groups?</qt>", 2293 groupNames.count()); 2294 2295 if (KMessageBox::questionTwoActionsList(this, ask, groupNames, i18n("Delete key"), KStandardGuiItem::remove(), KStandardGuiItem::cancel()) != KMessageBox::PrimaryAction) 2296 return; 2297 2298 bool groupDeleted = false; 2299 2300 const auto grefs = node->getGroupRefs(); 2301 for (KGpgGroupMemberNode *gref : grefs) { 2302 KGpgGroupNode *group = gref->getParentKeyNode(); 2303 2304 bool deleteWholeGroup = (group->getChildCount() == 1) && 2305 (group->getChild(0)->toGroupMemberNode() == gref); 2306 if (deleteWholeGroup) 2307 deleteWholeGroup = (KMessageBox::questionTwoActions(this, 2308 i18n("You are removing the last key from key group %1.<br/>Do you want to delete the group, too?", group->getName()), 2309 i18n("Delete key"), KStandardGuiItem::remove(), KStandardGuiItem::cancel()) == KMessageBox::PrimaryAction); 2310 2311 if (!deleteWholeGroup) { 2312 imodel->deleteFromGroup(group, gref); 2313 } else { 2314 group->remove(); 2315 imodel->delNode(group); 2316 groupDeleted = true; 2317 } 2318 } 2319 2320 if (groupDeleted) { 2321 updateStatusCounter(); 2322 } 2323 } 2324 2325 void KeysManager::deleteseckey() 2326 { 2327 KGpgKeyNode *nd = iview->selectedNode()->toKeyNode(); 2328 Q_ASSERT(nd != nullptr); 2329 2330 // delete a key 2331 int result = KMessageBox::warningContinueCancel(this, 2332 i18n("<p>Delete <b>secret</b> key pair <b>%1</b>?</p>Deleting this key pair means you will never be able to decrypt files encrypted with this key again.", 2333 nd->getNameComment()), 2334 QString(), 2335 KGuiItem(i18n("Delete"), QLatin1String( "edit-delete" ))); 2336 if (result != KMessageBox::Continue) 2337 return; 2338 2339 if (terminalkey == nd) 2340 return; 2341 if (m_delkey != nullptr) { 2342 KMessageBox::error(this, 2343 i18n("Another key delete operation is still in progress.\nPlease wait a moment until this operation is complete."), 2344 i18n("Delete key")); 2345 return; 2346 } 2347 2348 removeFromGroups(nd); 2349 2350 m_delkey = new KGpgDelKey(this, nd); 2351 connect(m_delkey, &KGpgDelKey::done, this, &KeysManager::secretKeyDeleted); 2352 m_delkey->start(); 2353 } 2354 2355 void KeysManager::secretKeyDeleted(int retcode) 2356 { 2357 KGpgKeyNode *delkey = m_delkey->keys.at(0); 2358 if (retcode == 0) { 2359 KMessageBox::information(this, i18n("Key <b>%1</b> deleted.", delkey->getBeautifiedFingerprint()), i18n("Delete key")); 2360 imodel->delNode(delkey); 2361 } else { 2362 KMessageBox::error(this, i18n("Deleting key <b>%1</b> failed.", delkey->getBeautifiedFingerprint()), i18n("Delete key")); 2363 } 2364 m_delkey->deleteLater(); 2365 m_delkey = nullptr; 2366 } 2367 2368 void KeysManager::confirmdeletekey() 2369 { 2370 if (m_delkey) { 2371 KMessageBox::error(this, 2372 i18n("Another key delete operation is still in progress.\nPlease wait a moment until this operation is complete."), 2373 i18n("Delete key")); 2374 return; 2375 } 2376 2377 KgpgCore::KgpgItemType pt; 2378 bool same; 2379 const auto ndlist = iview->selectedNodes(&same, &pt); 2380 if (ndlist.empty()) 2381 return; 2382 2383 // do not delete a key currently edited in terminal 2384 if ((!(pt & ~ITYPE_PAIR)) && (ndlist.at(0) == terminalkey) && (ndlist.size() == 1)) { 2385 KMessageBox::error(this, 2386 i18n("Can not delete key <b>%1</b> while it is edited in terminal.", 2387 terminalkey->getBeautifiedFingerprint()), i18n("Delete key")); 2388 return; 2389 } else if (pt == ITYPE_GROUP) { 2390 deleteGroup(); 2391 return; 2392 } else if (!(pt & ITYPE_GROUP) && (pt & ITYPE_SECRET) && (ndlist.size() == 1)) { 2393 deleteseckey(); 2394 return; 2395 } else if ((pt == ITYPE_UID) && (ndlist.size() == 1)) { 2396 slotDelUid(); 2397 return; 2398 } else if ((pt & ITYPE_GROUP) && !(pt & ~ITYPE_GPAIR)) { 2399 bool invalidDelete = std::any_of(ndlist.cbegin(), ndlist.cend(), 2400 [](const KGpgNode *nd) { return nd->getType() == ITYPE_GROUP; }); 2401 2402 // only allow removing group members if they belong to the same group 2403 if (!invalidDelete) { 2404 const KGpgNode * const group = ndlist.front()->getParentKeyNode(); 2405 invalidDelete = std::any_of(ndlist.cbegin(), ndlist.cend(), 2406 [group] (const KGpgNode *nd) { return nd->getParentKeyNode() != group; }); 2407 } 2408 2409 if (!invalidDelete) { 2410 KGpgGroupNode *gnd = ndlist.front()->getParentKeyNode()->toGroupNode(); 2411 2412 QList<KGpgNode *> members = gnd->getChildren(); 2413 2414 for (KGpgNode *nd : ndlist) { 2415 int r = members.removeAll(nd); 2416 Q_ASSERT(r == 1); 2417 Q_UNUSED(r); 2418 } 2419 2420 imodel->changeGroup(gnd, members); 2421 return; 2422 } 2423 } 2424 2425 if (pt & ~ITYPE_PAIR) { 2426 KMessageBox::error(this, 2427 i18n("You have selected items that are not keys. They can not be deleted with this menu entry."), 2428 i18n("Delete key")); 2429 return; 2430 } 2431 2432 QStringList keysToDelete; 2433 QStringList deleteIds; 2434 QStringList secList; 2435 KGpgKeyNode::List delkeys; 2436 2437 bool secretKeyInside = (pt & ITYPE_SECRET); 2438 for (KGpgNode *nd : ndlist) { 2439 KGpgKeyNode *ki = nd->toKeyNode(); 2440 2441 if (ki->getType() & ITYPE_SECRET) { 2442 secList += ki->getNameComment(); 2443 } else if (ki != terminalkey) { 2444 keysToDelete += ki->getNameComment(); 2445 deleteIds << ki->getId(); 2446 delkeys << ki; 2447 } 2448 } 2449 2450 if (secretKeyInside) { 2451 int result = KMessageBox::warningContinueCancel(this, 2452 i18n("<qt>The following are secret key pairs:<br/><b>%1</b><br/>They will not be deleted.</qt>", 2453 secList.join( QLatin1String( "<br />" )))); 2454 if (result != KMessageBox::Continue) 2455 return; 2456 } 2457 2458 if (keysToDelete.isEmpty()) 2459 return; 2460 2461 int result = KMessageBox::warningContinueCancelList(this, 2462 i18np("<qt><b>Delete the following public key?</b></qt>", 2463 "<qt><b>Delete the following %1 public keys?</b></qt>", 2464 keysToDelete.count()), keysToDelete, QString(), 2465 KStandardGuiItem::del()); 2466 if (result != KMessageBox::Continue) 2467 return; 2468 2469 for (KGpgNode *nd : ndlist) 2470 removeFromGroups(nd->toKeyNode()); 2471 2472 m_delkey = new KGpgDelKey(this, delkeys); 2473 connect(m_delkey, &KGpgDelKey::done, this, &KeysManager::slotDelKeyDone); 2474 m_delkey->start(); 2475 } 2476 2477 void KeysManager::slotDelKeyDone(int res) 2478 { 2479 if (res == 0) { 2480 for (KGpgKeyNode *kn : m_delkey->keys) 2481 imodel->delNode(kn); 2482 } 2483 2484 m_delkey->deleteLater(); 2485 m_delkey = nullptr; 2486 2487 updateStatusCounter(); 2488 } 2489 2490 void KeysManager::slotPreImportKey() 2491 { 2492 QPointer<QDialog> dial = new QDialog(this); 2493 dial->setWindowTitle(i18n("Key Import")); 2494 QVBoxLayout *mainLayout = new QVBoxLayout(dial); 2495 QWidget *mainWidget = new QWidget(this); 2496 mainLayout->addWidget(mainWidget); 2497 dial->setLayout(mainLayout); 2498 2499 SrcSelect *page = new SrcSelect(); 2500 mainLayout->addWidget(page); 2501 page->newFilename->setWindowTitle(i18n("Open File")); 2502 page->newFilename->setMode(KFile::File); 2503 2504 page->buttonBox->button(QDialogButtonBox::Ok)->setShortcut(Qt::CTRL | Qt::Key_Return); 2505 connect(page->buttonBox, &QDialogButtonBox::accepted, dial.data(), &QDialog::accept); 2506 connect(page->buttonBox, &QDialogButtonBox::rejected, dial.data(), &QDialog::reject); 2507 2508 if (dial->exec() == QDialog::Accepted) { 2509 if (page->checkFile->isChecked()) { 2510 QUrl impname = page->newFilename->url(); 2511 if (!impname.isEmpty()) 2512 slotImport(QList<QUrl>({impname})); 2513 } else if (page->checkServer->isChecked()) { 2514 const QString ids(page->keyIds->text().simplified()); 2515 if (!ids.isEmpty()) 2516 importRemoteKeys(ids.split(QLatin1Char( ' ' ))); 2517 } else { 2518 slotImport(qApp->clipboard()->text(m_clipboardmode)); 2519 } 2520 } 2521 2522 delete dial; 2523 } 2524 2525 void KeysManager::slotImport(const QString &text) 2526 { 2527 if (text.isEmpty()) 2528 return; 2529 2530 KGpgImport *imp; 2531 2532 if (!KGpgImport::isKey(text) && KGpgDecrypt::isEncryptedText(text)) { 2533 if (KMessageBox::questionTwoActions(this, 2534 i18n("<qt>The text in the clipboard does not look like a key, but like encrypted text.<br />Do you want to decrypt it first" 2535 " and then try importing it?</qt>"), 2536 i18n("Import from Clipboard"), KStandardGuiItem::ok(), KStandardGuiItem::cancel()) != KMessageBox::PrimaryAction) 2537 return; 2538 2539 imp = new KGpgImport(this); 2540 KGpgDecrypt *decr = new KGpgDecrypt(this, text); 2541 imp->setInputTransaction(decr); 2542 } else { 2543 imp = new KGpgImport(this, text); 2544 } 2545 2546 startImport(imp); 2547 } 2548 2549 void KeysManager::slotImport(const QList<QUrl> &files) 2550 { 2551 startImport(new KGpgImport(this, files)); 2552 } 2553 2554 void KeysManager::startImport(KGpgImport *import) 2555 { 2556 changeMessage(i18n("Importing..."), true); 2557 connect(import, &KGpgImport::done, this, &KeysManager::slotImportDone); 2558 import->start(); 2559 } 2560 2561 void KeysManager::slotImportDone(int result) 2562 { 2563 KGpgImport *import = qobject_cast<KGpgImport *>(sender()); 2564 Q_ASSERT(import != nullptr); 2565 const QStringList rawmsgs(import->getMessages()); 2566 2567 if (result != 0) { 2568 KMessageBox::detailedError(this, i18n("Key importing failed. Please see the detailed log for more information."), 2569 rawmsgs.join(QLatin1String("\n")) , i18n("Key Import")); 2570 } 2571 2572 QStringList keys(import->getImportedIds(0x1f)); 2573 const bool needsRefresh = !keys.isEmpty(); 2574 keys << import->getImportedIds(0); 2575 2576 if (!keys.isEmpty()) { 2577 const QString msg(import->getImportMessage()); 2578 const QStringList keynames(import->getImportedKeys()); 2579 2580 new KgpgDetailedInfo(this, msg, rawmsgs.join(QLatin1String("\n")), keynames, i18n("Key Import")); 2581 if (needsRefresh) 2582 imodel->refreshKeys(keys); 2583 else 2584 changeMessage(i18nc("Application ready for user input", "Ready")); 2585 } else{ 2586 changeMessage(i18nc("Application ready for user input", "Ready")); 2587 } 2588 2589 import->deleteLater(); 2590 } 2591 2592 void KeysManager::refreshkey() 2593 { 2594 imodel->refreshAllKeys(); 2595 updateStatusCounter(); 2596 } 2597 2598 KGpgItemModel *KeysManager::getModel() 2599 { 2600 return imodel; 2601 } 2602 2603 void 2604 KeysManager::toggleNetworkActions(bool online) 2605 { 2606 m_online = online; 2607 kserver->setEnabled(online); 2608 importSignatureKey->setEnabled(online); 2609 importAllSignKeys->setEnabled(online); 2610 refreshKey->setEnabled(online); 2611 } 2612 2613 void 2614 KeysManager::setupTrayIcon() 2615 { 2616 bool newtray = (m_trayicon == nullptr); 2617 2618 if (newtray) { 2619 m_trayicon = new KStatusNotifierItem(this); 2620 m_trayicon->setIconByName(QLatin1String( "kgpg" )); 2621 m_trayicon->setToolTip(QLatin1String( "kgpg" ), i18n("KGpg - encryption tool"), QString()); 2622 } 2623 2624 switch (KGpgSettings::leftClick()) { 2625 case KGpgSettings::EnumLeftClick::Editor: 2626 s_kgpgEditor->winId(); // create windowHandle 2627 m_trayicon->setAssociatedWindow(s_kgpgEditor->windowHandle()); 2628 break; 2629 case KGpgSettings::EnumLeftClick::KeyManager: 2630 winId(); // create windowHandle 2631 m_trayicon->setAssociatedWindow(windowHandle()); 2632 break; 2633 } 2634 2635 m_trayicon->setCategory(KStatusNotifierItem::ApplicationStatus); 2636 2637 if (!newtray) 2638 return; 2639 2640 QMenu *conf_menu = m_trayicon->contextMenu(); 2641 2642 QAction *KgpgOpenManager = actionCollection()->addAction(QLatin1String("kgpg_manager"), this, &KeysManager::show); 2643 KgpgOpenManager->setIcon(QIcon::fromTheme( QLatin1String( "kgpg" ))); 2644 KgpgOpenManager->setText(i18n("Ke&y Manager")); 2645 2646 QAction *KgpgEncryptClipboard = actionCollection()->addAction(QLatin1String("clip_encrypt"), this, &KeysManager::clipEncrypt); 2647 KgpgEncryptClipboard->setText(i18n("&Encrypt Clipboard")); 2648 2649 QAction *KgpgDecryptClipboard = actionCollection()->addAction(QLatin1String("clip_decrypt"), this, &KeysManager::clipDecrypt); 2650 KgpgDecryptClipboard->setText(i18n("&Decrypt Clipboard")); 2651 2652 QAction *KgpgSignClipboard = actionCollection()->addAction(QLatin1String("clip_sign"), this, &KeysManager::clipSign); 2653 KgpgSignClipboard->setText(i18n("&Sign/Verify Clipboard")); 2654 KgpgSignClipboard->setIcon(QIcon::fromTheme( QLatin1String( "document-sign-key" ))); 2655 2656 QAction *KgpgPreferences = KStandardAction::preferences(this, &KeysManager::showOptions, actionCollection()); 2657 2658 conf_menu->addAction( KgpgEncryptClipboard ); 2659 conf_menu->addAction( KgpgDecryptClipboard ); 2660 conf_menu->addAction( KgpgSignClipboard ); 2661 conf_menu->addAction( KgpgOpenManager ); 2662 conf_menu->addAction( openEditor ); 2663 conf_menu->addAction( kserver ); 2664 conf_menu->addSeparator(); 2665 conf_menu->addAction( KgpgPreferences ); 2666 } 2667 2668 void 2669 KeysManager::showTrayMessage(const QString &message) 2670 { 2671 if (m_trayicon == nullptr) 2672 return; 2673 2674 m_trayicon->showMessage(QString(), message, QLatin1String( "kgpg" )); 2675 } 2676 2677 QKeySequence 2678 KeysManager::goDefaultShortcut() const 2679 { 2680 return QKeySequence(goToDefaultKey->shortcut()); 2681 } 2682 2683 void 2684 KeysManager::clipEncrypt() 2685 { 2686 const QString cliptext(qApp->clipboard()->text(m_clipboardmode)); 2687 2688 if (cliptext.isEmpty()) { 2689 Q_ASSERT(m_trayicon != nullptr); 2690 m_trayicon->showMessage(QString(), i18n("Clipboard is empty."), QLatin1String( "kgpg" )); 2691 return; 2692 } 2693 2694 QPointer<KgpgSelectPublicKeyDlg> dialog = new KgpgSelectPublicKeyDlg(this, imodel, QKeySequence(goToDefaultKey->shortcut()), true); 2695 if (dialog->exec() == QDialog::Accepted) { 2696 KGpgEncrypt::EncryptOptions encOptions = KGpgEncrypt::AsciiArmored; 2697 QStringList options; 2698 2699 if (!dialog->getCustomOptions().isEmpty() && KGpgSettings::allowCustomEncryptionOptions()) 2700 options = dialog->getCustomOptions().split(QLatin1Char(' '), Qt::SkipEmptyParts); 2701 2702 if (dialog->getUntrusted()) 2703 encOptions |= KGpgEncrypt::AllowUntrustedEncryption; 2704 if (dialog->getHideId()) 2705 encOptions |= KGpgEncrypt::HideKeyId; 2706 2707 if (KGpgSettings::pgpCompatibility()) 2708 options.append(QLatin1String( "--pgp6" )); 2709 2710 KGpgEncrypt *enc = new KGpgEncrypt(this, dialog->selectedKeys(), cliptext, encOptions, options); 2711 connect(enc, &KGpgEncrypt::done, this, &KeysManager::slotSetClip); 2712 2713 m_trayicon->setStatus(KStatusNotifierItem::Active); 2714 enc->start(); 2715 } 2716 2717 delete dialog; 2718 } 2719 2720 void 2721 KeysManager::slotSetClip(int result) 2722 { 2723 KGpgEncrypt *enc = qobject_cast<KGpgEncrypt *>(sender()); 2724 Q_ASSERT(enc != nullptr); 2725 sender()->deleteLater(); 2726 2727 m_trayicon->setStatus(KStatusNotifierItem::Passive); 2728 2729 if (result != KGpgTransaction::TS_OK) 2730 return; 2731 2732 qApp->clipboard()->setText(enc->encryptedText().join(QLatin1String("\n")), m_clipboardmode); 2733 2734 Q_ASSERT(m_trayicon != nullptr); 2735 m_trayicon->showMessage(QString(), i18n("Text successfully encrypted."), QLatin1String( "kgpg" )); 2736 } 2737 2738 void 2739 KeysManager::slotOpenKeyUrl() 2740 { 2741 KGpgNode *cur = iview->selectedNode(); 2742 if (cur == nullptr) 2743 return; 2744 2745 QString id; 2746 2747 switch (cur->getType()) { 2748 case ITYPE_PAIR: 2749 case ITYPE_PUBLIC: { 2750 id = cur->toKeyNode()->getFingerprint(); 2751 break; 2752 } 2753 case ITYPE_GPAIR: 2754 case ITYPE_GPUBLIC: { 2755 id = cur->getId(); 2756 break; 2757 } 2758 default: 2759 return; 2760 } 2761 2762 const QStringList servers = KGpgSettings::infoServers(); 2763 if (servers.isEmpty()) 2764 return; 2765 2766 QString url = servers.first(); 2767 const QString idUC = id.toUpper(); 2768 const QString idLC = id.toLower(); 2769 2770 url.replace(QLatin1String("$$ID8$$"), idUC.right(8)); 2771 url.replace(QLatin1String("$$ID16$$"), idUC.right(16)); 2772 url.replace(QLatin1String("$$FPR$$"), idUC); 2773 url.replace(QLatin1String("$$id8$$"), idLC.right(8)); 2774 url.replace(QLatin1String("$$id16$$"), idLC.right(16)); 2775 url.replace(QLatin1String("$$fpr$$"), idLC); 2776 2777 auto *job = new KIO::OpenUrlJob(QUrl(url)); 2778 job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this)); 2779 job->start(); 2780 } 2781 2782 void 2783 KeysManager::clipDecrypt() 2784 { 2785 const QString cliptext(qApp->clipboard()->text(m_clipboardmode).trimmed()); 2786 2787 if (cliptext.isEmpty()) { 2788 Q_ASSERT(m_trayicon != nullptr); 2789 m_trayicon->showMessage(QString(), i18n("Clipboard is empty."), QLatin1String( "kgpg" )); 2790 return; 2791 } 2792 2793 KgpgEditor *kgpgtxtedit = new KgpgEditor(this, imodel, {}); 2794 kgpgtxtedit->setAttribute(Qt::WA_DeleteOnClose); 2795 connect(this, &KeysManager::fontChanged, kgpgtxtedit, &KgpgEditor::slotSetFont); 2796 kgpgtxtedit->m_editor->setPlainText(cliptext); 2797 kgpgtxtedit->m_editor->slotDecode(); 2798 kgpgtxtedit->show(); 2799 } 2800 2801 void 2802 KeysManager::clipSign() 2803 { 2804 QString cliptext = qApp->clipboard()->text(m_clipboardmode); 2805 if (cliptext.isEmpty()) { 2806 Q_ASSERT(m_trayicon != nullptr); 2807 m_trayicon->showMessage(QString(), i18n("Clipboard is empty."), QLatin1String( "kgpg" )); 2808 return; 2809 } 2810 2811 KgpgEditor *kgpgtxtedit = new KgpgEditor(this, imodel, {}); 2812 kgpgtxtedit->setAttribute(Qt::WA_DeleteOnClose); 2813 connect(kgpgtxtedit->m_editor, &KgpgTextEdit::verifyFinished, kgpgtxtedit, &KgpgEditor::closeWindow); 2814 2815 kgpgtxtedit->m_editor->signVerifyText(cliptext); 2816 kgpgtxtedit->show(); 2817 }