diff --git a/core/KGpgKeyNode.cpp b/core/KGpgKeyNode.cpp index 7caea132..582b8723 100644 --- a/core/KGpgKeyNode.cpp +++ b/core/KGpgKeyNode.cpp @@ -1,373 +1,371 @@ /* * Copyright (C) 2008,2009,2010,2012,2013,2014,2017 * Rolf Eike Beer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "KGpgKeyNode.h" #include "KGpgGroupMemberNode.h" #include "KGpgRootNode.h" #include "KGpgSubkeyNode.h" #include "KGpgUatNode.h" #include "KGpgUidNode.h" #include "convert.h" #include "kgpginterface.h" #include "kgpgsettings.h" #include "model/kgpgitemmodel.h" #include KGpgKeyNode::KGpgKeyNode(KGpgRootNode *parent, const KgpgCore::KgpgKey &k) : KGpgSignableNode(parent), m_key(new KgpgCore::KgpgKey(k)), m_signs(0) { } KGpgKeyNode::~KGpgKeyNode() { // do not try to access the root node if we are being deleted from there KGpgRootNode * const root = parent() != nullptr ? m_parent->toRootNode() : nullptr; for (KGpgRefNode *nd : qAsConst(m_refs)) nd->unRef(root); } KgpgCore::KgpgItemType KGpgKeyNode::getType() const { return getType(m_key); } bool KGpgKeyNode::hasChildren() const { return true; } KgpgCore::KgpgItemType KGpgKeyNode::getType(const KgpgCore::KgpgKey *k) { if (k->secret()) return KgpgCore::ITYPE_PAIR; return KgpgCore::ITYPE_PUBLIC; } KgpgCore::KgpgKeyTrust KGpgKeyNode::getTrust() const { return m_key->trust(); } const QString & KGpgKeyNode::getFingerprint() const { return m_key->fingerprint(); } QString KGpgKeyNode::getSize() const { return i18nc("size of signing key / size of encryption key", "%1 / %2", m_key->strength(), m_key->encryptionStrength()); } QString KGpgKeyNode::getName() const { return m_key->name(); } QString KGpgKeyNode::getEmail() const { return m_key->email(); } QDateTime KGpgKeyNode::getExpiration() const { return m_key->expirationDate(); } QDateTime KGpgKeyNode::getCreation() const { return m_key->creationDate(); } QString KGpgKeyNode::getId() const { return m_key->fullId(); } KGpgKeyNode * KGpgKeyNode::getKeyNode(void) { return this; } bool KGpgKeyNode::isSecret() const { return m_key->secret(); } const KGpgKeyNode * KGpgKeyNode::getKeyNode(void) const { return this; } QString KGpgKeyNode::getBeautifiedFingerprint() const { static const QChar space = QLatin1Char(' '); QString fingervalue = m_key->fingerprint(); int len = fingervalue.length(); if ((len > 0) && (len % 4 == 0)) for (int n = 0; 4 * (n + 1) < len; n++) fingervalue.insert(5 * n + 4, space); return fingervalue; } QString KGpgKeyNode::getComment() const { return m_key->comment(); } void KGpgKeyNode::readChildren() { KgpgInterface::readSignatures(this); m_signs = 0; for (const KGpgNode *n : qAsConst(children)) if (n->getType() == ITYPE_SIGN) m_signs++; } QString KGpgKeyNode::getSignCount() const { if (!wasExpanded()) return QString(); return i18np("1 signature", "%1 signatures", m_signs); } KgpgKey * KGpgKeyNode::copyKey() const { return new KgpgKey(*m_key); } void KGpgKeyNode::setKey(const KgpgKey &key) { Q_ASSERT(m_key->fingerprint() == key.fingerprint()); delete m_key; for (int i = 0; i < children.count(); i++) delete children.at(i); children.clear(); m_key = new KgpgKey(key); } const KgpgKey * KGpgKeyNode::getKey() const { return m_key; } unsigned int KGpgKeyNode::getSignKeySize() const { return m_key->size(); } unsigned int KGpgKeyNode::getEncryptionKeySize() const { return m_key->encryptionSize(); } void KGpgKeyNode::addRef(KGpgRefNode *node) { Q_ASSERT(m_refs.indexOf(node) == -1); m_refs.append(node); } void KGpgKeyNode::delRef(KGpgRefNode *node) { Q_ASSERT(m_refs.indexOf(node) != -1); m_refs.removeOne(node); Q_ASSERT(m_refs.indexOf(node) == -1); } QList KGpgKeyNode::getGroups(void) const { QList ret; const QList refs = getGroupRefs(); ret.reserve(refs.count()); for (KGpgGroupMemberNode *gnd : refs) ret.append(gnd->getParentKeyNode()); return ret; } QList KGpgKeyNode::getRefsOfType(const KgpgItemType &type) const { QList ret; for (KGpgRefNode *nd : m_refs) { if (nd->getType() & type) ret.append(nd); } return ret; } QList KGpgKeyNode::getGroupRefs(void) const { QList ret; const QList refs = getRefsOfType(KgpgCore::ITYPE_GROUP); ret.reserve(refs.count()); for (KGpgRefNode *rn : refs) ret.append(rn->toGroupMemberNode()); return ret; } KGpgSignNode::List KGpgKeyNode::getSignRefs(void) const { KGpgSignNode::List ret; const QList refs = getRefsOfType(KgpgCore::ITYPE_SIGN); ret.reserve(refs.count()); for (KGpgRefNode *rn : refs) ret.append(rn->toSignNode()); return ret; } KGpgSignNode::List KGpgKeyNode::getSignatures(const bool subkeys) const { KGpgSignNode::List ret = KGpgSignableNode::getSignatures(); if (!subkeys) return ret; for (KGpgNode *child : children) { switch (child->getType()) { case KgpgCore::ITYPE_UID: case KgpgCore::ITYPE_UAT: break; default: continue; } const KGpgSignNode::List tmp = child->toSignableNode()->getSignatures(); for (KGpgSignNode *sn : tmp) { bool found = false; const QString snid(sn->getId()); for (const KGpgSignNode *retsn : qAsConst(ret)) { found = (retsn->getId() == snid); if (found) break; } if (!found) ret << sn; } } return ret; } const KGpgSignableNode * KGpgKeyNode::getUid(const unsigned int index) const { Q_ASSERT(index > 0); if (index == 1) return this; const QString idxstr = QString::number(index); for (const KGpgNode *child : children) { KGpgSignNode::List tmp; switch (child->getType()) { case KgpgCore::ITYPE_UID: case KgpgCore::ITYPE_UAT: if (child->getId() == idxstr) return child->toSignableNode(); break; default: continue; } } return nullptr; } bool KGpgKeyNode::compareId(const QString &other) const { if (other.length() == m_key->fullId().length()) return (other.compare(m_key->fullId(), Qt::CaseInsensitive) == 0); if (other.length() == m_key->fingerprint().length()) return (other.compare(m_key->fingerprint(), Qt::CaseInsensitive) == 0); const QString comId = m_key->fullId().isEmpty() ? m_key->fingerprint() : m_key->fullId(); - return (other.right(comId.length()).compare( - comId.right(other.length()), - Qt::CaseInsensitive) == 0); + return (other.rightRef(comId.length()).compare(comId.rightRef(other.length()), Qt::CaseInsensitive) == 0); } bool KGpgKeyNode::canEncrypt() const { return ((m_key->keytype() & KgpgCore::SKT_ENCRYPTION) != 0); } void KGpgKeyNode::expand() { if (!wasExpanded()) readChildren(); emit expanded(); } diff --git a/core/KGpgRefNode.cpp b/core/KGpgRefNode.cpp index cd4d1091..04037071 100644 --- a/core/KGpgRefNode.cpp +++ b/core/KGpgRefNode.cpp @@ -1,149 +1,149 @@ /* Copyright 2008,2009,2010,2013 Rolf Eike Beer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "KGpgRefNode.h" #include #include "KGpgExpandableNode.h" #include "KGpgRootNode.h" KGpgRefNode::KGpgRefNode(KGpgExpandableNode *parent, const QString &keyid) : KGpgNode(parent), m_id(keyid) { Q_ASSERT(!keyid.isEmpty()); KGpgRootNode *root = getRootNode(); KGpgExpandableNode *pnd = parent; do { - m_selfsig = (pnd->getId().right(keyid.length()) == keyid); + m_selfsig = (pnd->getId().rightRef(keyid.length()).compare(keyid) == 0); if (m_selfsig) m_keynode = pnd->toKeyNode(); else pnd = pnd->getParentKeyNode(); } while (!m_selfsig && (pnd != root)); // Self signatures do net need to get notified by their key: if the key is changed // the key node is deleted, then those refnode would be deleted anyway. This avoids // crashes when they would try to find the root node by iterating over their parent // when the parents destructor is already called (see bug 208659). if (!m_selfsig) { m_keynode = root->findKey(keyid); if (m_keynode != nullptr) { m_keynode->addRef(this); } else { m_updateConnection = connect(root, &KGpgRootNode::newKeyNode, this, &KGpgRefNode::keyUpdated); } } parent->children.append(this); } KGpgRefNode::KGpgRefNode(KGpgExpandableNode *parent, KGpgKeyNode *key) : KGpgNode(parent), m_id(key->getId()), m_keynode(key) { Q_ASSERT(key != nullptr); Q_ASSERT(parent != nullptr); m_keynode->addRef(this); parent->children.append(this); } KGpgRefNode::~KGpgRefNode() { if (m_keynode && !m_selfsig) m_keynode->delRef(this); } KGpgRootNode * KGpgRefNode::getRootNode() const { KGpgExpandableNode *root; KGpgExpandableNode *pt = m_parent; do { root = pt; pt = pt->getParentKeyNode(); } while (pt != nullptr); return root->toRootNode(); } void KGpgRefNode::keyUpdated(KGpgKeyNode *nkey) { Q_ASSERT(m_keynode == nullptr); Q_ASSERT(nkey != nullptr); if (nkey->compareId(m_id)) { disconnect(m_updateConnection); m_keynode = nkey; m_keynode->addRef(this); } } void KGpgRefNode::unRef(KGpgRootNode *root) { if (root != nullptr) m_updateConnection = connect(root, &KGpgRootNode::newKeyNode, this, &KGpgRefNode::keyUpdated); m_keynode = nullptr; } QString KGpgRefNode::getId() const { if (m_keynode != nullptr) return m_keynode->getFingerprint(); else return m_id; } QString KGpgRefNode::getName() const { if (m_keynode != nullptr) return m_keynode->getName(); return i18n("[No user id found]"); } QString KGpgRefNode::getEmail() const { if (m_keynode != nullptr) return m_keynode->getEmail(); return QString(); } bool KGpgRefNode::isUnknown() const { return (m_keynode == nullptr); } KGpgKeyNode * KGpgRefNode::getRefNode() const { return m_keynode; } diff --git a/keysmanager.cpp b/keysmanager.cpp index 555c4a66..e77a3f93 100644 --- a/keysmanager.cpp +++ b/keysmanager.cpp @@ -1,2857 +1,2857 @@ /* * Copyright (C) 2002 Jean-Baptiste Mardelle * Copyright (C) 2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017 * Rolf Eike Beer * Copyright (C) 2011 Luis Ángel Fernández Fernández * Copyright (C) 2016 Andrius Štikonas */ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "keysmanager.h" #include "caff.h" #include "core/images.h" #include "core/kgpgkey.h" #include "detailedconsole.h" #include "gpgproc.h" #include "groupedit.h" #include "keyadaptor.h" #include "keyexport.h" #include "keyinfodialog.h" #include "keyservers.h" #include "keytreeview.h" #include "kgpg_general_debug.h" #include "kgpg.h" #include "kgpgchangekey.h" #include "kgpgkeygenerate.h" #include "kgpgoptions.h" #include "kgpgrevokewidget.h" #include "kgpgsettings.h" #include "newkey.h" #include "selectpublickeydialog.h" #include "selectsecretkey.h" #include "sourceselect.h" #include "editor/kgpgeditor.h" #include "editor/kgpgtextedit.h" #include "model/keylistproxymodel.h" #include "transactions/kgpgaddphoto.h" #include "transactions/kgpgadduid.h" #include "transactions/kgpgdecrypt.h" #include "transactions/kgpgdelkey.h" #include "transactions/kgpgdelsign.h" #include "transactions/kgpgdeluid.h" #include "transactions/kgpgencrypt.h" #include "transactions/kgpgexport.h" #include "transactions/kgpggeneratekey.h" #include "transactions/kgpggeneraterevoke.h" #include "transactions/kgpgimport.h" #include "transactions/kgpgkeyservergettransaction.h" #include "transactions/kgpgprimaryuid.h" #include "transactions/kgpgsignkey.h" #include "transactions/kgpgsignuid.h" #include "transactions/kgpgtransactionjob.h" #include #include #include #include #include #include // #include TODO #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KgpgCore; KeysManager::KeysManager(QWidget *parent) : KXmlGuiWindow(parent), imodel(new KGpgItemModel(this)), m_adduid(nullptr), m_genkey(nullptr), m_delkey(nullptr), terminalkey(nullptr), m_trayicon(nullptr) { new KeyAdaptor(this); QDBusConnection::sessionBus().registerObject(QLatin1String( "/KeyInterface" ), this); setAttribute(Qt::WA_DeleteOnClose, false); setWindowTitle(i18n("Key Management")); KStandardAction::quit(this, &KeysManager::quitApp, actionCollection()); actionCollection()->addAction(KStandardAction::Preferences, QLatin1String( "options_configure" ), this, SLOT(showOptions())); openEditor = actionCollection()->addAction(QLatin1String("kgpg_editor"), this, &KeysManager::slotOpenEditor); openEditor->setIcon(QIcon::fromTheme( QLatin1String( "accessories-text-editor" ))); openEditor->setText(i18n("&Open Editor")); kserver = actionCollection()->addAction( QLatin1String("key_server"), this, &KeysManager::showKeyServer); kserver->setText( i18n("&Key Server Dialog") ); kserver->setIcon( QIcon::fromTheme( QLatin1String( "network-server" )) ); goToDefaultKey = actionCollection()->addAction(QLatin1String("go_default_key"), this, &KeysManager::slotGotoDefaultKey); goToDefaultKey->setIcon(QIcon::fromTheme( QLatin1String( "go-home" ))); goToDefaultKey->setText(i18n("&Go to Default Key")); actionCollection()->setDefaultShortcut(goToDefaultKey, QKeySequence(Qt::CTRL + Qt::Key_Home)); s_kgpgEditor = new KgpgEditor(this, imodel, Qt::Dialog); s_kgpgEditor->setAttribute(Qt::WA_DeleteOnClose, false); // this must come after kserver, preferences, and openEditor are created // because they are used to set up the tray icon context menu readOptions(); if (showTipOfDay) installEventFilter(this); QAction *action; action = actionCollection()->addAction(QLatin1String("help_tipofday"), this, &KeysManager::slotTip); action->setIcon( QIcon::fromTheme( QLatin1String( "help-hint" )) ); action->setText( i18n("Tip of the &Day") ); action = actionCollection()->addAction(QLatin1String("gpg_man"), this, &KeysManager::slotManpage); action->setText( i18n("View GnuPG Manual") ); action->setIcon( QIcon::fromTheme( QLatin1String( "help-contents" )) ); action = actionCollection()->addAction(QLatin1String("key_refresh"), this, &KeysManager::refreshkey); action->setIcon(QIcon::fromTheme( QLatin1String( "view-refresh" ))); action->setText(i18n("&Refresh List")); actionCollection()->setDefaultShortcuts(action, KStandardShortcut::reload()); longId = actionCollection()->add(QLatin1String("show_long_keyid"), this, &KeysManager::slotShowLongId); longId->setText(i18n("Show &Long Key Id")); longId->setChecked(KGpgSettings::showLongKeyId()); QAction *infoKey = actionCollection()->addAction(QLatin1String("key_info"), this, &KeysManager::keyproperties); infoKey->setIcon(QIcon::fromTheme( QLatin1String( "document-properties-key" ))); infoKey->setText(i18n("K&ey Properties")); QAction *openKeyUrl = actionCollection()->addAction(QLatin1String("key_url"), this, &KeysManager::slotOpenKeyUrl); openKeyUrl->setIcon(QIcon::fromTheme(QLatin1String("applications-internet"))); openKeyUrl->setText(i18n("&Open Key URL")); editKey = actionCollection()->addAction(QLatin1String("key_edit"), this, &KeysManager::slotedit); editKey->setIcon(QIcon::fromTheme( QLatin1String( "utilities-terminal" ))); editKey->setText(i18n("Edit Key in &Terminal")); actionCollection()->setDefaultShortcut(editKey, QKeySequence(Qt::ALT + Qt::Key_Return)); QAction *generateKey = actionCollection()->addAction(QLatin1String("key_gener"), this, &KeysManager::slotGenerateKey); generateKey->setIcon(QIcon::fromTheme( QLatin1String( "key-generate-pair" ))); generateKey->setText(i18n("&Generate Key Pair...")); actionCollection()->setDefaultShortcuts(generateKey, KStandardShortcut::shortcut(KStandardShortcut::New)); exportPublicKey = actionCollection()->addAction(QLatin1String("key_export"), this, &KeysManager::slotexport); exportPublicKey->setIcon(QIcon::fromTheme( QLatin1String( "document-export-key" ))); actionCollection()->setDefaultShortcuts(exportPublicKey, KStandardShortcut::shortcut(KStandardShortcut::Copy)); QAction *importKey = actionCollection()->addAction(QLatin1String("key_import"), this, &KeysManager::slotPreImportKey); importKey->setIcon(QIcon::fromTheme( QLatin1String( "document-import-key" ))); importKey->setText(i18n("&Import Key...")); actionCollection()->setDefaultShortcuts(importKey, KStandardShortcut::shortcut(KStandardShortcut::Paste)); m_sendEmail = actionCollection()->addAction(QLatin1String("send_mail"), this, &KeysManager::slotSendEmail); m_sendEmail->setIcon(QIcon::fromTheme(QLatin1String("mail-send"))); m_sendEmail->setText(i18n("Send Ema&il")); QAction *newContact = actionCollection()->addAction(QLatin1String("add_kab"), this, &KeysManager::addToKAB); newContact->setIcon(QIcon::fromTheme( QLatin1String( "contact-new" ))); newContact->setText(i18n("&Create New Contact in Address Book")); createGroup = actionCollection()->addAction(QLatin1String("create_group"), this, &KeysManager::createNewGroup); createGroup->setIcon(Images::group()); editCurrentGroup = actionCollection()->addAction(QLatin1String("edit_group"), this, &KeysManager::editGroup); editCurrentGroup->setText(i18n("&Edit Group...")); delGroup = actionCollection()->addAction(QLatin1String("delete_group"), this, &KeysManager::deleteGroup); delGroup->setText(i18n("&Delete Group")); delGroup->setIcon(QIcon::fromTheme( QLatin1String( "edit-delete" ))); m_groupRename = actionCollection()->addAction(QLatin1String("rename_group"), this, &KeysManager::renameGroup); m_groupRename->setText(i18n("&Rename Group")); m_groupRename->setIcon(QIcon::fromTheme( QLatin1String( "edit-rename" ))); actionCollection()->setDefaultShortcut(m_groupRename, QKeySequence(Qt::Key_F2)); deleteKey = actionCollection()->addAction(QLatin1String("key_delete"), this, &KeysManager::confirmdeletekey); deleteKey->setIcon(QIcon::fromTheme( QLatin1String( "edit-delete" ))); actionCollection()->setDefaultShortcut(deleteKey, QKeySequence(Qt::Key_Delete)); setDefaultKey = actionCollection()->addAction(QLatin1String("key_default"), this, &KeysManager::slotSetDefKey); setDefaultKey->setText(i18n("Set as De&fault Key")); QAction *addPhoto = actionCollection()->addAction(QLatin1String("add_photo"), this, &KeysManager::slotAddPhoto); addPhoto->setText(i18n("&Add Photo...")); QAction *addUid = actionCollection()->addAction(QLatin1String("add_uid"), this, &KeysManager::slotAddUid); addUid->setText(i18n("&Add User Id...")); QAction *exportSecretKey = actionCollection()->addAction(QLatin1String("key_sexport"), this, &KeysManager::slotexportsec); exportSecretKey->setText(i18n("Export Secret Key...")); QAction *deleteKeyPair = actionCollection()->addAction(QLatin1String("key_pdelete"), this, &KeysManager::deleteseckey); deleteKeyPair->setText(i18n("Delete Key Pair")); deleteKeyPair->setIcon(QIcon::fromTheme( QLatin1String( "edit-delete" ))); m_revokeKey = actionCollection()->addAction(QLatin1String("key_revoke"), this, &KeysManager::revokeWidget); m_revokeKey->setText(i18n("Revoke Key...")); QAction *regeneratePublic = actionCollection()->addAction(QLatin1String("key_regener"), this, &KeysManager::slotregenerate); regeneratePublic->setText(i18n("&Regenerate Public Key")); delUid = actionCollection()->addAction(QLatin1String("del_uid"), this, &KeysManager::slotDelUid); delUid->setIcon(QIcon::fromTheme( QLatin1String( "edit-delete" ))); setPrimUid = actionCollection()->addAction(QLatin1String("prim_uid"), this, &KeysManager::slotPrimUid); setPrimUid->setText(i18n("Set User Id as &Primary")); QAction *openPhoto = actionCollection()->addAction(QLatin1String("key_photo"), this, &KeysManager::slotShowPhoto); openPhoto->setIcon(QIcon::fromTheme( QLatin1String( "image-x-generic" ))); openPhoto->setText(i18n("&Open Photo")); QAction *deletePhoto = actionCollection()->addAction(QLatin1String("delete_photo"), this, &KeysManager::slotDeletePhoto); deletePhoto->setIcon(QIcon::fromTheme( QLatin1String( "edit-delete" ))); deletePhoto->setText(i18n("&Delete Photo")); delSignKey = actionCollection()->addAction(QLatin1String("key_delsign"), this, &KeysManager::delsignkey); delSignKey->setIcon(QIcon::fromTheme( QLatin1String( "edit-delete" ))); delSignKey->setEnabled(false); importAllSignKeys = actionCollection()->addAction(QLatin1String("key_importallsign"), this, &KeysManager::importallsignkey); importAllSignKeys->setIcon(QIcon::fromTheme( QLatin1String( "document-import" ))); importAllSignKeys->setText(i18n("Import &Missing Signatures From Keyserver")); refreshKey = actionCollection()->addAction(QLatin1String("key_server_refresh"), this, &KeysManager::refreshKeyFromServer); refreshKey->setIcon(QIcon::fromTheme( QLatin1String( "view-refresh" ))); signKey = actionCollection()->addAction(QLatin1String("key_sign"), this, &KeysManager::signkey); signKey->setIcon(QIcon::fromTheme( QLatin1String( "document-sign-key" ))); signUid = actionCollection()->addAction(QLatin1String("key_sign_uid"), this, &KeysManager::signuid); signUid->setIcon(QIcon::fromTheme( QLatin1String( "document-sign-key" ))); signMailUid = actionCollection()->addAction(QLatin1String("key_sign_mail_uid"), this, &KeysManager::caff); signMailUid->setIcon(QIcon::fromTheme( QLatin1String( "document-sign-key" ))); importSignatureKey = actionCollection()->addAction(QLatin1String("key_importsign"), this, &KeysManager::preimportsignkey); importSignatureKey->setIcon(QIcon::fromTheme( QLatin1String( "document-import-key" ))); sTrust = actionCollection()->add(QLatin1String("show_trust"), this, &KeysManager::slotShowTrust); sTrust->setText(i18n("Trust")); sSize = actionCollection()->add(QLatin1String("show_size"), this, &KeysManager::slotShowSize); sSize->setText(i18n("Size")); sCreat = actionCollection()->add(QLatin1String("show_creat"), this, &KeysManager::slotShowCreation); sCreat->setText(i18n("Creation")); sExpi = actionCollection()->add(QLatin1String("show_expi"), this, &KeysManager::slotShowExpiration); sExpi->setText(i18n("Expiration")); photoProps = actionCollection()->add(QLatin1String( "photo_settings" )); photoProps->setIcon(QIcon::fromTheme( QLatin1String( "image-x-generic" ))); photoProps->setText(i18n("&Photo ID's")); // Keep the list in kgpg.kcfg in sync with this one! QStringList list; list.append(i18n("Disable")); list.append(i18nc("small picture", "Small")); list.append(i18nc("medium picture", "Medium")); list.append(i18nc("large picture", "Large")); photoProps->setItems(list); trustProps = actionCollection()->add(QLatin1String( "trust_filter_settings" )); trustProps->setText(i18n("Minimum &Trust")); QStringList tlist; tlist.append(i18nc("no filter: show all keys", "&None")); tlist.append(i18nc("show only active keys", "&Active")); tlist.append(i18nc("show only keys with at least marginal trust", "&Marginal")); tlist.append(i18nc("show only keys with at least full trust", "&Full")); tlist.append(i18nc("show only ultimately trusted keys", "&Ultimate")); trustProps->setItems(tlist); iproxy = new KeyListProxyModel(this); iproxy->setKeyModel(imodel); connect(this, &KeysManager::readAgainOptions, iproxy, &KeyListProxyModel::settingsChanged); iview = new KeyTreeView(this, iproxy); connect(iview, &KeyTreeView::doubleClicked, this, static_cast(&KeysManager::defaultAction)); connect(iview, &KeyTreeView::importDrop, this, static_cast &)>(&KeysManager::slotImport)); iview->setSelectionMode(QAbstractItemView::ExtendedSelection); setCentralWidget(iview); iview->resizeColumnsToContents(); iview->setAlternatingRowColors(true); iview->setSortingEnabled(true); connect(iview, &KeyTreeView::customContextMenuRequested, this, &KeysManager::slotMenu); iview->setContextMenuPolicy(Qt::CustomContextMenu); connect(iview->selectionModel(), &QItemSelectionModel::selectionChanged, this, &KeysManager::checkList); connect(iview, &KeyTreeView::returnPressed, this, &KeysManager::slotDefaultAction); hPublic = actionCollection()->add(QLatin1String("show_secret"), iproxy, &KeyListProxyModel::setOnlySecret); hPublic->setIcon(QIcon::fromTheme( QLatin1String( "view-key-secret" ))); hPublic->setText(i18n("&Show Only Secret Keys")); hPublic->setChecked(KGpgSettings::showSecret()); int psize = KGpgSettings::photoProperties(); photoProps->setCurrentItem(psize); slotSetPhotoSize(psize); psize = KGpgSettings::trustLevel(); trustProps->setCurrentItem(psize); slotSetTrustFilter(psize); slotShowLongId(KGpgSettings::showLongKeyId()); m_popuppub = new QMenu(this); m_popuppub->addAction(exportPublicKey); m_popuppub->addAction(m_sendEmail); m_popuppub->addAction(signMailUid); m_popuppub->addAction(signKey); m_popuppub->addAction(signUid); m_popuppub->addAction(deleteKey); m_popuppub->addAction(infoKey); m_popuppub->addAction(openKeyUrl); m_popuppub->addAction(editKey); m_popuppub->addAction(refreshKey); m_popuppub->addAction(createGroup); m_popuppub->addSeparator(); m_popuppub->addAction(importAllSignKeys); m_popupsec = new QMenu(this); m_popupsec->addAction(exportPublicKey); m_popupsec->addAction(m_sendEmail); m_popupsec->addAction(signKey); m_popupsec->addAction(signUid); m_popupsec->addAction(signMailUid); m_popupsec->addAction(infoKey); m_popupsec->addAction(openKeyUrl); m_popupsec->addAction(editKey); m_popupsec->addAction(refreshKey); m_popupsec->addAction(setDefaultKey); m_popupsec->addSeparator(); m_popupsec->addAction(importAllSignKeys); m_popupsec->addSeparator(); m_popupsec->addAction(addPhoto); m_popupsec->addAction(addUid); m_popupsec->addAction(exportSecretKey); m_popupsec->addAction(deleteKeyPair); m_popupgroup = new QMenu(this); m_popupgroup->addAction(editCurrentGroup); m_popupgroup->addAction(m_groupRename); m_popupgroup->addAction(delGroup); m_popupgroup->addAction(refreshKey); m_popupout = new QMenu(this); m_popupout->addAction(importKey); m_popupsig = new QMenu(); m_popupsig->addAction(importSignatureKey); m_popupsig->addAction(delSignKey); m_popupphoto = new QMenu(this); m_popupphoto->addAction(openPhoto); m_popupphoto->addAction(signUid); m_popupphoto->addAction(signMailUid); m_popupphoto->addAction(deletePhoto); m_popupuid = new QMenu(this); m_popupuid->addAction(m_sendEmail); m_popupuid->addAction(signMailUid); m_popupuid->addAction(signUid); m_popupuid->addAction(delUid); m_popupuid->addAction(setPrimUid); m_popuporphan = new QMenu(this); m_popuporphan->addAction(regeneratePublic); m_popuporphan->addAction(deleteKeyPair); exportPublicKey->setEnabled(false); KConfigGroup cg = KConfigGroup(KSharedConfig::openConfig().data(), "KeyView"); iview->restoreLayout(cg); connect(photoProps, static_cast(&KSelectAction::triggered), this, &KeysManager::slotSetPhotoSize); connect(trustProps, static_cast(&KSelectAction::triggered), this, &KeysManager::slotSetTrustFilter); QLabel *searchLabel = new QLabel(i18n("Search:"), this); m_listviewsearch = new QLineEdit(this); m_listviewsearch->setClearButtonEnabled(true); QWidget *searchWidget = new QWidget(this); QHBoxLayout *searchLayout = new QHBoxLayout(searchWidget); searchLayout->setMargin(0); searchLayout->addWidget(searchLabel); searchLayout->addWidget(m_listviewsearch); searchLayout->addStretch(); QWidgetAction *searchLineAction = new QWidgetAction(/*i18nc("Name of the action that is a search line, shown for example in the toolbar configuration dialog", "Search Line"), */this); actionCollection()->addAction(QLatin1String( "search_line" ), searchLineAction); searchLineAction->setDefaultWidget(searchWidget); action = actionCollection()->addAction(QLatin1String("search_focus"), m_listviewsearch, static_cast(&QWidget::setFocus)); action->setText(i18nc("Name of the action that gives the focus to the search line", "Focus Search Line")); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::Key_F6)); connect(m_listviewsearch, &QLineEdit::textChanged, iproxy, &KeyListProxyModel::setFilterFixedString); setActionDescriptions(1); // get all keys data setupGUI(KXmlGuiWindow::Create | Save | ToolBar | StatusBar | Keys, QLatin1String( "keysmanager.rc" )); sTrust->setChecked(KGpgSettings::showTrust()); iview->setColumnHidden(2, !KGpgSettings::showTrust()); sSize->setChecked(KGpgSettings::showSize()); iview->setColumnHidden(3, !KGpgSettings::showSize()); sCreat->setChecked(KGpgSettings::showCreat()); iview->setColumnHidden(4, !KGpgSettings::showCreat()); sExpi->setChecked(KGpgSettings::showExpi()); iview->setColumnHidden(5, !KGpgSettings::showExpi()); iproxy->setOnlySecret(KGpgSettings::showSecret()); m_statusBarLabel.setAlignment(Qt::AlignCenter); statusBar()->addPermanentWidget(&m_statusBarLabel); cg = KConfigGroup(KSharedConfig::openConfig().data(), "MainWindow"); setAutoSaveSettings(cg, true); applyMainWindowSettings(cg); connect(this, &KeysManager::fontChanged, s_kgpgEditor, &KgpgEditor::slotSetFont); QNetworkConfigurationManager *netmgr = new QNetworkConfigurationManager(this); connect(netmgr, &QNetworkConfigurationManager::onlineStateChanged, this, &KeysManager::toggleNetworkActions); toggleNetworkActions(netmgr->isOnline()); importSignatureKey->setEnabled(false); stateChanged(QStringLiteral("empty_list")); QMetaObject::invokeMethod(this, "refreshkey", Qt::QueuedConnection); } KeysManager::~KeysManager() { } void KeysManager::slotGenerateKey() { if (m_genkey) { KMessageBox::error(this, i18n("Another key generation operation is still in progress.\nPlease wait a moment until this operation is complete."), i18n("Generating new key pair")); return; } QPointer kg = new KgpgKeyGenerate(this); if (kg->exec() == QDialog::Accepted) { if (!kg->isExpertMode()) { KGpgGenerateKey *genkey = new KGpgGenerateKey(this, kg->name(), kg->email(), kg->comment(), kg->algo(), kg->size(), kg->days(), kg->expiration(), kg->caps()); m_genkey = new KGpgTransactionJob(genkey); connect(m_genkey, &KGpgTransactionJob::result, this, &KeysManager::slotGenerateKeyDone); KIO::getJobTracker()->registerJob(m_genkey); m_genkey->start(); QApplication::setOverrideCursor(Qt::BusyCursor); } else { KConfigGroup config(KSharedConfig::openConfig(), "General"); QString terminalApp(config.readPathEntry("TerminalApplication", QLatin1String( "konsole" ))); const QString gpgbin = KGpgSettings::gpgBinaryPath(); QString gpg_args = gpgbin + QLatin1String(" --expert"); if (GPGProc::gpgVersion(GPGProc::gpgVersionString(gpgbin)) > 0x20100) gpg_args += QLatin1String(" --full-gen-key"); else gpg_args += QLatin1String(" --gen-key"); QStringList args; args << QLatin1String( "-e" ) << gpg_args; QProcess *genKeyProc = new QProcess(this); genKeyProc->start(terminalApp, args); if (!genKeyProc->waitForStarted(-1)) { KMessageBox::error(this, i18n("Generating new key pair"), i18n("Can not start \"konsole\" application for expert mode.")); } else { genKeyProc->waitForFinished(-1); refreshkey(); } } } delete kg; } void KeysManager::showKeyManager() { show(); } void KeysManager::slotOpenEditor() { KgpgEditor *kgpgtxtedit = new KgpgEditor(this, imodel, Qt::Window); connect(this, &KeysManager::fontChanged, kgpgtxtedit, &KgpgEditor::slotSetFont); kgpgtxtedit->show(); } void KeysManager::changeMessage(const QString &msg, const bool keep) { int timeout = keep ? 0 : 10000; statusBar()->showMessage(msg, timeout); } void KeysManager::updateStatusCounter() { m_statusBarLabel.setText(imodel->statusCountMessage()); } void KeysManager::slotGenerateKeyDone(KJob *job) { changeMessage(i18nc("Application ready for user input", "Ready")); QApplication::restoreOverrideCursor(); KGpgTransactionJob *tjob = qobject_cast(job); const KGpgGenerateKey * const genkey = qobject_cast(tjob->getTransaction()); int res = tjob->getResultCode(); const QString infomessage(i18n("Generating new key pair")); switch (res) { case KGpgTransaction::TS_BAD_PASSPHRASE: KMessageBox::error(this, i18n("Bad passphrase. Cannot generate a new key pair."), infomessage); break; case KGpgTransaction::TS_USER_ABORTED: KMessageBox::error(this, i18n("Aborted by the user. Cannot generate a new key pair."), infomessage); break; case KGpgTransaction::TS_INVALID_EMAIL: KMessageBox::error(this, i18n("The email address is not valid. Cannot generate a new key pair."), infomessage); break; case KGpgGenerateKey::TS_INVALID_NAME: KMessageBox::error(this, i18n("The name is not accepted by gpg. Cannot generate a new key pair."), infomessage); break; case KGpgTransaction::TS_OK: { updateStatusCounter(); QPointer keyCreated = new QDialog(this); keyCreated->setWindowTitle(i18n("New Key Pair Created")); QVBoxLayout *mainLayout = new QVBoxLayout(keyCreated); keyCreated->setLayout(mainLayout); newKey *page = new newKey(keyCreated); page->TLname->setText(QLatin1String( "" ) + genkey->getName() + QLatin1String( "" )); const QString email(genkey->getEmail()); page->TLemail->setText(QLatin1String( "" ) + email + QLatin1String( "" )); page->kURLRequester1->setUrl(KGpgRevokeDialog::revokeUrl(genkey->getName(), email)); const QString fingerprint(genkey->getFingerprint()); - page->TLid->setText(QLatin1String( "" ) + fingerprint.right(8) + QLatin1String( "" )); + page->TLid->setText(QLatin1String( "" ) % fingerprint.rightRef(8) % QLatin1String( "" )); page->LEfinger->setText(fingerprint); page->CBdefault->setChecked(true); page->show(); mainLayout->addWidget(page); page->buttonBox->button(QDialogButtonBox::Ok)->setShortcut(Qt::CTRL | Qt::Key_Return); connect(page->buttonBox, &QDialogButtonBox::accepted, keyCreated.data(), &QDialog::accept); keyCreated->exec(); if (keyCreated.isNull()) return; imodel->refreshKey(fingerprint); KGpgKeyNode *knode = imodel->getRootNode()->findKey(fingerprint); if (page->CBdefault->isChecked()) imodel->setDefaultKey(knode); iview->selectNode(knode); if (page->CBsave->isChecked() || page->CBprint->isChecked()) { QUrl revurl; if (page->CBsave->isChecked()) revurl = page->kURLRequester1->url(); KGpgGenerateRevoke *genRev = new KGpgGenerateRevoke(this, fingerprint, revurl, 0, i18n("backup copy")); connect(genRev, &KGpgGenerateRevoke::done, this, &KeysManager::slotRevokeGenerated); if (page->CBprint->isChecked()) connect(genRev, &KGpgGenerateRevoke::revokeCertificate, this, &KeysManager::doPrint); genRev->start(); } delete keyCreated; break; } default: KMessageBox::detailedError(this, i18n("gpg process did not finish. Cannot generate a new key pair."), genkey->gpgErrorMessage(), infomessage); } m_genkey = nullptr; } void KeysManager::slotShowTrust() { bool b = !sTrust->isChecked(); iview->setColumnHidden(KEYCOLUMN_TRUST, b); if (!b && (iview->columnWidth(KEYCOLUMN_TRUST) == 0)) iview->resizeColumnToContents(KEYCOLUMN_TRUST); } void KeysManager::slotShowExpiration() { bool b = !sExpi->isChecked(); iview->setColumnHidden(KEYCOLUMN_EXPIR, b); if (!b && (iview->columnWidth(KEYCOLUMN_EXPIR) == 0)) iview->resizeColumnToContents(KEYCOLUMN_EXPIR); } void KeysManager::slotShowSize() { bool b = !sSize->isChecked(); iview->setColumnHidden(KEYCOLUMN_SIZE, b); if (!b && (iview->columnWidth(KEYCOLUMN_SIZE) == 0)) iview->resizeColumnToContents(KEYCOLUMN_SIZE); } void KeysManager::slotShowCreation() { bool b = !sCreat->isChecked(); iview->setColumnHidden(KEYCOLUMN_CREAT, b); if (!b && (iview->columnWidth(KEYCOLUMN_CREAT) == 0)) iview->resizeColumnToContents(KEYCOLUMN_CREAT); } void KeysManager::slotShowLongId(bool b) { iproxy->setIdLength(b ? 16 : 8); } void KeysManager::slotSetTrustFilter(int i) { KgpgCore::KgpgKeyTrustFlag t; Q_ASSERT((i >= 0) && (i < 5)); switch (i) { case 0: t = TRUST_MINIMUM; break; case 1: t = TRUST_UNDEFINED; break; case 2: t = TRUST_MARGINAL; break; case 3: t = TRUST_FULL; break; default: t = TRUST_ULTIMATE; } iproxy->setTrustFilter(t); } bool KeysManager::eventFilter(QObject *, QEvent *e) { if ((e->type() == QEvent::Show) && (showTipOfDay)) { KTipDialog::showTip(this, QLatin1String("kgpg/tips"), false); showTipOfDay = false; } return false; } void KeysManager::slotGotoDefaultKey() { iview->selectNode(imodel->getRootNode()->findKey(KGpgSettings::defaultKey())); } void KeysManager::refreshKeyFromServer() { const auto keysList = iview->selectedNodes(); if (keysList.empty()) return; QStringList keyIDS; for (KGpgNode *item : keysList) { if (item->getType() == ITYPE_GROUP) { for (int j = 0; j < item->getChildCount(); j++) keyIDS << item->getChild(j)->getId(); continue; } if (item->getType() & ITYPE_PAIR) { keyIDS << item->getId(); } else { KMessageBox::sorry(this, i18n("You can only refresh primary keys. Please check your selection.")); return; } } QString proxy; if (KGpgSettings::useProxy()) proxy = QLatin1String( qgetenv("http_proxy") ); KGpgRefreshKeys *t = new KGpgRefreshKeys(this, KGpgSettings::keyServers().first(), keyIDS, true, proxy); connect(t, &KGpgRefreshKeys::done, this, &KeysManager::slotKeyRefreshDone); QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); t->start(); } void KeysManager::slotKeyRefreshDone(int result) { KGpgRefreshKeys *t = qobject_cast(sender()); Q_ASSERT(t != nullptr); if (result == KGpgTransaction::TS_USER_ABORTED) { t->deleteLater(); QApplication::restoreOverrideCursor(); return; } const QStringList log(t->getLog()); const QStringList keys = KGpgImport::getImportedIds(log, 0xffff); const QStringList message(KGpgImport::getImportMessage(log)); t->deleteLater(); if (!keys.empty()) imodel->refreshKeys(keys); QApplication::restoreOverrideCursor(); (void) new KgpgDetailedInfo(this, message.join(QLatin1String("\n")), log.join(QLatin1String("
")), KGpgImport::getDetailedImportMessage(log, imodel).split(QLatin1Char('\n'))); } void KeysManager::slotDelUid() { KGpgUidNode *nd = iview->selectedNode()->toUidNode(); KGpgDelUid *deluid = new KGpgDelUid(this, nd); connect(deluid, &KGpgDelUid::done, this, &KeysManager::slotDelUidDone); deluid->start(); } void KeysManager::slotDelUidDone(int result) { KGpgDelUid * const deluid = qobject_cast(sender()); Q_ASSERT(deluid != nullptr); sender()->deleteLater(); if (result == KGpgTransaction::TS_OK) imodel->refreshKey(deluid->getKeyId()); // FIXME: do something useful with result if it is a failure } void KeysManager::slotPrimUid() { KGpgPrimaryUid *puid = new KGpgPrimaryUid(this, iview->selectedNode()->toUidNode()); connect(puid, &KGpgPrimaryUid::done, this, &KeysManager::slotPrimUidDone); puid->start(); } void KeysManager::slotPrimUidDone(int result) { const QString kid(qobject_cast(sender())->getKeyId()); sender()->deleteLater(); if (result == KGpgTransaction::TS_OK) imodel->refreshKey(kid); // FIXME: some error reporting } void KeysManager::slotregenerate() { QString regID = iview->selectedNode()->getId(); KProcess *p1, *p2, *p3; p1 = new KProcess(this); *p1 << KGpgSettings::gpgBinaryPath() << QLatin1String("--no-secmem-warning") << QLatin1String("--export-secret-key") << regID; p1->setOutputChannelMode(KProcess::OnlyStdoutChannel); p2 = new KProcess(this); *p2 << QLatin1String("gpgsplit") << QLatin1String("--no-split") << QLatin1String("--secret-to-public"); p2->setOutputChannelMode(KProcess::OnlyStdoutChannel); p3 = new KProcess(this); *p3 << KGpgSettings::gpgBinaryPath() << QLatin1String("--import"); p1->setStandardOutputProcess(p2); p2->setStandardOutputProcess(p3); p1->start(); p2->start(); p3->start(); p1->waitForFinished(); p2->waitForFinished(); p3->waitForFinished(); delete p1; delete p2; delete p3; imodel->refreshKey(regID); } void KeysManager::slotAddUid() { if (m_adduid) { KMessageBox::error(this, i18n("Another operation is still in progress.\nPlease wait a moment until this operation is complete."), i18n("Add New User Id")); return; } addUidWidget = new QDialog(this); addUidWidget->setWindowTitle(i18n("Add New User Id")); QVBoxLayout *mainLayout = new QVBoxLayout(addUidWidget); addUidWidget->setLayout(mainLayout); keyUid = new AddUid(addUidWidget); mainLayout->addWidget(keyUid); keyUid->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); keyUid->buttonBox->button(QDialogButtonBox::Ok)->setShortcut(Qt::CTRL | Qt::Key_Return); connect(keyUid->buttonBox, &QDialogButtonBox::accepted, addUidWidget, &QDialog::accept); connect(keyUid->buttonBox, &QDialogButtonBox::rejected, addUidWidget, &QDialog::reject); //keyUid->setMinimumSize(keyUid->sizeHint()); keyUid->setMinimumWidth(300); connect(keyUid->qLineEdit1, &QLineEdit::textChanged, this, &KeysManager::slotAddUidEnable); if (addUidWidget->exec() != QDialog::Accepted) return; m_adduid = new KGpgAddUid(this, iview->selectedNode()->getId(), keyUid->qLineEdit1->text(), keyUid->qLineEdit2->text(), keyUid->qLineEdit3->text()); connect(m_adduid, &KGpgAddUid::done, this, &KeysManager::slotAddUidFin); m_adduid->start(); } void KeysManager::slotAddUidFin(int res) { // TODO error reporting if (res == 0) imodel->refreshKey(m_adduid->getKeyid()); m_adduid->deleteLater(); m_adduid = nullptr; } void KeysManager::slotAddUidEnable(const QString & name) { keyUid->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(name.length() > 4); } void KeysManager::slotAddPhoto() { QString mess = i18n("The image must be a JPEG file. Remember that the image is stored within your public key, so " "if you use a very large picture, your key will become very large as well. The size should not exceed 6 KiB. " "An image size of around 240x288 is a good size to use."); if (KMessageBox::warningContinueCancel(nullptr, mess) != KMessageBox::Continue) return; QString imagepath = QFileDialog::getOpenFileName(nullptr, QString(), QString(), QLatin1String( "image/jpeg" )); if (imagepath.isEmpty()) return; KGpgAddPhoto *addphoto = new KGpgAddPhoto(this, iview->selectedNode()->getId(), imagepath); connect(addphoto, &KGpgAddPhoto::done, this, &KeysManager::slotAddPhotoFinished); addphoto->start(); } void KeysManager::slotAddPhotoFinished(int res) { sender()->deleteLater(); // TODO : add res == 3 (bad passphrase) if (res == 0) slotUpdatePhoto(); } void KeysManager::slotDeletePhoto() { KGpgNode *nd = iview->selectedNode(); KGpgUatNode *und = nd->toUatNode(); KGpgKeyNode *parent = und->getParentKeyNode(); QString mess = i18n("Are you sure you want to delete Photo id %1
from key %2 <%3>?
", und->getId(), parent->getName(), parent->getEmail()); if (KMessageBox::warningContinueCancel(this, mess) != KMessageBox::Continue) return; KGpgDelUid *deluid = new KGpgDelUid(this, und); connect(deluid, &KGpgDelUid::done, this, &KeysManager::slotDelPhotoFinished); deluid->start(); } void KeysManager::slotDelPhotoFinished(int res) { sender()->deleteLater(); // TODO : add res == 3 (bad passphrase) if (res == 0) { KGpgNode *nd = iview->selectedNode(); imodel->refreshKey(nd->getParentKeyNode()->toKeyNode()); } } void KeysManager::slotUpdatePhoto() { KGpgNode *nd = iview->selectedNode(); imodel->refreshKey(nd->toKeyNode()); } void KeysManager::slotSetPhotoSize(int size) { switch(size) { case 1: iproxy->setPreviewSize(22); break; case 2: iproxy->setPreviewSize(42); break; case 3: iproxy->setPreviewSize(65); break; default: iproxy->setPreviewSize(0); break; } } void KeysManager::addToKAB() { KGpgNode *nd = iview->selectedNode(); if (nd == nullptr) return; Akonadi::ContactSearchJob * const job = new Akonadi::ContactSearchJob(); job->setLimit(1); job->setQuery(Akonadi::ContactSearchJob::Email, nd->getEmail()); connect(job, &Akonadi::ContactSearchJob::result, this, &KeysManager::slotAddressbookSearchResult); m_addIds[job] = nd; } void KeysManager::slotAddressbookSearchResult(KJob *job) { KGpgNode * const nd = m_addIds.value(job, 0); if (!nd) return; Akonadi::ContactSearchJob *searchJob = qobject_cast(job); Q_ASSERT(searchJob); const KContacts::Addressee::List addresseeList = searchJob->contacts(); m_addIds.take(job); Akonadi::ContactEditorDialog *dlg; // KContacts::Key key; TODO if (!addresseeList.isEmpty()) { dlg = new Akonadi::ContactEditorDialog(Akonadi::ContactEditorDialog::EditMode, this); dlg->setContact(searchJob->items().at(0)); } else { KContacts::Addressee addressee; addressee.setNameFromString(nd->getName()); addressee.setEmails(QStringList(nd->getEmail())); dlg = new Akonadi::ContactEditorDialog(Akonadi::ContactEditorDialog::CreateMode, this); dlg->editor()->setContactTemplate(addressee); } connect(dlg, &Akonadi::ContactEditorDialog::finished, dlg, &Akonadi::ContactEditorDialog::deleteLater); dlg->show(); } void KeysManager::slotManpage() { KToolInvocation::startServiceByDesktopName(QLatin1String("khelpcenter"), QLatin1String("man:/gpg"), nullptr, nullptr, nullptr, QByteArray(), true); } void KeysManager::slotTip() { KTipDialog::showTip(this, QLatin1String("kgpg/tips"), true); } void KeysManager::showKeyServer() { QPointer ks = new KeyServer(this, imodel); connect(ks.data(), &KeyServer::importFinished, imodel, static_cast(&KGpgItemModel::refreshKeys)); ks->exec(); delete ks; refreshkey(); } void KeysManager::checkList() { const auto exportList = iview->selectedNodes(); switch (exportList.size()) { case 0: stateChanged(QStringLiteral("empty_list")); return; case 1: if (exportList.at(0)->getType() == ITYPE_GROUP) { stateChanged(QLatin1String( "group_selected" )); } else { stateChanged(QLatin1String( "single_selected" )); m_revokeKey->setEnabled(exportList.at(0)->getType() == ITYPE_PAIR); if (terminalkey) editKey->setEnabled(false); m_sendEmail->setEnabled(!exportList[0]->getEmail().isEmpty()); setDefaultKey->setEnabled(!imodel->isDefaultKey(exportList[0])); } break; default: stateChanged(QLatin1String( "multi_selected" )); } if (!m_online) refreshKey->setEnabled(false); switch (exportList.at(0)->getType()) { case ITYPE_PUBLIC: changeMessage(i18n("Public Key")); break; case ITYPE_SUB: changeMessage(i18n("Sub Key")); break; case ITYPE_PAIR: changeMessage(i18n("Secret Key Pair")); break; case ITYPE_GROUP: changeMessage(i18n("Key Group")); break; case ITYPE_SIGN: changeMessage(i18n("Signature")); break; case ITYPE_UID: changeMessage(i18n("User ID")); break; case ITYPE_REVSIGN: changeMessage(i18n("Revocation Signature")); break; case ITYPE_UAT: changeMessage(i18n("Photo ID")); break; case ITYPE_SECRET: changeMessage(i18n("Orphaned Secret Key")); break; case ITYPE_GPUBLIC: case ITYPE_GSECRET: case ITYPE_GPAIR: changeMessage(i18n("Group member")); break; default: qCDebug(KGPG_LOG_GENERAL) << "Oops, unmatched type value" << exportList.at(0)->getType(); } } void KeysManager::quitApp() { // close window saveToggleOpts(); qApp->quit(); } void KeysManager::saveToggleOpts(void) { KConfigGroup cg = KConfigGroup(KSharedConfig::openConfig().data(), "KeyView"); iview->saveLayout(cg); KGpgSettings::setPhotoProperties(photoProps->currentItem()); KGpgSettings::setShowTrust(sTrust->isChecked()); KGpgSettings::setShowExpi(sExpi->isChecked()); KGpgSettings::setShowCreat(sCreat->isChecked()); KGpgSettings::setShowSize(sSize->isChecked()); KGpgSettings::setTrustLevel(trustProps->currentItem()); KGpgSettings::setShowSecret(hPublic->isChecked()); KGpgSettings::setShowLongKeyId(longId->isChecked()); KGpgSettings::self()->save(); } void KeysManager::readOptions() { m_clipboardmode = QClipboard::Clipboard; if (KGpgSettings::useMouseSelection() && (qApp->clipboard()->supportsSelection())) m_clipboardmode = QClipboard::Selection; if (imodel != nullptr) updateStatusCounter(); showTipOfDay = KGpgSettings::showTipOfDay(); if (KGpgSettings::showSystray()) { setupTrayIcon(); } else { delete m_trayicon; m_trayicon = nullptr; } } void KeysManager::showOptions() { if (KConfigDialog::showDialog(QLatin1String( "settings" ))) return; QPointer optionsDialog = new kgpgOptions(this, imodel); connect(optionsDialog.data(), &kgpgOptions::settingsUpdated, this, &KeysManager::readAllOptions); connect(optionsDialog.data(), &kgpgOptions::homeChanged, imodel, &KGpgItemModel::refreshAllKeys); connect(optionsDialog.data(), &kgpgOptions::homeChanged, imodel, &KGpgItemModel::refreshGroups); connect(optionsDialog.data(), &kgpgOptions::refreshTrust, imodel, &KGpgItemModel::refreshTrust); connect(optionsDialog.data(), &kgpgOptions::changeFont, this, &KeysManager::fontChanged); optionsDialog->exec(); delete optionsDialog; s_kgpgEditor->m_recentfiles->setMaxItems(KGpgSettings::recentFiles()); } void KeysManager::readAllOptions() { readOptions(); emit readAgainOptions(); } void KeysManager::slotSetDefKey() { setDefaultKeyNode(iview->selectedNode()->toKeyNode()); } void KeysManager::slotSetDefaultKey(const QString &newID) { KGpgKeyNode *ndef = imodel->getRootNode()->findKey(newID); if (ndef == nullptr) { KGpgSettings::setDefaultKey(newID); KGpgSettings::self()->save(); return; } setDefaultKeyNode(ndef); } void KeysManager::setDefaultKeyNode(KGpgKeyNode *key) { const QString &newID(key->getId()); if (newID == KGpgSettings::defaultKey()) return; KGpgSettings::setDefaultKey(newID); KGpgSettings::self()->save(); imodel->setDefaultKey(key); } void KeysManager::setActionDescriptions(int cnt) { signUid->setText(i18np("&Sign User ID ...", "&Sign User IDs ...", cnt)); signMailUid->setText(i18np("Sign and &Mail User ID ...", "Sign and &Mail User IDs ...", cnt)); exportPublicKey->setText(i18np("E&xport Public Key...", "E&xport Public Keys...", cnt)); refreshKey->setText(i18np("&Refresh Key From Keyserver", "&Refresh Keys From Keyserver", cnt)); createGroup->setText(i18np("&Create Group with Selected Key...", "&Create Group with Selected Keys...", cnt)); signKey->setText(i18np("&Sign Key...", "&Sign Keys...", cnt)); delUid->setText(i18np("&Delete User ID", "&Delete User IDs", cnt)); delSignKey->setText(i18np("Delete Sign&ature", "Delete Sign&atures", cnt)); importSignatureKey->setText(i18np("Import Key From Keyserver", "Import Keys From Keyserver", cnt)); deleteKey->setText(i18np("&Delete Key", "&Delete Keys", cnt)); } void KeysManager::slotMenu(const QPoint &pos) { QPoint globpos = iview->mapToGlobal(pos); bool sametype; KgpgItemType itype; const auto ndlist = iview->selectedNodes(&sametype, &itype); bool unksig = false; QSet l; const int cnt = ndlist.size(); // find out if an item has unknown signatures. Only check if the item has been // expanded before as expansion is very expensive and can take several seconds // that will freeze the UI meanwhile. for (KGpgNode *nd : ndlist) { if (!nd->hasChildren()) continue; KGpgExpandableNode *exnd = nd->toExpandableNode(); if (!exnd->wasExpanded()) { unksig = true; break; } getMissingSigs(l, exnd); if (!l.isEmpty()) { unksig = true; break; } } importAllSignKeys->setEnabled(unksig && m_online); signUid->setEnabled(!(itype & ~(ITYPE_PAIR | ITYPE_UID | ITYPE_UAT))); signMailUid->setEnabled(signUid->isEnabled()); setActionDescriptions(cnt); if (itype == ITYPE_SIGN) { bool allunksig = true; for (KGpgNode *nd : ndlist) { allunksig = nd->toSignNode()->isUnknown(); if (!allunksig) break; } importSignatureKey->setEnabled(allunksig && m_online); delSignKey->setEnabled( (cnt == 1) ); m_popupsig->exec(globpos); } else if (itype == ITYPE_UID) { if (cnt == 1) { KGpgKeyNode *knd = ndlist.at(0)->toUidNode()->getParentKeyNode(); setPrimUid->setEnabled(knd->getType() & ITYPE_SECRET); } m_popupuid->exec(globpos); } else if ((itype == ITYPE_UAT) && (cnt == 1)) { m_popupphoto->exec(globpos); } else if ((itype == ITYPE_PAIR) && (cnt == 1)) { m_popupsec->exec(globpos); } else if ((itype == ITYPE_SECRET) && (cnt == 1)) { m_popuporphan->exec(globpos); } else if (itype == ITYPE_GROUP) { delGroup->setEnabled( (cnt == 1) ); editCurrentGroup->setEnabled( (cnt == 1) ); m_groupRename->setEnabled( (cnt == 1) ); m_popupgroup->exec(globpos); } else if (!(itype & ~(ITYPE_PAIR | ITYPE_GROUP))) { signKey->setEnabled(!(itype & ITYPE_GROUP)); deleteKey->setEnabled(!(itype & ITYPE_GROUP)); setDefaultKey->setEnabled( (cnt == 1) ); m_popuppub->exec(globpos); } else if (!(itype & ~(ITYPE_UID | ITYPE_PAIR | ITYPE_UAT))) { setPrimUid->setEnabled(false); delUid->setEnabled(false); m_popupuid->exec(globpos); } else { m_popupout->exec(globpos); } } void KeysManager::revokeWidget() { KGpgNode *nd = iview->selectedNode(); QDialog *keyRevokeDialog = new KGpgRevokeDialog(this, nd->toKeyNode()); connect(keyRevokeDialog, &QDialog::finished, this, &KeysManager::slotRevokeDialogFinished); keyRevokeDialog->open(); } void KeysManager::slotRevokeDialogFinished(int result) { sender()->deleteLater(); if (result != QDialog::Accepted) return; KGpgRevokeDialog *keyRevokeDialog = qobject_cast(sender()); KGpgGenerateRevoke *genRev = new KGpgGenerateRevoke(this, keyRevokeDialog->getId(), keyRevokeDialog->saveUrl(), keyRevokeDialog->getReason(), keyRevokeDialog->getDescription()); connect(genRev, &KGpgGenerateRevoke::done, this, &KeysManager::slotRevokeGenerated); if (keyRevokeDialog->printChecked()) connect(genRev, &KGpgGenerateRevoke::revokeCertificate, this, &KeysManager::doPrint); if (keyRevokeDialog->importChecked()) connect(genRev, &KGpgGenerateRevoke::revokeCertificate, this, &KeysManager::slotImportRevokeTxt); genRev->start(); } void KeysManager::slotRevokeGenerated(int result) { KGpgGenerateRevoke *genRev = qobject_cast(sender()); genRev->deleteLater(); switch (result) { case KGpgTransaction::TS_OK: case KGpgTransaction::TS_USER_ABORTED: break; default: KMessageBox::detailedSorry(this, i18n("Creation of the revocation certificate failed..."), genRev->getOutput()); break; } } void KeysManager::slotImportRevokeTxt(const QString &revokeText) { KGpgImport *import = new KGpgImport(this, revokeText); connect(import, &KGpgImport::done, this, &KeysManager::slotImportDone); import->start(); } void KeysManager::slotexportsec() { // export secret key const QString warn(i18n("Secret keys should not be saved in an unsafe place.
" "If someone else can access this file, encryption with this key will be compromised.
Continue key export?
")); int result = KMessageBox::warningContinueCancel(this, warn); if (result != KMessageBox::Continue) return; KGpgNode *nd = iview->selectedNode(); QString sname(nd->getEmail().section(QLatin1Char( '@' ), 0, 0).section(QLatin1Char( '.' ), 0, 0)); if (sname.isEmpty()) sname = nd->getName().section(QLatin1Char( ' ' ), 0, 0); sname.append(QLatin1String( ".asc" )); sname.prepend(QDir::homePath() + QLatin1Char( '/' )); QUrl url(QFileDialog::getSaveFileUrl(this, i18n("Export PRIVATE KEY As"), QUrl(sname), i18n( "*.asc|*.asc Files" ))); if(!url.isEmpty()) { KGpgExport *exp = new KGpgExport(this, QStringList(nd->getId()), url.path(), QStringList(QLatin1String( "--armor" )), true); connect(exp, &KGpgExport::done, this, &KeysManager::slotExportSecFinished); exp->start(); } } void KeysManager::slotExportSecFinished(int result) { KGpgExport *exp = qobject_cast(sender()); Q_ASSERT(exp != nullptr); if (result == KGpgTransaction::TS_OK) { KMessageBox::information(this, i18n("Your private key \"%1\" was successfully exported to
%2.
Do not leave it in an insecure place.
", exp->getKeyIds().first(), exp->getOutputFile())); } else { KMessageBox::sorry(this, i18n("Your secret key could not be exported.\nCheck the key.")); } } void KeysManager::slotexport() { bool same; KgpgItemType tp; const auto ndlist = iview->selectedNodes(&same, &tp); if (ndlist.empty()) return; if (!(tp & ITYPE_PUBLIC) || (tp & ~ITYPE_GPAIR)) return; QString sname; if (ndlist.size() == 1) { sname = ndlist.at(0)->getEmail().section(QLatin1Char( '@' ), 0, 0).section(QLatin1Char( '.' ), 0, 0); if (sname.isEmpty()) sname = ndlist.at(0)->getName().section(QLatin1Char(' '), 0, 0); } else sname = QLatin1String( "keyring" ); QStringList klist; for (const auto k : ndlist) klist << k->getId(); sname.append(QLatin1String( ".asc" )); sname.prepend(QDir::homePath() + QLatin1Char( '/' )); QStringList serverList(KGpgSettings::keyServers()); serverList.replaceInStrings(QRegExp(QLatin1String(" .*")), QString()); // Remove kde 3.5 (Default) tag. if (!serverList.isEmpty()) { QString defaultServer = serverList.takeFirst(); std::sort(serverList.begin(), serverList.end()); serverList.prepend(defaultServer); } QPointer page = new KeyExport(this, serverList); page->newFilename->setUrl(QUrl(sname)); if (!m_online) page->checkServer->setEnabled(false); if (page->exec() == QDialog::Accepted) { // export to file QString exportAttr; if (page->checkAttrAll->isChecked()) { // nothing } else if (page->checkAttrPhoto->isChecked()) { exportAttr = QLatin1String( "no-export-attributes" ); } else { exportAttr = QLatin1String( "export-minimal" ); } QStringList expopts; if (!exportAttr.isEmpty()) expopts << QLatin1String( "--export-options" ) << exportAttr; if (page->checkServer->isChecked()) { KeyServer *expServer = new KeyServer(0, imodel); expServer->slotSetExportAttribute(exportAttr); expServer->slotSetKeyserver(page->destServer->currentText()); expServer->slotExport(klist); } else if (page->checkFile->isChecked()) { const QString expname(page->newFilename->url().path().simplified()); if (!expname.isEmpty()) { expopts.append(QLatin1String( "--armor" )); KGpgExport *exp = new KGpgExport(this, klist, expname, expopts); connect(exp, &KGpgExport::done, this, &KeysManager::slotExportFinished); exp->start(); } } else { KGpgExport *exp = new KGpgExport(this, klist, expopts); if (page->checkClipboard->isChecked()) connect(exp, &KGpgExport::done, this, &KeysManager::slotProcessExportClip); else connect(exp, &KGpgExport::done, this, &KeysManager::slotProcessExportMail); exp->start(); } } delete page; } void KeysManager::slotExportFinished(int result) { KGpgExport *exp = qobject_cast(sender()); Q_ASSERT(exp != nullptr); if (result == KGpgTransaction::TS_OK) { KMessageBox::information(this, i18np("The public key was successfully exported to
%2
", "The %1 public keys were successfully exported to
%2
", exp->getKeyIds().count(), exp->getOutputFile())); } else { KMessageBox::sorry(this, i18n("Your public key could not be exported\nCheck the key.")); } exp->deleteLater(); } void KeysManager::slotProcessExportMail(int result) { KGpgExport *exp = qobject_cast(sender()); Q_ASSERT(exp != nullptr); // start default Mail application if (result == KGpgTransaction::TS_OK) { QDesktopServices::openUrl(QUrl(QLatin1String("mailto:?body=") + QLatin1String(exp->getOutputData()))); } else { KMessageBox::sorry(this, i18n("Your public key could not be exported\nCheck the key.")); } exp->deleteLater(); } void KeysManager::slotProcessExportClip(int result) { KGpgExport *exp = qobject_cast(sender()); Q_ASSERT(exp != nullptr); if (result == KGpgTransaction::TS_OK) { qApp->clipboard()->setText(QLatin1String( exp->getOutputData() ), m_clipboardmode); } else { KMessageBox::sorry(this, i18n("Your public key could not be exported\nCheck the key.")); } exp->deleteLater(); } void KeysManager::showKeyInfo(const QString &keyID) { KGpgKeyNode *key = imodel->getRootNode()->findKey(keyID); if (key == nullptr) return; showProperties(key); } void KeysManager::slotShowPhoto() { const KService::List list = KMimeTypeTrader::self()->query(QLatin1String("image/jpeg")); if (list.isEmpty()) { KMessageBox::sorry(nullptr, i18n("A viewer for JPEG images is not specified.
Please check your installation.
"), i18n("Show photo")); return; } KGpgNode *nd = iview->selectedNode(); KGpgUatNode *und = nd->toUatNode(); KGpgKeyNode *parent = und->getParentKeyNode(); KService::Ptr ptr = list.first(); KProcess p; p << KGpgSettings::gpgBinaryPath() << QLatin1String("--no-tty") << QLatin1String("--photo-viewer") << (ptr->desktopEntryName() + QLatin1String( " %i" )) << QLatin1String("--edit-key") << parent->getId() << QLatin1String("uid") << und->getId() << QLatin1String("showphoto") << QLatin1String("quit"); p.startDetached(); } void KeysManager::defaultAction(const QModelIndex &index) { KGpgNode *nd = iproxy->nodeForIndex(index); defaultAction(nd); } void KeysManager::slotDefaultAction() { defaultAction(iview->selectedNode()); } void KeysManager::defaultAction(KGpgNode *nd) { if (nd == nullptr) return; if (iview->isEditing()) return; switch (nd->getType()) { case ITYPE_GROUP: editGroup(); break; case ITYPE_UAT: slotShowPhoto(); break; case ITYPE_SIGN: case ITYPE_GPUBLIC: case ITYPE_GSECRET: case ITYPE_GPAIR: iview->selectNode(nd->toRefNode()->getRefNode()); break; case ITYPE_SECRET: slotregenerate(); break; case ITYPE_PAIR: case ITYPE_PUBLIC: showProperties(nd); return; } } void KeysManager::showProperties(KGpgNode *n) { switch (n->getType()) { case ITYPE_UAT: return; case ITYPE_PUBLIC: case ITYPE_PAIR: { KGpgKeyNode *k = n->toKeyNode(); QPointer opts = new KgpgKeyInfo(k, imodel, this); connect(opts.data(), &KgpgKeyInfo::keyNeedsRefresh, imodel, static_cast(&KGpgItemModel::refreshKey)); connect(opts->keychange, &KGpgChangeKey::keyNeedsRefresh, imodel, static_cast(&KGpgItemModel::refreshKey)); opts->exec(); delete opts; } default: return; } } void KeysManager::keyproperties() { KGpgNode *cur = iview->selectedNode(); if (cur == nullptr) return; KGpgKeyNode *kn; switch (cur->getType()) { case ITYPE_SECRET: case ITYPE_GSECRET: if (KMessageBox::questionYesNo(this, i18n("

