File indexing completed on 2022-08-04 16:24:14

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