This key is an orphaned secret key (secret key without public key.) It is currently not usable.

" "

Would you like to regenerate the public key?

"), QString(), KGuiItem(i18n("Generate")), KGuiItem(i18n("Do Not Generate"))) == KMessageBox::Yes) slotregenerate(); return; case ITYPE_PAIR: case ITYPE_PUBLIC: { kn = cur->toKeyNode(); break; } case ITYPE_GPAIR: case ITYPE_GPUBLIC: { kn = cur->toGroupMemberNode()->getRefNode(); break; } default: qCDebug(KGPG_LOG_GENERAL) << "Oops, called with invalid item type" << cur->getType(); return; } QPointer opts = new KgpgKeyInfo(kn, imodel, this); connect(opts.data(), &KgpgKeyInfo::keyNeedsRefresh, imodel, static_cast(&KGpgItemModel::refreshKey)); opts->exec(); delete opts; } void KeysManager::deleteGroup() { KGpgNode *nd = iview->selectedNode(); if (!nd || (nd->getType() != ITYPE_GROUP)) return; int result = KMessageBox::warningContinueCancel(this, i18n("Are you sure you want to delete group %1 ?", nd->getName()), QString(), KGuiItem(i18n("Delete"), QLatin1String("edit-delete"))); if (result != KMessageBox::Continue) return; nd->toGroupNode()->remove(); imodel->delNode(nd); updateStatusCounter(); } void KeysManager::renameGroup() { if (iview->selectionModel()->selectedIndexes().isEmpty()) return; QModelIndex selectedNodeIndex = iview->selectionModel()->selectedIndexes().at(0); iview->edit(selectedNodeIndex); } void KeysManager::createNewGroup() { QStringList badkeys; KGpgKeyNode::List keysList; KgpgItemType tp; const auto ndlist = iview->selectedNodes(nullptr, &tp); if (ndlist.empty()) return; if (tp & ~ITYPE_PAIR) { KMessageBox::sorry(this, i18n("You cannot create a group containing signatures, subkeys or other groups.")); return; } KgpgKeyTrustFlag mintrust; if (KGpgSettings::allowUntrustedGroupMembers()) { mintrust = KgpgCore::TRUST_UNDEFINED; } else { mintrust = KgpgCore::TRUST_FULL; } for (KGpgNode *nd : ndlist) { if (nd->getTrust() >= mintrust) { keysList.append(nd->toKeyNode()); } else { badkeys += i18nc(" () ID: ", "%1 (%2) ID: %3", nd->getName(), nd->getEmail(), nd->getId()); } } QString groupName(QInputDialog::getText(this, i18n("Create New Group"), i18nc("Enter the name of the group you are creating now", "Enter new group name:"))); if (groupName.isEmpty()) return; if (!keysList.isEmpty()) { if (!badkeys.isEmpty()) KMessageBox::informationList(this, i18n("Following keys are not valid or not trusted and will not be added to the group:"), badkeys); iview->selectNode(imodel->addGroup(groupName, keysList)); updateStatusCounter(); } else { KMessageBox::sorry(this, i18n("No valid or trusted key was selected. The group %1 will not be created.", groupName)); } } void KeysManager::editGroup() { KGpgNode *nd = iview->selectedNode(); if (!nd || (nd->getType() != ITYPE_GROUP)) return; KGpgGroupNode *gnd = nd->toGroupNode(); QPointer dialogGroupEdit = new QDialog(this ); dialogGroupEdit->setWindowTitle(i18n("Group Properties")); QVBoxLayout *mainLayout = new QVBoxLayout(dialogGroupEdit); QWidget *mainWidget = new QWidget(this); mainLayout->addWidget(mainWidget); dialogGroupEdit->setLayout(mainLayout); QList members(gnd->getChildren()); groupEdit *gEdit = new groupEdit(dialogGroupEdit, &members, imodel); mainLayout->addWidget(gEdit); gEdit->buttonBox->button(QDialogButtonBox::Ok)->setShortcut(Qt::CTRL | Qt::Key_Return); connect(gEdit->buttonBox, &QDialogButtonBox::accepted, dialogGroupEdit.data(), &QDialog::accept); connect(gEdit->buttonBox, &QDialogButtonBox::rejected, dialogGroupEdit.data(), &QDialog::reject); gEdit->show(); if (dialogGroupEdit->exec() == QDialog::Accepted) imodel->changeGroup(gnd, members); delete dialogGroupEdit; } void KeysManager::signkey() { // another sign operation is still running if (!signList.isEmpty()) return; KgpgItemType tp; const auto tmplist = iview->selectedNodes(nullptr, &tp); if (tmplist.empty()) return; if (tp & ~ITYPE_PAIR) { KMessageBox::sorry(this, i18n("You can only sign primary keys. Please check your selection.")); return; } if (tmplist.size() == 1) { KGpgKeyNode *nd = tmplist.at(0)->toKeyNode(); QString opt; if (nd->getEmail().isEmpty()) opt = i18n("You are about to sign key:

%1
ID: %2
Fingerprint:
%3.

" "You should check the key fingerprint by phoning or meeting the key owner to be sure that someone " "is not trying to intercept your communications.
", nd->getName(), nd->getId().right(8), nd->getBeautifiedFingerprint()); else opt = i18n("You are about to sign key:

%1 (%2)
ID: %3
Fingerprint:
%4.

" "You should check the key fingerprint by phoning or meeting the key owner to be sure that someone " "is not trying to intercept your communications.
", nd->getName(), nd->getEmail(), nd->getId().right(8), nd->getBeautifiedFingerprint()); if (KMessageBox::warningContinueCancel(this, opt) != KMessageBox::Continue) { return; } signList.append(nd); } else { QStringList signKeyList; for (KGpgNode *n : tmplist) { const KGpgKeyNode *nd = n->toKeyNode(); if (nd->getEmail().isEmpty()) signKeyList += i18nc("Name: ID", "%1: %2", nd->getName(), nd->getBeautifiedFingerprint()); else signKeyList += i18nc("Name (Email): ID", "%1 (%2): %3", nd->getName(), nd->getEmail(), nd->getBeautifiedFingerprint()); signList.append(n->toSignableNode()); } if (KMessageBox::Continue != KMessageBox::warningContinueCancelList(this, i18n("You are about to sign the following keys in one pass.
If you have not carefully checked all fingerprints," " the security of your communications may be compromised.
"), signKeyList)) return; } QPointer opts = new KgpgSelectSecretKey(this, imodel, signList.count()); if (opts->exec() != QDialog::Accepted) { delete opts; signList.clear(); return; } globalkeyID = QString(opts->getKeyID()); const bool localsign = opts->isLocalSign(); const int checklevel = opts->getSignTrust(); bool isterminal = opts->isTerminalSign(); delete opts; if (isterminal) { const QString keyid(signList.at(0)->getId()); signList.clear(); signKeyOpenConsole(globalkeyID, keyid, checklevel, localsign); } else { keyCount = 0; m_signuids = false; signLoop(localsign, checklevel); } } void KeysManager::signuid() { // another sign operation is still running if (!signList.isEmpty()) return; KgpgItemType tp; const auto tmplist = iview->selectedNodes(nullptr, &tp); if (tmplist.empty()) return; if (tp & ~(ITYPE_PAIR | ITYPE_UID | ITYPE_UAT)) { KMessageBox::sorry(this, i18n("You can only sign user ids and photo ids. Please check your selection.")); return; } if (tmplist.size() == 1) { KGpgSignableNode *nd = tmplist.at(0)->toSignableNode(); KGpgKeyNode *pnd; if (tp & ITYPE_PUBLIC) pnd = nd->toKeyNode(); else pnd = nd->getParentKeyNode()->toKeyNode(); QString opt; if (nd->getEmail().isEmpty()) opt = i18n("You are about to sign user id:

%1
ID: %2
Fingerprint:
%3.

" "You should check the key fingerprint by phoning or meeting the key owner to be sure that someone " "is not trying to intercept your communications.
", nd->getName(), nd->getId(), pnd->getBeautifiedFingerprint()); else opt = i18n("You are about to sign user id:

%1 (%2)
ID: %3
Fingerprint:
%4.

" "You should check the key fingerprint by phoning or meeting the key owner to be sure that someone " "is not trying to intercept your communications.
", nd->getName(), nd->getEmail(), nd->getId(), pnd->getBeautifiedFingerprint()); if (KMessageBox::warningContinueCancel(this, opt) != KMessageBox::Continue) { return; } signList.append(nd); } else { QStringList signKeyList; for (KGpgNode *nd : tmplist) { const KGpgKeyNode *pnd = (nd->getType() & (ITYPE_UID | ITYPE_UAT)) ? nd->getParentKeyNode()->toKeyNode() : nd->toKeyNode(); if (nd->getEmail().isEmpty()) signKeyList += i18nc("Name: ID", "%1: %2", nd->getName(), pnd->getBeautifiedFingerprint()); else signKeyList += i18nc("Name (Email): ID", "%1 (%2): %3", nd->getName(), nd->getEmail(), pnd->getBeautifiedFingerprint()); signList.append(nd->toSignableNode()); } if (KMessageBox::warningContinueCancelList(this, i18n("You are about to sign the following user ids in one pass.
If you have not carefully checked all fingerprints," " the security of your communications may be compromised.
"), signKeyList) != KMessageBox::Continue) return; } QPointer opts = new KgpgSelectSecretKey(this, imodel, signList.count()); if (opts->exec() != QDialog::Accepted) { delete opts; signList.clear(); return; } globalkeyID = QString(opts->getKeyID()); const bool localsign = opts->isLocalSign(); const int checklevel = opts->getSignTrust(); bool isterminal = opts->isTerminalSign(); delete opts; if (isterminal) { const QString keyid(signList.at(0)->getId()); signList.clear(); signKeyOpenConsole(globalkeyID, keyid, checklevel, localsign); } else { keyCount = 0; m_signuids = true; signLoop(localsign, checklevel); } } void KeysManager::signLoop(const bool localsign, const int checklevel) { Q_ASSERT(keyCount < signList.count()); KGpgSignableNode *nd = signList.at(keyCount); QString uid; QString keyid; const KGpgSignTransactionHelper::carefulCheck cc = static_cast(checklevel); KGpgTransaction *sta; if (m_signuids) { sta = new KGpgSignUid(this, globalkeyID, nd, localsign, cc); } else { sta = new KGpgSignKey(this, globalkeyID, nd->toKeyNode(), localsign, cc); } connect(sta, &KGpgTransaction::done, this, &KeysManager::signatureResult); sta->start(); } void KeysManager::signatureResult(int success) { KGpgSignTransactionHelper *ta; KGpgSignUid *suid = qobject_cast(sender()); if (suid != nullptr) { ta = static_cast(suid); } else { ta = static_cast(static_cast(sender())); } KGpgKeyNode *nd = const_cast(ta->getKey()); const bool localsign = ta->getLocal(); const int checklevel = ta->getChecking(); const QString signer(ta->getSigner()); sender()->deleteLater(); switch (success) { case KGpgTransaction::TS_OK: if (refreshList.indexOf(nd) == -1) refreshList.append(nd); break; case KGpgTransaction::TS_BAD_PASSPHRASE: KMessageBox::sorry(this, i18n("Bad passphrase, key %1 (%2) not signed.", nd->getName(), nd->getEmail())); break; case KGpgSignTransactionHelper::TS_ALREADY_SIGNED: KMessageBox::sorry(this, i18n("The key %1 (%2) is already signed.", nd->getName(), nd->getEmail())); break; default: if (KMessageBox::questionYesNo(this, i18n("Signing key %1 with key %2 failed.
" "Do you want to try signing the key in console mode?
", nd->getId(), signer)) == KMessageBox::Yes) signKeyOpenConsole(signer, nd->getId(), checklevel, localsign); } if (++keyCount == signList.count()) { signList.clear(); if (!refreshList.isEmpty()) imodel->refreshKeys(refreshList); refreshList.clear(); } else { signLoop(localsign, checklevel); } } void KeysManager::caff() { KgpgItemType tp; const auto tmplist = iview->selectedNodes(nullptr, &tp); KGpgSignableNode::List slist; if (tmplist.empty()) return; if (tp & ~(ITYPE_PAIR | ITYPE_UID | ITYPE_UAT)) { KMessageBox::sorry(this, i18n("You can only sign user ids and photo ids. Please check your selection.")); return; } for (KGpgNode *nd : tmplist) { switch (nd->getType()) { case KgpgCore::ITYPE_PAIR: case KgpgCore::ITYPE_PUBLIC: { KGpgKeyNode *knd = qobject_cast(nd); if (!knd->wasExpanded()) knd->getChildCount(); } } slist.append(nd->toSignableNode()); } QPointer opts = new KgpgSelectSecretKey(this, imodel, slist.count(), false, false); if (opts->exec() != QDialog::Accepted) { delete opts; return; } KGpgCaff *ca = new KGpgCaff(this, slist, QStringList(opts->getKeyID()), opts->getSignTrust(), KGpgCaff::IgnoreAlreadySigned); delete opts; connect(ca, &KGpgCaff::done, this, &KeysManager::slotCaffDone); connect(ca, &KGpgCaff::aborted, this, &KeysManager::slotCaffDone); ca->run(); } void KeysManager::slotCaffDone() { Q_ASSERT(qobject_cast(sender()) != nullptr); sender()->deleteLater(); } void KeysManager::signKeyOpenConsole(const QString &signer, const QString &keyid, const int checking, const bool local) { KConfigGroup config(KSharedConfig::openConfig(), "General"); KProcess process; process << config.readPathEntry("TerminalApplication", QLatin1String("konsole")) << QLatin1String("-e") << KGpgSettings::gpgBinaryPath() << QLatin1String("--no-secmem-warning") << QLatin1String("-u") << signer << QLatin1String("--default-cert-level") << QString(checking); if (!local) process << QLatin1String( "--sign-key" ) << keyid; else process << QLatin1String( "--lsign-key" ) << keyid; process.execute(); } void KeysManager::getMissingSigs(QSet &missingKeys, const KGpgExpandableNode *nd) { for (const KGpgNode *ch : nd->getChildren()) { if (ch->hasChildren()) { getMissingSigs(missingKeys, ch->toExpandableNode()); continue; } else if (ch->getType() == ITYPE_SIGN) { if (ch->toSignNode()->isUnknown()) missingKeys << ch->getId(); } } } void KeysManager::importallsignkey() { const auto sel = iview->selectedNodes(); QSet missingKeys; if (sel.empty()) return; for (const KGpgNode *nd : sel) { if (nd->hasChildren()) { getMissingSigs(missingKeys, nd->toExpandableNode()); } else if (nd->getType() == ITYPE_SIGN) { const KGpgSignNode *sn = nd->toSignNode(); if (sn->isUnknown()) missingKeys << sn->getId(); } } if (missingKeys.isEmpty()) { KMessageBox::information(this, i18np("All signatures for this key are already in your keyring", "All signatures for this keys are already in your keyring", sel.size())); return; } importRemoteKeys(missingKeys.toList()); } void KeysManager::preimportsignkey() { const auto exportList = iview->selectedNodes(); QStringList idlist; if (exportList.empty()) return; for (const KGpgNode *nd : exportList) idlist << nd->getId(); importRemoteKeys(idlist); } bool KeysManager::importRemoteKey(const QString &keyIDs) { return importRemoteKeys(keyIDs.simplified().split(QLatin1Char( ' ' )), false); } bool KeysManager::importRemoteKeys(const QStringList &keyIDs, const bool dialog) { const QStringList kservers = KeyServer::getServerList(); if (kservers.isEmpty()) return false; KGpgReceiveKeys *proc = new KGpgReceiveKeys(this, kservers.first(), keyIDs, dialog, QLatin1String( qgetenv("http_proxy") )); connect(proc, &KGpgReceiveKeys::done, this, &KeysManager::importRemoteFinished); proc->start(); return true; } void KeysManager::importRemoteFinished(int result) { KGpgReceiveKeys *t = qobject_cast(sender()); Q_ASSERT(t != nullptr); const QStringList keys = KGpgImport::getImportedIds(t->getLog()); t->deleteLater(); if ((result == KGpgTransaction::TS_OK) && !keys.isEmpty()) imodel->refreshKeys(keys); } void KeysManager::delsignkey() { KGpgNode *nd = iview->selectedNode(); if (nd == nullptr) return; QString uid; QString parentKey; KGpgExpandableNode *parent = nd->getParentKeyNode(); switch (parent->getType()) { case ITYPE_PAIR: case ITYPE_PUBLIC: uid = QLatin1Char( '1' ); parentKey = parent->getId(); break; case ITYPE_UID: case ITYPE_UAT: uid = parent->getId(); parentKey = parent->getParentKeyNode()->getId(); break; default: Q_ASSERT(0); return; } const QString signID(nd->getId()); QString signMail(nd->getNameComment()); QString parentMail(parent->getNameComment()); if (!parent->getEmail().isEmpty()) parentMail += QLatin1String( " <" ) + parent->getEmail() + QLatin1String( ">" ); if (!nd->getEmail().isEmpty()) signMail += QLatin1String( " <" ) + nd->getEmail() + QLatin1String( ">" ); if (parentKey == signID) { KMessageBox::sorry(this, i18n("Edit key manually to delete a self-signature.")); return; } QString ask = i18n("Are you sure you want to delete signature
%1
from user id %2
of key: %3?
", signMail, parentMail, parentKey); if (KMessageBox::questionYesNo(this, ask, QString(), KStandardGuiItem::del(), KStandardGuiItem::cancel()) != KMessageBox::Yes) return; KGpgDelSign *delsig = new KGpgDelSign(this, nd->toSignNode()); connect(delsig, &KGpgDelSign::done, this, &KeysManager::delsignatureResult); delsig->start(); } void KeysManager::delsignatureResult(int success) { sender()->deleteLater(); if (success == KGpgTransaction::TS_OK) { KGpgNode *nd = iview->selectedNode()->getParentKeyNode(); while (!(nd->getType() & ITYPE_PAIR)) nd = nd->getParentKeyNode(); imodel->refreshKey(nd->toKeyNode()); } else { KMessageBox::sorry(this, i18n("Requested operation was unsuccessful, please edit the key manually.")); } } void KeysManager::slotSendEmail() { QStringList maillist; const auto nodes = iview->selectedNodes(); for (const KGpgNode *nd : nodes) { if (nd->getEmail().isEmpty()) continue; maillist << QLatin1Char('"') + nd->getName() + QLatin1String("\" <") + nd->getEmail() + QLatin1Char('>'); } if (maillist.isEmpty()) return; QDesktopServices::openUrl(QUrl(QLatin1String("mailto:") + maillist.join(QLatin1String(", ")))); } void KeysManager::slotedit() { KGpgNode *nd = iview->selectedNode(); Q_ASSERT(nd != nullptr); if (!(nd->getType() & ITYPE_PAIR)) return; if (terminalkey) return; if ((m_delkey != nullptr) && m_delkey->keys.contains(nd->toKeyNode())) return; KProcess *kp = new KProcess(this); KConfigGroup config(KSharedConfig::openConfig(), "General"); *kp << config.readPathEntry("TerminalApplication", QLatin1String("konsole")) << QLatin1String("-e") << KGpgSettings::gpgBinaryPath() << QLatin1String("--no-secmem-warning") << QLatin1String("--edit-key") << nd->getId() << QLatin1String("help"); terminalkey = nd->toKeyNode(); editKey->setEnabled(false); connect(kp, static_cast(&KProcess::finished), this, &KeysManager::slotEditDone); kp->start(); } void KeysManager::slotEditDone(int exitcode) { if (exitcode == 0) imodel->refreshKey(terminalkey); terminalkey = nullptr; editKey->setEnabled(true); } void KeysManager::doPrint(const QString &txt) { QPrinter prt; //qCDebug(KGPG_LOG_GENERAL) << "Printing..." ; QPointer printDialog = new QPrintDialog(&prt, this); if (printDialog->exec() == QDialog::Accepted) { QPainter painter(&prt); int width = painter.device()->width(); int height = painter.device()->height(); painter.drawText(0, 0, width, height, Qt::AlignLeft|Qt::AlignTop|Qt::TextDontClip, txt); } delete printDialog; } void KeysManager::removeFromGroups(KGpgKeyNode *node) { QStringList groupNames; const auto groups = node->getGroups(); for (const KGpgGroupNode *gnd : groups) groupNames << gnd->getName(); if (groupNames.isEmpty()) return; const QString ask = i18np("The key you are deleting is a member of the following key group. Do you want to remove it from this group?", "The key you are deleting is a member of the following key groups. Do you want to remove it from these groups?", groupNames.count()); if (KMessageBox::questionYesNoList(this, ask, groupNames, i18n("Delete key")) != KMessageBox::Yes) return; bool groupDeleted = false; const auto grefs = node->getGroupRefs(); for (KGpgGroupMemberNode *gref : grefs) { KGpgGroupNode *group = gref->getParentKeyNode(); bool deleteWholeGroup = (group->getChildCount() == 1) && (group->getChild(0)->toGroupMemberNode() == gref); if (deleteWholeGroup) deleteWholeGroup = (KMessageBox::questionYesNo(this, i18n("You are removing the last key from key group %1.
Do you want to delete the group, too?", group->getName()), i18n("Delete key")) == KMessageBox::Yes); if (!deleteWholeGroup) { imodel->deleteFromGroup(group, gref); } else { group->remove(); imodel->delNode(group); groupDeleted = true; } } if (groupDeleted) { updateStatusCounter(); } } void KeysManager::deleteseckey() { KGpgKeyNode *nd = iview->selectedNode()->toKeyNode(); Q_ASSERT(nd != nullptr); // delete a key int result = KMessageBox::warningContinueCancel(this, i18n("

Delete secret key pair %1?

Deleting this key pair means you will never be able to decrypt files encrypted with this key again.", nd->getNameComment()), QString(), KGuiItem(i18n("Delete"), QLatin1String( "edit-delete" ))); if (result != KMessageBox::Continue) return; if (terminalkey == nd) return; if (m_delkey != nullptr) { KMessageBox::error(this, i18n("Another key delete operation is still in progress.\nPlease wait a moment until this operation is complete."), i18n("Delete key")); return; } removeFromGroups(nd); m_delkey = new KGpgDelKey(this, nd); connect(m_delkey, &KGpgDelKey::done, this, &KeysManager::secretKeyDeleted); m_delkey->start(); } void KeysManager::secretKeyDeleted(int retcode) { KGpgKeyNode *delkey = m_delkey->keys.at(0); if (retcode == 0) { KMessageBox::information(this, i18n("Key %1 deleted.", delkey->getBeautifiedFingerprint()), i18n("Delete key")); imodel->delNode(delkey); } else { KMessageBox::error(this, i18n("Deleting key %1 failed.", delkey->getBeautifiedFingerprint()), i18n("Delete key")); } m_delkey->deleteLater(); m_delkey = nullptr; } void KeysManager::confirmdeletekey() { if (m_delkey) { KMessageBox::error(this, i18n("Another key delete operation is still in progress.\nPlease wait a moment until this operation is complete."), i18n("Delete key")); return; } KgpgCore::KgpgItemType pt; bool same; const auto ndlist = iview->selectedNodes(&same, &pt); if (ndlist.empty()) return; // do not delete a key currently edited in terminal if ((!(pt & ~ITYPE_PAIR)) && (ndlist.at(0) == terminalkey) && (ndlist.size() == 1)) { KMessageBox::error(this, i18n("Can not delete key %1 while it is edited in terminal.", terminalkey->getBeautifiedFingerprint()), i18n("Delete key")); return; } else if (pt == ITYPE_GROUP) { deleteGroup(); return; } else if (!(pt & ITYPE_GROUP) && (pt & ITYPE_SECRET) && (ndlist.size() == 1)) { deleteseckey(); return; } else if ((pt == ITYPE_UID) && (ndlist.size() == 1)) { slotDelUid(); return; } else if ((pt & ITYPE_GROUP) && !(pt & ~ITYPE_GPAIR)) { bool invalidDelete = false; for (const KGpgNode *nd : ndlist) if (nd->getType() == ITYPE_GROUP) { invalidDelete = true; break; } // only allow removing group members if they belong to the same group if (!invalidDelete) { const KGpgNode * const group = ndlist.front()->getParentKeyNode(); for (const KGpgNode *nd : ndlist) if (nd->getParentKeyNode() != group) { invalidDelete = true; break; } } if (!invalidDelete) { KGpgGroupNode *gnd = ndlist.front()->getParentKeyNode()->toGroupNode(); QList members = gnd->getChildren(); for (KGpgNode *nd : ndlist) { int r = members.removeAll(nd); Q_ASSERT(r == 1); Q_UNUSED(r); } imodel->changeGroup(gnd, members); return; } } if (pt & ~ITYPE_PAIR) { KMessageBox::error(this, i18n("You have selected items that are not keys. They can not be deleted with this menu entry."), i18n("Delete key")); return; } QStringList keysToDelete; QStringList deleteIds; QStringList secList; KGpgKeyNode::List delkeys; bool secretKeyInside = (pt & ITYPE_SECRET); for (KGpgNode *nd : ndlist) { KGpgKeyNode *ki = nd->toKeyNode(); if (ki->getType() & ITYPE_SECRET) { secList += ki->getNameComment(); } else if (ki != terminalkey) { keysToDelete += ki->getNameComment(); deleteIds << ki->getId(); delkeys << ki; } } if (secretKeyInside) { int result = KMessageBox::warningContinueCancel(this, i18n("The following are secret key pairs:
%1
They will not be deleted.
", secList.join( QLatin1String( "
" )))); if (result != KMessageBox::Continue) return; } if (keysToDelete.isEmpty()) return; int result = KMessageBox::warningContinueCancelList(this, i18np("Delete the following public key?", "Delete the following %1 public keys?", keysToDelete.count()), keysToDelete, QString(), KStandardGuiItem::del()); if (result != KMessageBox::Continue) return; for (KGpgNode *nd : ndlist) removeFromGroups(nd->toKeyNode()); m_delkey = new KGpgDelKey(this, delkeys); connect(m_delkey, &KGpgDelKey::done, this, &KeysManager::slotDelKeyDone); m_delkey->start(); } void KeysManager::slotDelKeyDone(int res) { if (res == 0) { for (KGpgKeyNode *kn : m_delkey->keys) imodel->delNode(kn); } m_delkey->deleteLater(); m_delkey = nullptr; updateStatusCounter(); } void KeysManager::slotPreImportKey() { QPointer dial = new QDialog(this); dial->setWindowTitle(i18n("Key Import")); QVBoxLayout *mainLayout = new QVBoxLayout(dial); QWidget *mainWidget = new QWidget(this); mainLayout->addWidget(mainWidget); dial->setLayout(mainLayout); SrcSelect *page = new SrcSelect(); mainLayout->addWidget(page); page->newFilename->setWindowTitle(i18n("Open File")); page->newFilename->setMode(KFile::File); page->buttonBox->button(QDialogButtonBox::Ok)->setShortcut(Qt::CTRL | Qt::Key_Return); connect(page->buttonBox, &QDialogButtonBox::accepted, dial.data(), &QDialog::accept); connect(page->buttonBox, &QDialogButtonBox::rejected, dial.data(), &QDialog::reject); if (dial->exec() == QDialog::Accepted) { if (page->checkFile->isChecked()) { QUrl impname = page->newFilename->url(); if (!impname.isEmpty()) slotImport(QList({impname})); } else if (page->checkServer->isChecked()) { const QString ids(page->keyIds->text().simplified()); if (!ids.isEmpty()) importRemoteKeys(ids.split(QLatin1Char( ' ' ))); } else { slotImport(qApp->clipboard()->text(m_clipboardmode)); } } delete dial; } void KeysManager::slotImport(const QString &text) { if (text.isEmpty()) return; KGpgImport *imp; if (!KGpgImport::isKey(text) && KGpgDecrypt::isEncryptedText(text)) { if (KMessageBox::questionYesNo(this, i18n("The text in the clipboard does not look like a key, but like encrypted text.
Do you want to decrypt it first" " and then try importing it?
"), i18n("Import from Clipboard")) != KMessageBox::Yes) return; imp = new KGpgImport(this); KGpgDecrypt *decr = new KGpgDecrypt(this, text); imp->setInputTransaction(decr); } else { imp = new KGpgImport(this, text); } startImport(imp); } void KeysManager::slotImport(const QList &files) { startImport(new KGpgImport(this, files)); } void KeysManager::startImport(KGpgImport *import) { changeMessage(i18n("Importing..."), true); connect(import, &KGpgImport::done, this, &KeysManager::slotImportDone); import->start(); } void KeysManager::slotImportDone(int result) { KGpgImport *import = qobject_cast(sender()); Q_ASSERT(import != nullptr); const QStringList rawmsgs(import->getMessages()); if (result != 0) { KMessageBox::detailedSorry(this, i18n("Key importing failed. Please see the detailed log for more information."), rawmsgs.join(QLatin1String("\n")) , i18n("Key Import")); } QStringList keys(import->getImportedIds(0x1f)); const bool needsRefresh = !keys.isEmpty(); keys << import->getImportedIds(0); if (!keys.isEmpty()) { const QString msg(import->getImportMessage()); const QStringList keynames(import->getImportedKeys()); new KgpgDetailedInfo(this, msg, rawmsgs.join(QLatin1String("\n")), keynames, i18n("Key Import")); if (needsRefresh) imodel->refreshKeys(keys); else changeMessage(i18nc("Application ready for user input", "Ready")); } else{ changeMessage(i18nc("Application ready for user input", "Ready")); } import->deleteLater(); } void KeysManager::refreshkey() { imodel->refreshAllKeys(); updateStatusCounter(); } KGpgItemModel *KeysManager::getModel() { return imodel; } void KeysManager::toggleNetworkActions(bool online) { m_online = online; kserver->setEnabled(online); importSignatureKey->setEnabled(online); importAllSignKeys->setEnabled(online); refreshKey->setEnabled(online); } void KeysManager::setupTrayIcon() { bool newtray = (m_trayicon == nullptr); if (newtray) { m_trayicon = new KStatusNotifierItem(this); m_trayicon->setIconByName(QLatin1String( "kgpg" )); m_trayicon->setToolTip(QLatin1String( "kgpg" ), i18n("KGpg - encryption tool"), QString()); } switch (KGpgSettings::leftClick()) { case KGpgSettings::EnumLeftClick::Editor: m_trayicon->setAssociatedWidget(s_kgpgEditor); break; case KGpgSettings::EnumLeftClick::KeyManager: m_trayicon->setAssociatedWidget(this); break; } m_trayicon->setCategory(KStatusNotifierItem::ApplicationStatus); if (!newtray) return; QMenu *conf_menu = m_trayicon->contextMenu(); QAction *KgpgOpenManager = actionCollection()->addAction(QLatin1String("kgpg_manager"), this, &KeysManager::show); KgpgOpenManager->setIcon(QIcon::fromTheme( QLatin1String( "kgpg" ))); KgpgOpenManager->setText(i18n("Ke&y Manager")); QAction *KgpgEncryptClipboard = actionCollection()->addAction(QLatin1String("clip_encrypt"), this, &KeysManager::clipEncrypt); KgpgEncryptClipboard->setText(i18n("&Encrypt Clipboard")); QAction *KgpgDecryptClipboard = actionCollection()->addAction(QLatin1String("clip_decrypt"), this, &KeysManager::clipDecrypt); KgpgDecryptClipboard->setText(i18n("&Decrypt Clipboard")); QAction *KgpgSignClipboard = actionCollection()->addAction(QLatin1String("clip_sign"), this, &KeysManager::clipSign); KgpgSignClipboard->setText(i18n("&Sign/Verify Clipboard")); KgpgSignClipboard->setIcon(QIcon::fromTheme( QLatin1String( "document-sign-key" ))); QAction *KgpgPreferences = KStandardAction::preferences(this, &KeysManager::showOptions, actionCollection()); conf_menu->addAction( KgpgEncryptClipboard ); conf_menu->addAction( KgpgDecryptClipboard ); conf_menu->addAction( KgpgSignClipboard ); conf_menu->addAction( KgpgOpenManager ); conf_menu->addAction( openEditor ); conf_menu->addAction( kserver ); conf_menu->addSeparator(); conf_menu->addAction( KgpgPreferences ); } void KeysManager::showTrayMessage(const QString &message) { if (m_trayicon == nullptr) return; m_trayicon->showMessage(QString(), message, QLatin1String( "kgpg" )); } QKeySequence KeysManager::goDefaultShortcut() const { return QKeySequence(goToDefaultKey->shortcut()); } void KeysManager::clipEncrypt() { const QString cliptext(qApp->clipboard()->text(m_clipboardmode)); if (cliptext.isEmpty()) { Q_ASSERT(m_trayicon != nullptr); m_trayicon->showMessage(QString(), i18n("Clipboard is empty."), QLatin1String( "kgpg" )); return; } QPointer dialog = new KgpgSelectPublicKeyDlg(this, imodel, QKeySequence(goToDefaultKey->shortcut()), true); if (dialog->exec() == QDialog::Accepted) { KGpgEncrypt::EncryptOptions encOptions = KGpgEncrypt::AsciiArmored; QStringList options; if (!dialog->getCustomOptions().isEmpty() && KGpgSettings::allowCustomEncryptionOptions()) options = dialog->getCustomOptions().split(QLatin1Char(' '), QString::SkipEmptyParts); if (dialog->getUntrusted()) encOptions |= KGpgEncrypt::AllowUntrustedEncryption; if (dialog->getHideId()) encOptions |= KGpgEncrypt::HideKeyId; if (KGpgSettings::pgpCompatibility()) options.append(QLatin1String( "--pgp6" )); KGpgEncrypt *enc = new KGpgEncrypt(this, dialog->selectedKeys(), cliptext, encOptions, options); connect(enc, &KGpgEncrypt::done, this, &KeysManager::slotSetClip); m_trayicon->setStatus(KStatusNotifierItem::Active); enc->start(); } delete dialog; } void KeysManager::slotSetClip(int result) { KGpgEncrypt *enc = qobject_cast(sender()); Q_ASSERT(enc != nullptr); sender()->deleteLater(); m_trayicon->setStatus(KStatusNotifierItem::Passive); if (result != KGpgTransaction::TS_OK) return; qApp->clipboard()->setText(enc->encryptedText().join(QLatin1String("\n")), m_clipboardmode); Q_ASSERT(m_trayicon != nullptr); m_trayicon->showMessage(QString(), i18n("Text successfully encrypted."), QLatin1String( "kgpg" )); } void KeysManager::slotOpenKeyUrl() { KGpgNode *cur = iview->selectedNode(); if (cur == nullptr) return; QString id; switch (cur->getType()) { case ITYPE_PAIR: case ITYPE_PUBLIC: { id = cur->toKeyNode()->getFingerprint(); break; } case ITYPE_GPAIR: case ITYPE_GPUBLIC: { id = cur->getId(); break; } default: return; } const QStringList servers = KGpgSettings::infoServers(); if (servers.isEmpty()) return; QString url = servers.first(); const QString idUC = id.toUpper(); const QString idLC = id.toLower(); url.replace(QLatin1String("$$ID8$$"), idUC.right(8)); url.replace(QLatin1String("$$ID16$$"), idUC.right(16)); url.replace(QLatin1String("$$FPR$$"), idUC); url.replace(QLatin1String("$$id8$$"), idLC.right(8)); url.replace(QLatin1String("$$id16$$"), idLC.right(16)); url.replace(QLatin1String("$$fpr$$"), idLC); new KRun(QUrl(url), this); } void KeysManager::clipDecrypt() { const QString cliptext(qApp->clipboard()->text(m_clipboardmode).trimmed()); if (cliptext.isEmpty()) { Q_ASSERT(m_trayicon != nullptr); m_trayicon->showMessage(QString(), i18n("Clipboard is empty."), QLatin1String( "kgpg" )); return; } KgpgEditor *kgpgtxtedit = new KgpgEditor(this, imodel, nullptr); kgpgtxtedit->setAttribute(Qt::WA_DeleteOnClose); connect(this, &KeysManager::fontChanged, kgpgtxtedit, &KgpgEditor::slotSetFont); kgpgtxtedit->m_editor->setPlainText(cliptext); kgpgtxtedit->m_editor->slotDecode(); kgpgtxtedit->show(); } void KeysManager::clipSign() { QString cliptext = qApp->clipboard()->text(m_clipboardmode); if (cliptext.isEmpty()) { Q_ASSERT(m_trayicon != nullptr); m_trayicon->showMessage(QString(), i18n("Clipboard is empty."), QLatin1String( "kgpg" )); return; } KgpgEditor *kgpgtxtedit = new KgpgEditor(this, imodel, nullptr); kgpgtxtedit->setAttribute(Qt::WA_DeleteOnClose); connect(kgpgtxtedit->m_editor, &KgpgTextEdit::verifyFinished, kgpgtxtedit, &KgpgEditor::closeWindow); kgpgtxtedit->m_editor->signVerifyText(cliptext); kgpgtxtedit->show(); } diff --git a/kgpgexternalactions.cpp b/kgpgexternalactions.cpp index f7211c23..bc25b1be 100644 --- a/kgpgexternalactions.cpp +++ b/kgpgexternalactions.cpp @@ -1,495 +1,496 @@ /* * Copyright (C) 2002 Jean-Baptiste Mardelle * Copyright (C) 2008,2009,2010,2011,2012,2013 Rolf Eike Beer * Copyright (C) 2016 Andrius Štikoans */ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "kgpgexternalactions.h" #include "detailedconsole.h" #include "foldercompressjob.h" #include "keyservers.h" #include "keysmanager.h" #include "kgpgfirstassistant.h" #include "kgpginterface.h" #include "kgpgsettings.h" #include "kgpgtextinterface.h" #include "selectpublickeydialog.h" #include "selectsecretkey.h" #include "core/images.h" #include "editor/kgpgeditor.h" #include "editor/kgpgtextedit.h" #include "transactions/kgpgdecrypt.h" #include "transactions/kgpgencrypt.h" #include "transactions/kgpgsigntext.h" #include "transactions/kgpgtransactionjob.h" #include "transactions/kgpgverify.h" #include #include #include #include #include #include #include #include #include #include #include #include KGpgExternalActions::KGpgExternalActions(KeysManager *parent, KGpgItemModel *model) : QObject(parent), compressionScheme(0), m_model(model), m_kgpgfoldertmp(nullptr), m_keysmanager(parent) { readOptions(); } KGpgExternalActions::~KGpgExternalActions() { delete m_kgpgfoldertmp; } void KGpgExternalActions::encryptFiles(KeysManager *parent, const QList &urls) { Q_ASSERT(!urls.isEmpty()); KGpgExternalActions *encActions = new KGpgExternalActions(parent, parent->getModel()); KgpgSelectPublicKeyDlg *dialog = new KgpgSelectPublicKeyDlg(parent, parent->getModel(), encActions->goDefaultKey(), false, urls); connect(dialog, &KgpgSelectPublicKeyDlg::accepted, encActions, &KGpgExternalActions::slotEncryptionKeySelected); connect(dialog, &KgpgSelectPublicKeyDlg::rejected, dialog, &KgpgSelectPublicKeyDlg::deleteLater); connect(dialog, &KgpgSelectPublicKeyDlg::rejected, encActions, &KGpgExternalActions::deleteLater); dialog->show(); } void KGpgExternalActions::slotEncryptionKeySelected() { KgpgSelectPublicKeyDlg *dialog = qobject_cast(sender()); Q_ASSERT(dialog != nullptr); sender()->deleteLater(); QStringList opts; QString defaultKey; if (KGpgSettings::encryptFilesTo()) { if (KGpgSettings::pgpCompatibility()) opts << QLatin1String( "--pgp6" ); defaultKey = KGpgSettings::fileEncryptionKey(); } KGpgEncrypt::EncryptOptions eopt = KGpgEncrypt::DefaultEncryption; if (dialog->getUntrusted()) eopt |= KGpgEncrypt::AllowUntrustedEncryption; if (dialog->getArmor()) eopt |= KGpgEncrypt::AsciiArmored; if (dialog->getHideId()) eopt |= KGpgEncrypt::HideKeyId; if (KGpgSettings::allowCustomEncryptionOptions()) { const QString customopts(dialog->getCustomOptions().isEmpty()); if (!customopts.isEmpty()) opts << customopts.split(QLatin1Char(' '), QString::SkipEmptyParts); } QStringList keys = dialog->selectedKeys(); if (!defaultKey.isEmpty() && !keys.contains(defaultKey)) keys.append(defaultKey); if (dialog->getSymmetric()) keys.clear(); KGpgEncrypt *enc = new KGpgEncrypt(dialog->parent(), keys, dialog->getFiles(), eopt, opts); KGpgTransactionJob *encjob = new KGpgTransactionJob(enc); KIO::getJobTracker()->registerJob(encjob); encjob->start(); deleteLater(); } void KGpgExternalActions::encryptFolders(KeysManager *parent, const QList &urls) { QTemporaryFile *tmpfolder = new QTemporaryFile(); if (!tmpfolder->open()) { delete tmpfolder; KMessageBox::sorry(parent, i18n("Cannot create temporary file for folder compression."), i18n("Temporary File Creation")); return; } if (KMessageBox::Continue != KMessageBox::warningContinueCancel(parent, i18n("KGpg will now create a temporary archive file:
%1 to process the encryption. " "The file will be deleted after the encryption is finished.
", tmpfolder->fileName()), i18n("Temporary File Creation"), KStandardGuiItem::cont(), KStandardGuiItem::cancel(), QLatin1String( "FolderTmpFile" ))) { delete tmpfolder; return; } KGpgExternalActions *encActions = new KGpgExternalActions(parent, parent->getModel()); KgpgSelectPublicKeyDlg *dialog = new KgpgSelectPublicKeyDlg(parent, parent->getModel(), encActions->goDefaultKey(), false, urls); encActions->m_kgpgfoldertmp = tmpfolder; QWidget *bGroup = new QWidget(dialog->optionsbox); QHBoxLayout *bGroupHBoxLayout = new QHBoxLayout(bGroup); bGroupHBoxLayout->setMargin(0); (void) new QLabel(i18n("Compression method for archive:"), bGroup); QComboBox *optionbx = new QComboBox(bGroup); bGroupHBoxLayout->addWidget(optionbx); optionbx->setModel(new QStringListModel(FolderCompressJob::archiveNames(), bGroup)); connect(optionbx, static_cast(&QComboBox::activated), encActions, &KGpgExternalActions::slotSetCompression); connect(dialog, &KgpgSelectPublicKeyDlg::accepted, encActions, &KGpgExternalActions::startFolderEncode); connect(dialog, &KgpgSelectPublicKeyDlg::rejected, encActions, &KGpgExternalActions::deleteLater); connect(dialog, &KgpgSelectPublicKeyDlg::rejected, dialog, &KgpgSelectPublicKeyDlg::deleteLater); dialog->show(); } void KGpgExternalActions::slotSetCompression(int cp) { compressionScheme = cp; } void KGpgExternalActions::startFolderEncode() { KgpgSelectPublicKeyDlg *dialog = qobject_cast(sender()); Q_ASSERT(dialog != nullptr); dialog->deleteLater(); const QList urls = dialog->getFiles(); QStringList selec = dialog->selectedKeys(); KGpgEncrypt::EncryptOptions encOptions = KGpgEncrypt::DefaultEncryption; const QStringList encryptOptions = dialog->getCustomOptions().split(QLatin1Char(' '), QString::SkipEmptyParts); if (dialog->getSymmetric()) { selec.clear(); } else { Q_ASSERT(!selec.isEmpty()); } QString extension = FolderCompressJob::extensionForArchive(compressionScheme); if (dialog->getArmor()) extension += QLatin1String( ".asc" ); else if (KGpgSettings::pgpExtension()) extension += QLatin1String( ".pgp" ); else extension += QLatin1String( ".gpg" ); if (dialog->getArmor()) encOptions |= KGpgEncrypt::AsciiArmored; if (dialog->getHideId()) encOptions |= KGpgEncrypt::HideKeyId; if (dialog->getUntrusted()) encOptions |= KGpgEncrypt::AllowUntrustedEncryption; QUrl encryptedFile(QUrl::fromLocalFile(urls.first().adjusted(QUrl::StripTrailingSlash).path() + extension)); QFile encryptedFolder(encryptedFile.path()); dialog->hide(); if (encryptedFolder.exists()) { QPointer over = new KIO::RenameDialog(m_keysmanager, i18n("File Already Exists"), QUrl(), encryptedFile, KIO::RenameDialog_Overwrite); if (over->exec() == QDialog::Rejected) { dialog = nullptr; delete over; deleteLater(); return; } encryptedFile = over->newDestUrl(); delete over; } FolderCompressJob *trayinfo = new FolderCompressJob(m_keysmanager, urls, encryptedFile, m_kgpgfoldertmp, selec, encryptOptions, encOptions, compressionScheme); connect(trayinfo, &FolderCompressJob::result, this, &KGpgExternalActions::slotFolderFinished); KIO::getJobTracker()->registerJob(trayinfo); trayinfo->start(); } void KGpgExternalActions::slotFolderFinished(KJob *job) { FolderCompressJob *trayinfo = qobject_cast(job); Q_ASSERT(trayinfo != nullptr); if (trayinfo->error()) KMessageBox::sorry(m_keysmanager, trayinfo->errorString()); deleteLater(); } void KGpgExternalActions::verifyFile(QUrl url) { // check file signature if (url.isEmpty()) return; QString sigfile; // try to find detached signature. if (!url.fileName().endsWith(QLatin1String(".sig"))) { sigfile = url.path() + QLatin1String( ".sig" ); QFile fsig(sigfile); if (!fsig.exists()) { sigfile = url.path() + QLatin1String( ".asc" ); QFile fsig(sigfile); // if no .asc or .sig signature file included, assume the file is internally signed if (!fsig.exists()) sigfile.clear(); } } else { sigfile = url.path(); - url = QUrl(sigfile.left(sigfile.length() - 4)); + sigfile.chop(4); + url = QUrl(sigfile); } KGpgVerify *kgpv = new KGpgVerify(parent(), QList({QUrl(sigfile)})); connect(kgpv, &KGpgVerify::done, this, &KGpgExternalActions::slotVerificationDone); kgpv->start(); } void KGpgExternalActions::slotVerificationDone(int result) { KGpgVerify *kgpv = qobject_cast(sender()); Q_ASSERT(kgpv != nullptr); kgpv->deleteLater(); if (result == KGpgVerify::TS_MISSING_KEY) { KeyServer *kser = new KeyServer(m_keysmanager, m_model); kser->slotSetText(kgpv->missingId()); kser->slotImport(); } else { const QStringList messages = kgpv->getMessages(); if (messages.isEmpty()) return; QStringList msglist; for (QString rawmsg : messages) msglist << rawmsg.replace(QLatin1Char('<'), QLatin1String("<")); (void) new KgpgDetailedInfo(m_keysmanager, KGpgVerify::getReport(messages, m_model), msglist.join(QLatin1String("
")), QStringList(), i18nc("Caption of message box", "Verification Finished")); } } void KGpgExternalActions::signFiles(KeysManager* parent, const QList& urls) { Q_ASSERT(!urls.isEmpty()); KGpgExternalActions *signActions = new KGpgExternalActions(parent, parent->getModel()); signActions->droppedUrls = urls; KgpgSelectSecretKey *keydlg = new KgpgSelectSecretKey(parent, parent->getModel(), false); connect(keydlg, &KgpgSelectSecretKey::accepted, signActions, &KGpgExternalActions::slotSignFiles); connect(keydlg, &KgpgSelectSecretKey::rejected, keydlg, &KgpgSelectSecretKey::deleteLater); connect(keydlg, &KgpgSelectSecretKey::rejected, signActions, &KGpgExternalActions::deleteLater); keydlg->show(); } void KGpgExternalActions::slotSignFiles() { KgpgSelectSecretKey *keydlg = qobject_cast(sender()); Q_ASSERT(keydlg != nullptr); sender()->deleteLater(); const QString signKeyID = keydlg->getKeyID(); QStringList Options; KGpgSignText::SignOptions sopts = KGpgSignText::DetachedSignature; if (KGpgSettings::asciiArmor()) { Options << QLatin1String( "--armor" ); sopts |= KGpgSignText::AsciiArmored; } if (KGpgSettings::pgpCompatibility()) Options << QLatin1String( "--pgp6" ); if (droppedUrls.count() > 1) { KGpgTextInterface *signFileProcess = new KGpgTextInterface(parent(), signKeyID, Options); connect(signFileProcess, &KGpgTextInterface::fileSignFinished, signFileProcess, &KGpgTextInterface::deleteLater); signFileProcess->signFiles(droppedUrls); } else { KGpgSignText *signt = new KGpgSignText(parent(), signKeyID, droppedUrls, sopts); connect(signt, &KGpgSignText::done, signt, &KGpgSignText::deleteLater); signt->start(); } deleteLater(); } void KGpgExternalActions::decryptFiles(KeysManager* parent, const QList &urls) { KGpgExternalActions *decActions = new KGpgExternalActions(parent, parent->getModel()); decActions->decryptFile(urls); } void KGpgExternalActions::decryptFile(QList urls) { if (urls.isEmpty()) { deleteLater(); return; } while (!urls.first().isLocalFile()) { showDroppedFile(urls.takeFirst()); } QUrl first = urls.first(); QString oldname(first.fileName()); if (oldname.endsWith(QLatin1String(".gpg"), Qt::CaseInsensitive) || oldname.endsWith(QLatin1String(".asc"), Qt::CaseInsensitive) || oldname.endsWith(QLatin1String(".pgp"), Qt::CaseInsensitive)) oldname.chop(4); else oldname.append(QLatin1String( ".clear" )); QUrl swapname = QUrl::fromLocalFile(first.adjusted(QUrl::RemoveFilename).path() + oldname); QFile fgpg(swapname.path()); if (fgpg.exists()) { QPointer over = new KIO::RenameDialog(m_keysmanager, i18n("File Already Exists"), QUrl(), swapname, KIO::RenameDialog_Overwrite); if (over->exec() != QDialog::Accepted) { delete over; urls.pop_front(); decryptFile(urls); return; } swapname = over->newDestUrl(); delete over; } droppedUrls = urls; KGpgDecrypt *decr = new KGpgDecrypt(this, droppedUrls.first(), swapname); connect(decr, &KGpgDecrypt::done, this, &KGpgExternalActions::slotDecryptionDone); decr->start(); } void KGpgExternalActions::slotDecryptionDone(int status) { KGpgDecrypt *decr = qobject_cast(sender()); Q_ASSERT(decr != nullptr); if (status != KGpgTransaction::TS_OK) m_decryptionFailed << droppedUrls.first(); decr->deleteLater(); droppedUrls.pop_front(); if (!droppedUrls.isEmpty()) { decryptFile(droppedUrls); } else { if (!m_decryptionFailed.isEmpty()) { QStringList failedFiles; for (const QUrl &url : m_decryptionFailed) failedFiles.append(url.toDisplayString()); KMessageBox::errorList(nullptr, i18np("Decryption of this file failed:", "Decryption of these files failed:", m_decryptionFailed.count()), failedFiles, i18n("Decryption failed.")); } deleteLater(); } } void KGpgExternalActions::showDroppedFile(const QUrl &file) { KgpgEditor *kgpgtxtedit = new KgpgEditor(m_keysmanager, m_model, {}); connect(m_keysmanager, &KeysManager::fontChanged, kgpgtxtedit, &KgpgEditor::slotSetFont); kgpgtxtedit->m_editor->openDroppedFile(file, false); kgpgtxtedit->show(); } void KGpgExternalActions::readOptions() { if (KGpgSettings::firstRun()) { firstRun(); } else if (KGpgSettings::gpgConfigPath().isEmpty()) { if (KMessageBox::Yes == KMessageBox::questionYesNo(nullptr, i18n("You have not set a path to your GnuPG config file.
This may cause some surprising results in KGpg's execution." "
Would you like to start KGpg's assistant to fix this problem?
"), QString(), KGuiItem(i18n("Start Assistant")), KGuiItem(i18n("Do Not Start")))) startAssistant(); } } void KGpgExternalActions::firstRun() { QProcess *createConfigProc = new QProcess(this); QStringList args; args << QLatin1String( "--no-tty" ) << QLatin1String( "--list-secret-keys" ); createConfigProc->start(QLatin1String( "gpg" ), args); // start GnuPG so that it will create a config file createConfigProc->waitForFinished(); startAssistant(); } void KGpgExternalActions::startAssistant() { if (m_assistant.isNull()) { m_assistant = new KGpgFirstAssistant(m_keysmanager); connect(m_assistant.data(), &KGpgFirstAssistant::accepted, this, &KGpgExternalActions::slotSaveOptionsPath); connect(m_assistant.data(), &KGpgFirstAssistant::rejected, m_assistant.data(), &KGpgFirstAssistant::deleteLater); connect(m_assistant->button(QDialogButtonBox::Help), &QPushButton::clicked, this, &KGpgExternalActions::help); } m_assistant->show(); } void KGpgExternalActions::slotSaveOptionsPath() { KGpgSettings::setAutoStart(m_assistant->getAutoStart()); KGpgSettings::setGpgConfigPath(m_assistant->getConfigPath()); KGpgSettings::setFirstRun(false); const QString gpgConfServer(KgpgInterface::getGpgSetting(QLatin1String( "keyserver" ), KGpgSettings::gpgConfigPath())); if (!gpgConfServer.isEmpty()) { // The user already had configured a keyserver, set this one as default. QStringList serverList(KGpgSettings::keyServers()); serverList.prepend(gpgConfServer); KGpgSettings::setKeyServers(serverList); } const QString defaultID(m_assistant->getDefaultKey()); KGpgSettings::self()->save(); emit updateDefault(defaultID); if (m_assistant->runKeyGenerate()) emit createNewKey(); m_assistant->deleteLater(); } void KGpgExternalActions::help() { KHelpClient::invokeHelp(QString(), QLatin1String( "kgpg" )); } QKeySequence KGpgExternalActions::goDefaultKey() const { return QKeySequence(qobject_cast(m_keysmanager->actionCollection()->action(QLatin1String( "go_default_key" )))->shortcut()); } diff --git a/kgpgfirstassistant.cpp b/kgpgfirstassistant.cpp index 0cf68bb0..4969a1f9 100644 --- a/kgpgfirstassistant.cpp +++ b/kgpgfirstassistant.cpp @@ -1,379 +1,378 @@ /* Copyright 2008,2010,2012 Rolf Eike Beer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "kgpgfirstassistant.h" #include "gpgproc.h" #include "kgpginterface.h" #include "core/kgpgkey.h" #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KgpgCore; KGpgFirstAssistant::KGpgFirstAssistant(QWidget *parent) : KAssistantDialog(parent) { setWindowTitle(i18n("KGpg Assistant")); QWidget *page = new QWidget(this); QGridLayout *gridLayout = new QGridLayout(page); gridLayout->setSpacing(6); gridLayout->setMargin(11); gridLayout->setContentsMargins(0, 0, 0, 0); QLabel *label = new QLabel(page); QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); sizePolicy.setHorizontalStretch(0); sizePolicy.setVerticalStretch(0); sizePolicy.setHeightForWidth(label->sizePolicy().hasHeightForWidth()); label->setSizePolicy(sizePolicy); label->setFrameShape(QFrame::NoFrame); label->setFrameShadow(QFrame::Plain); label->setScaledContents(false); label->setAlignment(Qt::AlignTop); label->setWordWrap(false); gridLayout->addWidget(label, 0, 0, 3, 1); label = new QLabel(page); label->setAlignment(Qt::AlignTop); label->setWordWrap(true); label->setText(i18n("This assistant will first setup some basic configuration options required for KGpg to work properly. Next, it will allow you to create your own key pair, enabling you to encrypt your files and emails.")); gridLayout->addWidget(label, 0, 1, 1, 1); QSpacerItem *spacerItem = new QSpacerItem(20, 41, QSizePolicy::Minimum, QSizePolicy::Expanding); gridLayout->addItem(spacerItem, 1, 1, 1, 1); page_welcome = addPage(page, i18n("Welcome to the KGpg Assistant")); page = new QWidget(this); gridLayout = new QGridLayout(page); gridLayout->setSpacing(6); gridLayout->setMargin(11); gridLayout->setContentsMargins(0, 0, 0, 0); label = new QLabel(page); label->setAlignment(Qt::AlignTop); label->setWordWrap(true); label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); label->setText(i18n("KGpg needs to know which GnuPG binary to use.")); gridLayout->addWidget(label, 0, 1, 1, 1); label = new QLabel(page); label->setAlignment(Qt::AlignTop); label->setWordWrap(true); label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); label->setText(i18n("Unless you want to try some unusual settings, just click on the \"next\" button.")); gridLayout->addWidget(label, 1, 1, 1, 1); spacerItem = new QSpacerItem(20, 60, QSizePolicy::Minimum, QSizePolicy::Expanding); gridLayout->addItem(spacerItem, 4, 1, 1, 1); txtGpgVersion = new QLabel(page); txtGpgVersion->setWordWrap(true); gridLayout->addWidget(txtGpgVersion, 3, 1, 1, 1); binURL = new KUrlRequester(page); binURL->setFilter(i18nc("search filter for gpg binary", "gpg|GnuPG binary\n*|All files")); QString gpgBin = QStandardPaths::findExecutable(QLatin1String("gpg2")); if (gpgBin.isEmpty()) gpgBin = QStandardPaths::findExecutable(QLatin1String("gpg")); if (gpgBin.isEmpty()) gpgBin = QLatin1String("gpg"); binURL->setUrl(QUrl::fromLocalFile(gpgBin)); connect(binURL, &KUrlRequester::textChanged, this, &KGpgFirstAssistant::slotBinaryChanged); slotBinaryChanged(gpgBin); gridLayout->addWidget(binURL, 2, 1, 1, 1); page_binary = addPage(page, i18n("GnuPG Binary")); page = new QWidget(this); gridLayout = new QGridLayout(page); gridLayout->setSpacing(6); gridLayout->setMargin(11); gridLayout->setContentsMargins(0, 0, 0, 0); text_optionsfound = new QLabel(page); text_optionsfound->setAlignment(Qt::AlignTop); text_optionsfound->setWordWrap(true); text_optionsfound->setText(i18n("Unless you want to try some unusual settings, just click on the \"next\" button.")); gridLayout->addWidget(text_optionsfound, 1, 1, 1, 1); label = new QLabel(page); label->setAlignment(Qt::AlignTop); label->setWordWrap(true); label->setText(i18n("KGpg needs to know where your GnuPG configuration file is stored.")); gridLayout->addWidget(label, 0, 1, 1, 1); spacerItem = new QSpacerItem(20, 60, QSizePolicy::Minimum, QSizePolicy::Expanding); gridLayout->addItem(spacerItem, 4, 1, 1, 1); pathURL = new KUrlRequester(page); gridLayout->addWidget(pathURL, 3, 1, 1, 1); label = new QLabel(page); label->setAlignment(Qt::AlignVCenter); label->setWordWrap(true); label->setText(i18n("Path to your GnuPG configuration file:")); gridLayout->addWidget(label, 2, 1, 1, 1); label = new QLabel(page); sizePolicy.setHeightForWidth(label->sizePolicy().hasHeightForWidth()); label->setSizePolicy(sizePolicy); label->setFrameShape(QFrame::NoFrame); label->setFrameShadow(QFrame::Plain); label->setScaledContents(false); label->setAlignment(Qt::AlignTop); label->setWordWrap(false); gridLayout->addWidget(label, 0, 0, 5, 1); page_config = addPage(page, i18n("Configuration File")); page = new QWidget(this); gridLayout = new QGridLayout(page); gridLayout->setSpacing(6); gridLayout->setMargin(11); gridLayout->setContentsMargins(0, 0, 0, 0); QHBoxLayout *hboxLayout = new QHBoxLayout(); hboxLayout->setSpacing(6); label = new QLabel(page); label->setText(i18n("Your default key:")); hboxLayout->addWidget(label); CBdefault = new QComboBox(page); QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::Fixed); sizePolicy1.setHorizontalStretch(0); sizePolicy1.setVerticalStretch(0); sizePolicy1.setHeightForWidth(CBdefault->sizePolicy().hasHeightForWidth()); CBdefault->setSizePolicy(sizePolicy1); hboxLayout->addWidget(CBdefault); gridLayout->addLayout(hboxLayout, 0, 1, 1, 1); spacerItem = new QSpacerItem(20, 30, QSizePolicy::Minimum, QSizePolicy::Expanding); gridLayout->addItem(spacerItem, 1, 1, 1, 1); page_defaultkey = addPage(page, i18n("Default Key")); page = new QWidget(this); gridLayout = new QGridLayout(page); gridLayout->setSpacing(6); gridLayout->setMargin(11); gridLayout->setContentsMargins(0, 0, 0, 0); binlabel = new QLabel(page); gridLayout->addWidget(binlabel, 0, 1, 1, 1); versionLabel = new QLabel(page); gridLayout->addWidget(versionLabel, 1, 1, 1, 1); defaultkeylabel = new QLabel(page); gridLayout->addWidget(defaultkeylabel, 2, 1, 1, 1); generateCB = new QCheckBox(page); generateCB->setText(i18n("Generate new key")); gridLayout->addWidget(generateCB, 3, 1, 1, 1); spacerItem = new QSpacerItem(20, 30, QSizePolicy::Minimum, QSizePolicy::Expanding); gridLayout->addItem(spacerItem, 4, 1, 1, 1); autostartCB = new QCheckBox(page); autostartCB->setChecked(true); autostartCB->setText(i18n("Start KGpg automatically at KDE startup.")); gridLayout->addWidget(autostartCB, 5, 1, 1, 1); page_done = addPage(page, i18n("Done")); } void KGpgFirstAssistant::findConfigPath(const QString &gpgBinary) { const QString gpgHome = GPGProc::getGpgHome(gpgBinary); QString confPath = gpgHome + QLatin1String( "gpg.conf" ); if (!QFile(confPath).exists()) { const QString confPathOpt = gpgHome + QLatin1String("options"); if (QFile(confPathOpt).exists()) { confPath = confPathOpt; } else { if (KMessageBox::questionYesNo(nullptr, i18n("The GnuPG configuration file was not found. Should KGpg try to create a config file ?"), QString(), KGuiItem(i18n("Create Config")), KGuiItem(i18n("Do Not Create"))) == KMessageBox::Yes) { QFile file(confPath); if (file.open(QIODevice::WriteOnly)) { QTextStream stream(&file); stream << "# GnuPG config file created by KGpg\n"; file.close(); } } else { text_optionsfound->setText(i18n("The GnuPG configuration file was not found.")); confPath.clear(); } } } pathURL->setUrl(QUrl::fromLocalFile(confPath)); const QStringList secids = KgpgInterface::readSecretKeys(); bool noSecKeys = secids.isEmpty(); generateCB->setChecked(noSecKeys); setAppropriate(page_defaultkey, !noSecKeys); if (noSecKeys) { defaultkeylabel->setVisible(false); return; } const KgpgKeyList publiclist = KgpgInterface::readPublicKeys(secids); CBdefault->clear(); for (const KgpgKey &k : publiclist) { QString s; if (k.email().isEmpty()) s = i18nc("Name: ID", "%1: %2", k.name(), k.id()); else s = i18nc("Name (Email): ID", "%1 (%2): %3", k.name(), k.email(), k.id()); CBdefault->addItem(s, k.fingerprint()); } CBdefault->setCurrentIndex(0); } void KGpgFirstAssistant::next() { if (currentPage() == page_binary) { const QString &gpgbin = binURL->url().path(); binlabel->setText(i18n("Your GnuPG binary is: %1", gpgbin)); findConfigPath(gpgbin); } else if (currentPage() == page_config) { - QString tst, name; m_confPath = pathURL->url().path(); - QString defaultID = KgpgInterface::getGpgSetting(QLatin1String( "default-key" ), m_confPath); + const QString defaultID = KgpgInterface::getGpgSetting(QLatin1String( "default-key" ), m_confPath); if (!defaultID.isEmpty()) { for (int i = 0; i < CBdefault->count(); i++) { - if (defaultID == CBdefault->itemData(i).toString().right(defaultID.length())) { + if (CBdefault->itemData(i).toString().rightRef(defaultID.length()).compare(defaultID) == 0) { CBdefault->setCurrentIndex(i); break; } } } versionLabel->setText(i18n("You have GnuPG version: %1", m_gpgVersion)); } else if (currentPage() == page_defaultkey) { defaultkeylabel->setVisible(true); defaultkeylabel->setText(i18n("Your default key is: %1", CBdefault->currentText())); int i = CBdefault->currentIndex(); if (i >= 0) { defaultkeylabel->setToolTip(CBdefault->itemData(i).toString()); } } KAssistantDialog::next(); } bool KGpgFirstAssistant::runKeyGenerate() const { return generateCB->isChecked(); } QString KGpgFirstAssistant::getConfigPath() const { return m_confPath; } QString KGpgFirstAssistant::getDefaultKey() const { int i = CBdefault->currentIndex(); if (i < 0) return QString(); else return CBdefault->itemData(i).toString(); } bool KGpgFirstAssistant::getAutoStart() const { return autostartCB->isChecked(); } void KGpgFirstAssistant::slotBinaryChanged(const QString &binary) { if (binary.isEmpty()) { setValid(page_binary, false); return; } m_gpgVersion = GPGProc::gpgVersionString(binary); setValid(page_binary, !m_gpgVersion.isEmpty()); if (!m_gpgVersion.isEmpty()) { const int gpgver = GPGProc::gpgVersion(m_gpgVersion); if (gpgver < 0x10400) { txtGpgVersion->setText(i18n("Your GnuPG version (%1) seems to be too old.
Compatibility with versions before 1.4.0 is no longer guaranteed.", m_gpgVersion)); } else { txtGpgVersion->setText(i18n("You have GnuPG version: %1", m_gpgVersion)); } } } diff --git a/model/keylistproxymodel.cpp b/model/keylistproxymodel.cpp index c4108a04..a96cd316 100644 --- a/model/keylistproxymodel.cpp +++ b/model/keylistproxymodel.cpp @@ -1,594 +1,594 @@ /* Copyright 2008,2009,2010,2012,2013 Rolf Eike Beer * Copyright 2013 Thomas Fischer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "keylistproxymodel.h" #include "model/kgpgitemnode.h" #include "kgpgitemmodel.h" #include "kgpgsettings.h" #include "core/kgpgkey.h" #include "core/images.h" #include #include using namespace KgpgCore; class KeyListProxyModelPrivate { KeyListProxyModel * const q_ptr; Q_DECLARE_PUBLIC(KeyListProxyModel) public: KeyListProxyModelPrivate(KeyListProxyModel *parent, const KeyListProxyModel::DisplayMode mode); bool lessThan(const KGpgNode *left, const KGpgNode *right, const int column) const; bool nodeLessThan(const KGpgNode *left, const KGpgNode *right, const int column) const; KGpgItemModel *m_model; bool m_onlysecret; bool m_encryptionKeys; KgpgCore::KgpgKeyTrustFlag m_mintrust; int m_previewsize; int m_idLength; KeyListProxyModel::DisplayMode m_displaymode; int m_emailSorting; QString reorderEmailComponents(const QString &emailAddress) const; QVariant dataSingleColumn(const QModelIndex &index, int role, const KGpgNode *node) const; QVariant dataMultiColumn(const QModelIndex &index, int role, const KGpgNode *node) const; }; KeyListProxyModelPrivate::KeyListProxyModelPrivate(KeyListProxyModel *parent, const KeyListProxyModel::DisplayMode mode) : q_ptr(parent), m_model(nullptr), m_onlysecret(false), m_encryptionKeys(false), m_mintrust(TRUST_UNKNOWN), m_previewsize(22), m_idLength(8), m_displaymode(mode), m_emailSorting(KGpgSettings::emailSorting()) { } /** * Reverses the list's order (this modifies the list) and returns * a string containing the reversed list's elements joined by a char. */ static QString reverseListAndJoinWithChar(const QStringList &list, const QChar &separator) { QString result = list.last(); for (int i = list.count() - 2; i >= 0; --i) result.append(separator).append(list[i]); return result; } QString KeyListProxyModelPrivate::reorderEmailComponents(const QString &emailAddress) const { if (emailAddress.isEmpty()) return QString(); /// split email addresses at @ static const QChar charAt = QLatin1Char('@'); /// split domain at . static const QChar charDot = QLatin1Char('.'); QString result = emailAddress; switch (m_emailSorting) { case KGpgSettings::EnumEmailSorting::TLDfirst: { /// get components of an email address /// john.doe@mail.kde.org becomes [john.doe, mail.kde.org] const QStringList emailComponents = result.split(charAt); if (emailComponents.count() != 2) /// expect an email address to contain exactly one @ break; /// get components of a domain /// mail.kde.org becomes [mail, kde, org] const QString fqdn = emailComponents.last(); QStringList fqdnComponents = fqdn.split(charDot); if (fqdnComponents.count() < 2) /// if domain consists of less than two components ... return fqdn + charDot + emailComponents.first(); /// ... take shortcut /// prepend localpart, will be last after list is reversed fqdnComponents.insert(0, emailComponents.first()); /// reverse components of domain, result becomes e.g. org.kde.mail /// with localpart already in the list it becomes org.kde.mail.john.doe result = reverseListAndJoinWithChar(fqdnComponents, charDot); break; } case KGpgSettings::EnumEmailSorting::DomainFirst: { /// get components of an email address /// john.doe@mail.kde.org becomes [john.doe, mail.kde.org] const QStringList emailComponents = result.split(charAt); if (emailComponents.count() != 2) /// expect an email address to contain exactly one @ break; /// get components of a domain /// mail.kde.org becomes [mail, kde, org] const QString fqdn = emailComponents.last(); QStringList fqdnComponents = fqdn.split(charDot); if (fqdnComponents.count() < 2) /// if domain consists of less than two components ... return fqdn + charDot + emailComponents.first(); /// ... take shortcut /// reverse last two components of domain, becomes e.g. kde.org /// TODO will fail for three-part domains like kde.org.uk result = charDot + fqdnComponents.takeLast(); result.prepend(fqdnComponents.takeLast()); /// append remaining components of domain, becomes e.g. kde.org.mail result.append(charDot).append(fqdnComponents.join(charDot)); /// append user name component of email address, becomes e.g. kde.org.mail.john.doe result.append(charDot).append(emailComponents.first()); break; } case KGpgSettings::EnumEmailSorting::FQDNFirst: { /// get components of an email address /// john.doe@mail.kde.org becomes [john.doe, mail.kde.org] const QStringList emailComponents = result.split(charAt); /// assemble result by joining components in reverse order, /// separated by a dot, becomes e.g. mail.kde.org.john.doe result = reverseListAndJoinWithChar(emailComponents, charDot); break; } case KGpgSettings::EnumEmailSorting::Alphabetical: /// do not modify email address break; } return result; } QVariant KeyListProxyModelPrivate::dataSingleColumn(const QModelIndex &index, int role, const KGpgNode *node) const { Q_Q(const KeyListProxyModel); if (index.column() != 0) return QVariant(); switch (role) { case Qt::DecorationRole: if (node->getType() == ITYPE_UAT) { if (m_previewsize > 0) { const KGpgUatNode *nd = node->toUatNode(); return nd->getPixmap().scaled(m_previewsize + 5, m_previewsize, Qt::KeepAspectRatio); } else { return Images::photo(); } } else { return m_model->data(q->mapToSource(index), Qt::DecorationRole); } case Qt::DisplayRole: { const QModelIndex srcidx(q->mapToSource(index)); const int srcrow = srcidx.row(); const QModelIndex ididx(srcidx.sibling(srcrow, KEYCOLUMN_ID)); const QString id(m_model->data(ididx, Qt::DisplayRole).toString().right(m_idLength)); const QModelIndex mailidx(srcidx.sibling(srcrow, KEYCOLUMN_EMAIL)); const QString mail(m_model->data(mailidx, Qt::DisplayRole).toString()); const QModelIndex nameidx(srcidx.sibling(srcrow, KEYCOLUMN_NAME)); const QString name(m_model->data(nameidx, Qt::DisplayRole).toString()); if (m_displaymode == KeyListProxyModel::SingleColumnIdFirst) { if (mail.isEmpty()) return i18nc("ID: Name", "%1: %2", id, name); else return i18nc("ID: Name ", "%1: %2 <%3>", id, name, mail); } else { if (mail.isEmpty()) return i18nc("Name: ID", "%1: %2", name, id); else return i18nc("Name : ID", "%1 <%2>: %3", name, mail, id); } } case Qt::ToolTipRole: { const QModelIndex srcidx(q->mapToSource(index)); const int srcrow = srcidx.row(); const QModelIndex ididx(srcidx.sibling(srcrow, KEYCOLUMN_ID)); return m_model->data(ididx, Qt::DisplayRole); } default: return QVariant(); } } QVariant KeyListProxyModelPrivate::dataMultiColumn(const QModelIndex &index, int role, const KGpgNode *node) const { Q_Q(const KeyListProxyModel); if ((node->getType() == ITYPE_UAT) && (role == Qt::DecorationRole) && (index.column() == 0)) { if (m_previewsize > 0) { const KGpgUatNode *nd = node->toUatNode(); return nd->getPixmap().scaled(m_previewsize + 5, m_previewsize, Qt::KeepAspectRatio); } else { return Images::photo(); } } else if ((role == Qt::DisplayRole) && (index.column() == KEYCOLUMN_ID)) { QString id = m_model->data(q->mapToSource(index), Qt::DisplayRole).toString(); return id.right(m_idLength); } return m_model->data(q->mapToSource(index), role); } KeyListProxyModel::KeyListProxyModel(QObject *parent, const DisplayMode mode) : QSortFilterProxyModel(parent), d_ptr(new KeyListProxyModelPrivate(this, mode)) { setFilterCaseSensitivity(Qt::CaseInsensitive); setFilterKeyColumn(-1); setDynamicSortFilter(true); } KeyListProxyModel::~KeyListProxyModel() { delete d_ptr; } bool KeyListProxyModel::hasChildren(const QModelIndex &idx) const { return sourceModel()->hasChildren(mapToSource(idx)); } void KeyListProxyModel::setKeyModel(KGpgItemModel *md) { Q_D(KeyListProxyModel); d->m_model = md; setSourceModel(md); } bool KeyListProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { Q_D(const KeyListProxyModel); KGpgNode *l = d->m_model->nodeForIndex(left); KGpgNode *r = d->m_model->nodeForIndex(right); return d->lessThan(l, r, left.column()); } bool KeyListProxyModelPrivate::lessThan(const KGpgNode *left, const KGpgNode *right, const int column) const { const KGpgRootNode * const r = m_model->getRootNode(); Q_ASSERT(r != left); Q_ASSERT(r != right); if (r == left->getParentKeyNode()) { if (r == right->getParentKeyNode()) { if (left->getType() == ITYPE_GROUP) { if (right->getType() == ITYPE_GROUP) return left->getName() < right->getName(); else return true; } else if (right->getType() == ITYPE_GROUP) return false; // we don't need to care about group members here because they will never have root as parent bool test1 = (left->getType() & ITYPE_PUBLIC) && !(left->getType() & ITYPE_SECRET); // only a public key bool test2 = (right->getType() & ITYPE_PUBLIC) && !(right->getType() & ITYPE_SECRET); // only a public key // key-pair goes before simple public key // extra check needed to get sorting by trust right if (left->getType() == ITYPE_PAIR && test2) return (column != KEYCOLUMN_TRUST); if (right->getType() == ITYPE_PAIR && test1) return (column == KEYCOLUMN_TRUST); return nodeLessThan(left, right, column); } else { return lessThan(left, right->getParentKeyNode(), column); } } else { if (r == right->getParentKeyNode()) { return lessThan(left->getParentKeyNode(), right, column); } else if (left->getParentKeyNode() == right->getParentKeyNode()) { if (left->getType() != right->getType()) return (left->getType() < right->getType()); return nodeLessThan(left, right, column); } else { return lessThan(left->getParentKeyNode(), right->getParentKeyNode(), column); } } return false; } bool KeyListProxyModelPrivate::nodeLessThan(const KGpgNode *left, const KGpgNode *right, const int column) const { Q_ASSERT(left->getType() == right->getType()); switch (column) { case KEYCOLUMN_NAME: if (left->getType() == ITYPE_SIGN) { const bool leftIsId = static_cast(left)->getRefNode() == nullptr; const bool rightIsId = static_cast(right)->getRefNode() == nullptr; if (leftIsId && !rightIsId) return false; else if (!leftIsId && rightIsId) return true; else if (leftIsId && rightIsId) return (left->getId() < right->getId()); } return (left->getName().compare(right->getName(), Qt::CaseInsensitive) < 0); case KEYCOLUMN_EMAIL: /// reverse email address to sort by TLD first, then domain, and account name last return (reorderEmailComponents(left->getEmail()).compare(reorderEmailComponents(right->getEmail()), Qt::CaseInsensitive) < 0); case KEYCOLUMN_TRUST: return (left->getTrust() < right->getTrust()); case KEYCOLUMN_EXPIR: return (left->getExpiration() < right->getExpiration()); case KEYCOLUMN_SIZE: if ((left->getType() & ITYPE_PAIR) && (right->getType() & ITYPE_PAIR)) { unsigned int lsign, lenc, rsign, renc; if (left->getType() & ITYPE_GROUP) { const KGpgGroupMemberNode *g = static_cast(left); lsign = g->getSignKeySize(); lenc = g->getEncryptionKeySize(); } else { const KGpgKeyNode *g = static_cast(left); lsign = g->getSignKeySize(); lenc = g->getEncryptionKeySize(); } if (right->getType() & ITYPE_GROUP) { const KGpgGroupMemberNode *g = static_cast(right); rsign = g->getSignKeySize(); renc = g->getEncryptionKeySize(); } else { const KGpgKeyNode *g = static_cast(right); rsign = g->getSignKeySize(); renc = g->getEncryptionKeySize(); } if (lsign != rsign) return lsign < rsign; else return lenc < renc; } else { return (left->getSize() < right->getSize()); } case KEYCOLUMN_CREAT: return (left->getCreation() < right->getCreation()); default: Q_ASSERT(column == KEYCOLUMN_ID); - return (left->getId().right(m_idLength) < right->getId().right(m_idLength)); + return (left->getId().rightRef(m_idLength).compare(right->getId().rightRef(m_idLength)) < 0); } } bool KeyListProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { Q_D(const KeyListProxyModel); QModelIndex idx = d->m_model->index(source_row, 0, source_parent); const KGpgNode *l = d->m_model->nodeForIndex(idx); if (l == d->m_model->getRootNode()) return false; if (d->m_onlysecret) { switch (l->getType()) { case ITYPE_PUBLIC: case ITYPE_GPUBLIC: case ITYPE_GROUP: return false; default: break; } } switch (d->m_displaymode) { case SingleColumnIdFirst: case SingleColumnIdLast: if (l->getType() == ITYPE_GROUP) return false; default: break; } if (l->getTrust() < d->m_mintrust) return false; /* check for expired signatures */ if ((d->m_mintrust > TRUST_EXPIRED) && (l->getType() == ITYPE_SIGN)) { const QDateTime expDate = l->toSignNode()->getExpiration(); if (expDate.isValid() && (expDate < QDateTime::currentDateTime())) return false; } if (l->getParentKeyNode() != d->m_model->getRootNode()) return true; if (d->m_encryptionKeys && ((l->getType() & ITYPE_GROUP) == 0)) { if (!l->toKeyNode()->canEncrypt()) return false; } if (l->getName().contains(filterRegExp())) return true; if (l->getEmail().contains(filterRegExp())) return true; if (l->getId().contains(filterRegExp())) return true; return false; } void KeyListProxyModel::setOnlySecret(const bool b) { Q_D(KeyListProxyModel); d->m_onlysecret = b; invalidateFilter(); } void KeyListProxyModel::settingsChanged() { Q_D(KeyListProxyModel); const int newSort = KGpgSettings::emailSorting(); if (newSort != d->m_emailSorting) { d->m_emailSorting = newSort; invalidate(); } } void KeyListProxyModel::setTrustFilter(const KgpgCore::KgpgKeyTrustFlag t) { Q_D(KeyListProxyModel); d->m_mintrust = t; invalidateFilter(); } void KeyListProxyModel::setEncryptionKeyFilter(bool b) { Q_D(KeyListProxyModel); d->m_encryptionKeys = b; invalidateFilter(); } KGpgNode * KeyListProxyModel::nodeForIndex(const QModelIndex &index) const { Q_D(const KeyListProxyModel); return d->m_model->nodeForIndex(mapToSource(index)); } QModelIndex KeyListProxyModel::nodeIndex(KGpgNode *node) { Q_D(KeyListProxyModel); return mapFromSource(d->m_model->nodeIndex(node)); } void KeyListProxyModel::setPreviewSize(const int pixel) { Q_D(KeyListProxyModel); emit layoutAboutToBeChanged(); d->m_previewsize = pixel; emit layoutChanged(); } QVariant KeyListProxyModel::data(const QModelIndex &index, int role) const { Q_D(const KeyListProxyModel); if (!index.isValid()) return QVariant(); const KGpgNode *node = nodeForIndex(index); switch (d->m_displaymode) { case MultiColumn: return d->dataMultiColumn(index, role, node); case SingleColumnIdFirst: case SingleColumnIdLast: return d->dataSingleColumn(index, role, node); } Q_ASSERT(0); return QVariant(); } KGpgItemModel * KeyListProxyModel::getModel() const { Q_D(const KeyListProxyModel); return d->m_model; } int KeyListProxyModel::idLength() const { Q_D(const KeyListProxyModel); return d->m_idLength; } void KeyListProxyModel::setIdLength(const int length) { Q_D(KeyListProxyModel); if (length == d->m_idLength) return; d->m_idLength = length; invalidate(); } bool KeyListProxyModel::setData(const QModelIndex &index, const QVariant &value, int role) { Q_UNUSED(role); if (value.type() != QVariant::String) return false; KGpgNode *node = nodeForIndex(index); if (!node) return false; const QString newName = value.toString(); if (newName.isEmpty() || (newName == node->getName())) return false; node->toGroupNode()->rename(newName); return true; } Qt::ItemFlags KeyListProxyModel::flags(const QModelIndex &index) const { KGpgNode *node = nodeForIndex(index); Qt::ItemFlags flags = QSortFilterProxyModel::flags(index); if ((node->getType() == ITYPE_GROUP) && (index.column() == KEYCOLUMN_NAME)) flags |= Qt::ItemIsEditable; return flags; } diff --git a/model/kgpgitemmodel.cpp b/model/kgpgitemmodel.cpp index 4249c9c5..bf29b21f 100644 --- a/model/kgpgitemmodel.cpp +++ b/model/kgpgitemmodel.cpp @@ -1,566 +1,566 @@ /* Copyright 2008,2009,2010,2011,2012,2013,2016,2017 Rolf Eike Beer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "kgpgitemmodel.h" #include "gpgproc.h" #include "kgpgsettings.h" #include "core/convert.h" #include "core/images.h" #include "model/kgpgitemnode.h" #include #include #include KGpgItemModel::KGpgItemModel(QObject *parent) : QAbstractItemModel(parent), m_root(new KGpgRootNode(this)), m_default(KGpgSettings::defaultKey()) { QMetaObject::invokeMethod(this, "refreshGroups", Qt::QueuedConnection); } KGpgItemModel::~KGpgItemModel() { delete m_root; } QModelIndex KGpgItemModel::index(int row, int column, const QModelIndex &parent) const { if (hasIndex(row, column, parent)) { KGpgNode *parentNode = nodeForIndex(parent); KGpgNode *childNode = parentNode->getChild(row); return createIndex(row, column, childNode); } return QModelIndex(); } QModelIndex KGpgItemModel::parent(const QModelIndex &child) const { if (!child.isValid()) return QModelIndex(); KGpgNode *childNode = nodeForIndex(child); KGpgNode *parentNode = childNode->m_parent; if (parentNode == m_root) return QModelIndex(); Q_ASSERT(parentNode != nullptr); int row = rowForNode(parentNode); int column = 0; return createIndex(row, column, parentNode); } int KGpgItemModel::rowCount(const QModelIndex &parent) const { if (parent.column() > 0) return 0; KGpgNode *parentNode = nodeForIndex(parent); return parentNode->getChildCount(); } bool KGpgItemModel::hasChildren(const QModelIndex &parent) const { if (parent.column() > 0) return false; KGpgNode *parentNode = nodeForIndex(parent); return parentNode->hasChildren(); } QVariant KGpgItemModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); KGpgNode *node = nodeForIndex(index); if (role == Qt::FontRole) { QFont f; f.setBold(isDefaultKey(node)); return f; } switch (index.column()) { case KEYCOLUMN_NAME: switch (role) { case Qt::DisplayRole: case Qt::EditRole: return node->getName(); case Qt::DecorationRole: switch (node->getType()) { case ITYPE_GROUP: return Images::group(); case ITYPE_GSECRET: case ITYPE_SECRET: return Images::orphan(); case ITYPE_GPUBLIC: case ITYPE_SUB: case ITYPE_PUBLIC: return Images::single(); case ITYPE_GPAIR: case ITYPE_PAIR: return Images::pair(); case ITYPE_UID: return Images::userId(); case ITYPE_UAT: return node->toUatNode()->getPixmap(); case ITYPE_REVSIGN: return Images::revoke(); case ITYPE_SIGN: return Images::signature(); default: Q_ASSERT(0); return QVariant(); } case Qt::ToolTipRole: return node->getComment(); } break; case KEYCOLUMN_EMAIL: if (role == Qt::DisplayRole) return node->getEmail(); break; case KEYCOLUMN_TRUST: { KgpgKeyTrust t = node->getTrust(); switch(node->getType()) { case ITYPE_PAIR: case ITYPE_PUBLIC: if(!node->toKeyNode()->getKey()->valid()) t = TRUST_DISABLED; break; default: break; } switch (role) { case Qt::BackgroundColorRole: switch (t) { case TRUST_INVALID: case TRUST_DISABLED: return KGpgSettings::colorBad(); case TRUST_EXPIRED: return KGpgSettings::colorExpired(); case TRUST_MARGINAL: return KGpgSettings::colorMarginal(); case TRUST_REVOKED: return KGpgSettings::colorRev(); case TRUST_UNDEFINED: case TRUST_NONE: return KGpgSettings::colorUnknown(); case TRUST_FULL: return KGpgSettings::colorGood(); case TRUST_ULTIMATE: return KGpgSettings::colorUltimate(); case TRUST_UNKNOWN: default: return KGpgSettings::colorUnknown(); } case Qt::AccessibleTextRole: return Convert::toString(t); case Qt::ToolTipRole: switch(node->getType()) { case ITYPE_PAIR: case ITYPE_PUBLIC: return i18n("Trust: %1
Owner Trust: %2", Convert::toString(node->getTrust()), Convert::toString(node->toKeyNode()->getKey()->ownerTrust())); default: return i18n("Trust: %1", Convert::toString(node->getTrust())); } } break; } case KEYCOLUMN_EXPIR: if (role == Qt::DisplayRole) return QLocale().toString(node->getExpiration().date(), QLocale::ShortFormat); break; case KEYCOLUMN_SIZE: switch (role) { case Qt::DisplayRole: return node->getSize(); case Qt::ToolTipRole: switch (node->getType()) { case ITYPE_PAIR: case ITYPE_PUBLIC: return node->toKeyNode()->getSignCount(); case ITYPE_UAT: return node->toUatNode()->getSignCount(); case ITYPE_UID: return node->toUidNode()->getSignCount(); case ITYPE_SUB: return node->toSubkeyNode()->getSignCount(); } } break; case KEYCOLUMN_CREAT: if (role == Qt::DisplayRole) return QLocale().toString(node->getCreation().date(), QLocale::ShortFormat); break; case KEYCOLUMN_ID: switch (role) { case Qt::DisplayRole: return node->getId(); case Qt::ToolTipRole: switch (node->getType()) { case ITYPE_PAIR: case ITYPE_PUBLIC: return node->toKeyNode()->getFingerprint(); case ITYPE_SECRET: return node->toOrphanNode()->getFingerprint(); case ITYPE_SUB: return node->toSubkeyNode()->getFingerprint(); default: return QVariant(); } default: return QVariant(); } break; } return QVariant(); } KGpgNode * KGpgItemModel::nodeForIndex(const QModelIndex &index) const { if (index.isValid()) return static_cast(index.internalPointer()); return m_root; } KGpgKeyNode * KGpgItemModel::findKeyNode(const QString& id) const { return m_root->findKey(id); } int KGpgItemModel::rowForNode(KGpgNode *node) const { return node->m_parent->getChildIndex(node); } KGpgRootNode * KGpgItemModel::getRootNode() const { return m_root; } QString KGpgItemModel::statusCountMessage() const { const int groups = m_root->groupChildren(); const int keys = m_root->getChildCount() - groups; return statusCountMessageString(keys, groups); } QString KGpgItemModel::statusCountMessageString(const unsigned int keys, const unsigned int groups) { // Most people will not have groups. Handle this case // special so the string isn't displayed in this case at all if (groups == 0) { return i18np("1 Key", "%1 Keys", keys); } const QString keyString = i18np("1 Key", "%1 Keys", keys); const QString groupString = i18np("1 Group", "%1 Groups", groups); return i18nc("%1 = something like 7 keys, %2 = something like 2 groups", "%1, %2", keyString, groupString); } KGpgGroupNode * KGpgItemModel::addGroup(const QString &name, const KGpgKeyNode::List &keys) { KGpgGroupNode *nd; const int cIndex = m_root->getChildCount(); // row of the new node beginInsertRows(QModelIndex(), cIndex, cIndex); nd = new KGpgGroupNode(m_root, name, keys); endInsertRows(); nd->saveMembers(); Q_ASSERT(m_root->getChildIndex(nd) == cIndex); return nd; } void KGpgItemModel::delNode(KGpgNode *node) { beginResetModel(); delete node; endResetModel(); } void KGpgItemModel::changeGroup(KGpgGroupNode *node, const KGpgNode::List &keys) { const QModelIndex gIndex = nodeIndex(node); for (int i = node->getChildCount() - 1; i >= 0; i--) { bool found = false; for (const KGpgNode *nd : keys) { found = (node->getChild(i)->getId() == nd->getId()); if (found) break; } if (found) continue; beginRemoveRows(gIndex, i, i); delete node->getChild(i); endRemoveRows(); } int cnt = node->getChildCount(); for (int i = 0; i < keys.count(); i++) { bool found = false; for (const KGpgNode *nd : node->getChildren()) { found = (nd->getId() == keys.at(i)->getId()); if (found) break; } if (found) continue; beginInsertRows(gIndex, cnt, cnt); new KGpgGroupMemberNode(node, keys.at(i)->toKeyNode()); endInsertRows(); cnt++; } node->saveMembers(); } void KGpgItemModel::deleteFromGroup(KGpgGroupNode *group, KGpgGroupMemberNode *member) { Q_ASSERT(group == member->getParentKeyNode()); const int childRow = group->getChildIndex(member); const QModelIndex pIndex = nodeIndex(group); beginRemoveRows(pIndex, childRow, childRow); delete member; endRemoveRows(); group->saveMembers(); } QVariant KGpgItemModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) return QVariant(); if (orientation != Qt::Horizontal) return QVariant(); switch (section) { case KEYCOLUMN_NAME: return QString(i18n("Name")); case KEYCOLUMN_EMAIL: return QString(i18nc("@title:column Title of a column of emails", "Email")); case KEYCOLUMN_TRUST: return QString(i18n("Trust")); case KEYCOLUMN_SIZE: return QString(i18n("Size")); case KEYCOLUMN_EXPIR: return QString(i18n("Expiration")); case KEYCOLUMN_CREAT: return QString(i18n("Creation")); case KEYCOLUMN_ID: return QString(i18n("ID")); default: return QVariant(); } } void KGpgItemModel::setDefaultKey(KGpgKeyNode *def) { int defrow = m_root->findKeyRow(def); int odefrow = m_root->findKeyRow(m_default); if (defrow == odefrow) return; int lastcol = columnCount(QModelIndex()) - 1; if (odefrow >= 0) { KGpgNode *nd = m_root->getChild(odefrow); emit dataChanged(createIndex(odefrow, 0, nd), createIndex(odefrow, lastcol, nd)); } if (def) { m_default = def->getId(); emit dataChanged(createIndex(defrow, 0, def), createIndex(defrow, lastcol, def)); } else { m_default.clear(); } } QModelIndex KGpgItemModel::nodeIndex(KGpgNode *node, const int column) { KGpgNode *p = node->getParentKeyNode(); for (int i = 0; i < p->getChildCount(); i++) if (p->getChild(i) == node) return createIndex(i, column, node); Q_ASSERT(0); return QModelIndex(); } static QStringList readGroups() { return GPGProc::getGgpParsedConfig(KGpgSettings::gpgBinaryPath(), "group"); } void KGpgItemModel::refreshKeys(const QStringList &ids) { if (ids.isEmpty()) { refreshAllKeys(); } else { beginResetModel(); QStringList::ConstIterator it = ids.constBegin(); const QStringList::ConstIterator itEnd = ids.constEnd(); KGpgKeyNode::List refreshNodes; QStringList addIds; for (; it != itEnd; ++it) { KGpgKeyNode *nd = m_root->findKey(*it); if (nd) refreshNodes << nd; else addIds << *it; } if (!refreshNodes.isEmpty()) m_root->refreshKeys(refreshNodes); if (!addIds.isEmpty()) m_root->addKeys(addIds); endResetModel(); } } void KGpgItemModel::refreshKeys(KGpgKeyNode::List keys) { beginResetModel(); m_root->refreshKeys(keys); endResetModel(); } void KGpgItemModel::refreshAllKeys() { beginResetModel(); for (int i = m_root->getChildCount() - 1; i >= 0; i--) delete m_root->getChild(i); m_root->addKeys(); m_root->addGroups(readGroups()); endResetModel(); } void KGpgItemModel::refreshGroups() { for (int i = m_root->getChildCount() - 1; i >= 0; i--) { KGpgNode *nd = m_root->getChild(i); if (nd->getType() != ITYPE_GROUP) continue; beginRemoveRows(QModelIndex(), i, i); delete nd; endRemoveRows(); } const QStringList groups = readGroups(); if (groups.isEmpty()) return; const int oldCount = m_root->getChildCount(); beginInsertRows(QModelIndex(), oldCount, oldCount + groups.count()); m_root->addGroups(groups); endInsertRows(); } bool KGpgItemModel::isDefaultKey(const KGpgNode *node) const { - return !m_default.isEmpty() && (m_default == node->getId().right(m_default.length())); + return !m_default.isEmpty() && (node->getId().rightRef(m_default.length()).compare(m_default) == 0); } void KGpgItemModel::invalidateIndexes(KGpgNode *nd) { const auto indexList = persistentIndexList(); for (const QModelIndex &idx : indexList) { KGpgNode *n = nodeForIndex(idx); if (n != nd) continue; changePersistentIndex(idx, QModelIndex()); } } void KGpgItemModel::refreshTrust(const KgpgCore::KgpgKeyTrust trust, const QColor& color) { updateNodeTrustColor(m_root, trust, color); } void KGpgItemModel::updateNodeTrustColor(KGpgExpandableNode *node, const KgpgCore::KgpgKeyTrust trust, const QColor &color) { for (int i = 0; i < node->getChildCount(); i++) { KGpgNode *child = node->getChild(i); if (child->getTrust() == trust) emit dataChanged(createIndex(i, KEYCOLUMN_TRUST, child), createIndex(i, KEYCOLUMN_TRUST, child)); if (!child->hasChildren()) continue; KGpgExpandableNode *echild = child->toExpandableNode(); if (echild->wasExpanded()) updateNodeTrustColor(echild, trust, color); } } diff --git a/transactions/kgpgdelsign.cpp b/transactions/kgpgdelsign.cpp index e9f2ee47..536e476c 100644 --- a/transactions/kgpgdelsign.cpp +++ b/transactions/kgpgdelsign.cpp @@ -1,138 +1,138 @@ /* * Copyright (C) 2010,2012 Rolf Eike Beer */ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "kgpgdelsign.h" #include "model/kgpgitemnode.h" #include "gpgproc.h" #include KGpgDelSign::KGpgDelSign(QObject *parent, const KGpgSignNode::List &signids) : KGpgUidTransaction(parent, signids.at(0)->getParentKeyNode()->getId()) { addArgument(QLatin1String( "delsig" )); const QStringList args = getProcess()->program(); // If we run with --no-tty GnuPG will not tell which sign it is currently // asking to remove :( int ntty = args.indexOf(QLatin1String("--no-tty")); if (ntty >= 0) replaceArgument(ntty, QLatin1String("--with-colons")); else insertArgument(1, QLatin1String( "--with-colons" )); if (signids.at(0)->getParentKeyNode()->getType() & KgpgCore::ITYPE_PUBLIC) setUid(QLatin1String( "1" )); else setUid(signids.at(0)->getParentKeyNode()->getId()); #ifndef QT_NO_DEBUG for (const KGpgSignNode *snode : signids) { Q_ASSERT(signids.at(0)->getParentKeyNode() == snode->getParentKeyNode()); } #endif setSignIds(signids); } KGpgDelSign::KGpgDelSign(QObject* parent, KGpgSignNode *signid) : KGpgUidTransaction(parent, signid->getParentKeyNode()->getId()) { addArgument(QLatin1String( "delsig" )); insertArgument(1, QLatin1String( "--with-colons" )); if (signid->getParentKeyNode()->getType() & KgpgCore::ITYPE_PUBLIC) setUid(QLatin1String( "1" )); else setUid(signid->getParentKeyNode()->getId()); setSignId(signid); } KGpgDelSign::~KGpgDelSign() { } KGpgSignNode::List KGpgDelSign::getSignIds(void) const { return m_signids; } void KGpgDelSign::setSignId(KGpgSignNode* keyid) { m_signids.clear(); m_signids << keyid; } void KGpgDelSign::setSignIds(const KGpgSignNode::List &keyids) { m_signids = keyids; } bool KGpgDelSign::nextLine(const QString &line) { if (line.startsWith(QLatin1String("sig:"))) { m_cachedid = line; return false; } else if (line.startsWith(QLatin1String("[GNUPG:] "))) { return standardCommands(line); } else { // GnuPG will tell us a bunch of stuff because we are not in // --no-tty mode but we don't care. return false; } } KGpgTransaction::ts_boolanswer KGpgDelSign::boolQuestion(const QString &line) { if (line.startsWith(QLatin1String("keyedit.delsig."))) { const QStringList parts = m_cachedid.split(QLatin1Char( ':' )); if (parts.count() < 7) return KGpgTransaction::BA_NO; const QString &sigid = parts[4]; const int snlen = sigid.length(); KGpgSignNode *signode = nullptr; for (KGpgSignNode *snode : qAsConst(m_signids)) { - if (sigid == snode->getId().right(snlen)) { + if (snode->getId().rightRef(snlen).compare(sigid) == 0) { signode = snode; break; } } if (signode == nullptr) return KGpgTransaction::BA_NO; const QDateTime creation = QDateTime::fromTime_t(parts[5].toUInt()); if (creation != signode->getCreation()) return KGpgTransaction::BA_NO; QDateTime sigexp; if (!parts[6].isEmpty() && (parts[6] != QLatin1String("0"))) sigexp = QDateTime::fromTime_t(parts[6].toUInt()); if (sigexp != signode->getExpiration()) return KGpgTransaction::BA_NO; m_signids.removeOne(signode); return KGpgTransaction::BA_YES; } else { return KGpgTransaction::boolQuestion(line); } } diff --git a/transactions/kgpgimport.cpp b/transactions/kgpgimport.cpp index 13051324..fbfbb0fd 100644 --- a/transactions/kgpgimport.cpp +++ b/transactions/kgpgimport.cpp @@ -1,287 +1,287 @@ /* * Copyright (C) 2008,2009,2010,2012 Rolf Eike Beer */ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "kgpgimport.h" #include "kgpg_general_debug.h" #include "model/kgpgitemmodel.h" #include "core/KGpgKeyNode.h" #include KGpgImport::KGpgImport(QObject *parent, const QString &text) : KGpgTextOrFileTransaction(parent, text, true) { } KGpgImport::KGpgImport(QObject *parent, const QList &files) : KGpgTextOrFileTransaction(parent, files, true) { } KGpgImport::~KGpgImport() { } QStringList KGpgImport::command() const { QStringList ret; ret << QLatin1String( "--import" ) << QLatin1String( "--allow-secret-key-import" ); return ret; } QStringList KGpgImport::getImportedKeys() const { QStringList res; for (const QString &str : getMessages()) if (str.startsWith(QLatin1String("[GNUPG:] IMPORTED "))) res << str.mid(18); return res; } QStringList KGpgImport::getImportedIds(const QStringList &log, const int reason) { QStringList res; for (const QString &str : log) { if (!str.startsWith(QLatin1String("[GNUPG:] IMPORT_OK "))) continue; QString tmpstr(str.mid(19).simplified()); int space = tmpstr.indexOf(QLatin1Char( ' ' )); if (space <= 0) { qCDebug(KGPG_LOG_GENERAL) << __LINE__ << "invalid format:" << str; continue; } bool ok; - unsigned char code = tmpstr.left(space).toUInt(&ok); + unsigned char code = tmpstr.leftRef(space).toUInt(&ok); if (!ok) { - qCDebug(KGPG_LOG_GENERAL) << __LINE__ << "invalid format:" << str << space << tmpstr.left(space - 1); + qCDebug(KGPG_LOG_GENERAL) << __LINE__ << "invalid format:" << str << space << tmpstr.leftRef(space - 1); continue; } if ((reason == -1) || ((reason == 0) && (code == 0)) || ((reason & code) != 0)) res << tmpstr.mid(space + 1); } return res; } QStringList KGpgImport::getImportedIds(const int reason) const { return getImportedIds(getMessages(), reason); } QString KGpgImport::getImportMessage() const { return getImportMessage(getMessages()); } QString KGpgImport::getImportMessage(const QStringList &log) { #define RESULT_PARTS_MIN 14 #define RESULT_PARTS_MAX 15 unsigned long rcode[RESULT_PARTS_MAX]; int line = 0; bool fine = false; memset(rcode, 0, sizeof(rcode)); for (const QString &str : log) { line++; if (!str.startsWith(QLatin1String("[GNUPG:] IMPORT_RES "))) continue; const QStringList rstr = str.mid(20).simplified().split(QLatin1Char(' ')); bool syn = (rstr.count() >= RESULT_PARTS_MIN); for (int i = std::min(rstr.count(), RESULT_PARTS_MAX) - 1; (i >= 0) && syn; i--) { rcode[i] += rstr.at(i).toULong(&syn); fine |= (rcode[i] != 0); } if (!syn) return xi18nc("@info", "The import result string has an unsupported format in line %1.Please see the detailed log for more information.", line); } if (!fine) return i18n("No key imported.
Please see the detailed log for more information."); QString resultMessage(xi18ncp("@info", "%1 key processed.", "%1 keys processed.", rcode[0])); if (rcode[1]) resultMessage += xi18ncp("@info", "One key without ID.", "%1 keys without ID.", rcode[1]); if (rcode[2]) resultMessage += xi18ncp("@info", "One key imported:", "%1 keys imported:", rcode[2]); if (rcode[3]) resultMessage += xi18ncp("@info", "One RSA key imported.", "%1 RSA keys imported.", rcode[3]); if (rcode[4]) resultMessage += xi18ncp("@info", "One key unchanged.", "%1 keys unchanged.", rcode[4]); if (rcode[5]) resultMessage += xi18ncp("@info", "One user ID imported.", "%1 user IDs imported.", rcode[5]); if (rcode[6]) resultMessage += xi18ncp("@info", "One subkey imported.", "%1 subkeys imported.", rcode[6]); if (rcode[7]) resultMessage += xi18ncp("@info", "One signature imported.", "%1 signatures imported.", rcode[7]); if (rcode[8]) resultMessage += xi18ncp("@info", "One revocation certificate imported.", "%1 revocation certificates imported.", rcode[8]); if (rcode[9]) resultMessage += xi18ncp("@info", "One secret key processed.", "%1 secret keys processed.", rcode[9]); if (rcode[10]) resultMessage += xi18ncp("@info", "One secret key imported.", "%1 secret keys imported.", rcode[10]); if (rcode[11]) resultMessage += xi18ncp("@info", "One secret key unchanged.", "%1 secret keys unchanged.", rcode[11]); if (rcode[12]) resultMessage += xi18ncp("@info", "One secret key not imported.", "%1 secret keys not imported.", rcode[12]); if (rcode[9]) resultMessage += xi18nc("@info", "You have imported a secret key." "Please note that imported secret keys are not trusted by default." "To fully use this secret key for signing and encryption, you must edit the key (double click on it) and set its trust to Full or Ultimate."); return resultMessage; } static QString beautifyKeyList(const QStringList &keyIds, const KGpgItemModel *model) { QString result; result.append(QLatin1String("\n")); if (model == nullptr) { result.append(QLatin1String(" ") + keyIds.join(QLatin1String("\n "))); } else { for (const QString &changed : keyIds) { const KGpgKeyNode *node = model->findKeyNode(changed); QString line; if (node == nullptr) { line = changed; } else { if (node->getEmail().isEmpty()) line = xi18nc("@item ID: Name", "%1: %2", node->getFingerprint(), node->getName()); else line = xi18nc("@item ID: Name ", "%1: %2 %3", node->getFingerprint(), node->getName(), node->getEmail()); } result.append(QLatin1String(" ") + line + QLatin1String("\n")); } } return result; } QString KGpgImport::getDetailedImportMessage(const QStringList &log, const KGpgItemModel *model) { QString result; QMap resultcodes; for (const QString &keyresult : log) { if (!keyresult.startsWith(QLatin1String("[GNUPG:] IMPORT_OK "))) continue; QStringList rc(keyresult.mid(19).split(QLatin1Char( ' ' ))); if (rc.count() < 2) { qCDebug(KGPG_LOG_GENERAL) << "unexpected syntax:" << keyresult; continue; } resultcodes[rc.at(1)] = rc.at(0).toUInt(); } const QMap::const_iterator iterend = resultcodes.constEnd(); for (unsigned int flag = 1; flag <= 16; flag <<= 1) { QStringList thischanged; for (QMap::const_iterator iter = resultcodes.constBegin(); iter != iterend; ++iter) { if (iter.value() & flag) thischanged << iter.key(); } if (thischanged.isEmpty()) continue; switch (flag) { case 1: result.append(i18np("New Key", "New Keys", thischanged.count())); break; case 2: result.append(i18np("Key with new User Id", "Keys with new User Ids", thischanged.count())); break; case 4: result.append(i18np("Key with new Signatures", "Keys with new Signatures", thischanged.count())); break; case 8: result.append(i18np("Key with new Subkeys", "Keys with new Subkeys", thischanged.count())); break; case 16: result.append(i18np("New Private Key", "New Private Keys", thischanged.count())); break; default: Q_ASSERT(flag == 1); } result.append(beautifyKeyList(thischanged, model)); result.append(QLatin1String("\n\n")); } QStringList unchanged(resultcodes.keys(0)); if (unchanged.isEmpty()) { // remove empty line at end result.chop(1); } else { result.append(i18np("Unchanged Key", "Unchanged Keys", unchanged.count())); result.append(beautifyKeyList(unchanged, model)); result.append(QLatin1String("\n")); } return result; } int KGpgImport::isKey(const QString &text, const bool incomplete) { int markpos = text.indexOf(QLatin1String("-----BEGIN PGP PUBLIC KEY BLOCK-----")); if (markpos >= 0) { markpos = text.indexOf(QLatin1String("-----END PGP PUBLIC KEY BLOCK-----"), markpos); return ((markpos > 0) || incomplete) ? 1 : 0; } markpos = text.indexOf(QLatin1String("-----BEGIN PGP PRIVATE KEY BLOCK-----")); if (markpos < 0) return 0; markpos = text.indexOf(QLatin1String("-----END PGP PRIVATE KEY BLOCK-----"), markpos); if ((markpos < 0) && !incomplete) return 0; return 2; }