Page MenuHome GnuPG

No OneTemporary

diff --git a/src/aboutdata.cpp b/src/aboutdata.cpp
index ece78d1b6..9c5775c94 100644
--- a/src/aboutdata.cpp
+++ b/src/aboutdata.cpp
@@ -1,115 +1,115 @@
/*
aboutdata.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2001,2002,2004 Klarälvdalens Datakonsult AB
Kleopatra 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.
Kleopatra 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include <config-kleopatra.h>
#include <version-kleopatra.h>
#include "aboutdata.h"
#include <KLocalizedString>
static const char kleopatra_version[] = KLEOPATRA_VERSION_STRING;
static const char description[] = I18N_NOOP("Certificate Manager and Unified Crypto GUI");
struct about_data {
const char *name;
const char *desc;
const char *email;
const char *web;
};
static const about_data authors[] = {
{ "Andre Heinecke", I18N_NOOP("Current Maintainer"), "aheinecke@gnupg.org", nullptr },
{ "Marc Mutz", I18N_NOOP("Former Maintainer"), "mutz@kde.org", nullptr },
{ "Steffen Hansen", I18N_NOOP("Former Maintainer"), "hansen@kde.org", nullptr },
{ "Matthias Kalle Dalheimer", I18N_NOOP("Original Author"), "kalle@kde.org", nullptr },
};
static const about_data credits[] = {
{
I18N_NOOP("David Faure"),
I18N_NOOP("Backend configuration framework, KIO integration"),
"faure@kde.org", nullptr
},
{
I18N_NOOP("Michel Boyer de la Giroday"),
I18N_NOOP("Key-state dependent colors and fonts in the certificates list"),
"michel@klaralvdalens-datakonsult.se", nullptr
},
{
I18N_NOOP("Thomas Moenicke"),
I18N_NOOP("Artwork"),
"tm@php-qt.org", nullptr
},
{
I18N_NOOP("Frank Osterfeld"),
I18N_NOOP("Resident gpgme/win wrangler, UI Server commands and dialogs"),
"osterfeld@kde.org", nullptr
},
{
I18N_NOOP("Karl-Heinz Zimmer"),
I18N_NOOP("DN display ordering support, infrastructure"),
"khz@kde.org", nullptr
},
{
I18N_NOOP("Laurent Montel"),
I18N_NOOP("Qt5 port, general code maintenance"),
"montel@kde.org", nullptr
},
};
AboutData::AboutData()
: KAboutData(QStringLiteral("kleopatra"), i18n("Kleopatra"),
QLatin1String(kleopatra_version), i18n(description), KAboutLicense::GPL,
i18n("(c) 2002 Steffen\u00A0Hansen, Matthias\u00A0Kalle\u00A0" "Dalheimer, Klar\u00E4lvdalens\u00A0" "Datakonsult\u00A0" "AB\n"
"(c) 2004, 2007, 2008, 2009 Marc\u00A0Mutz, Klar\u00E4lvdalens\u00A0" "Datakonsult\u00A0" "AB") +
- '\n' + i18n("(c) 2010-2018 The Kleopatra developers")
+ QLatin1Char('\n') + i18n("(c) 2010-2018 The Kleopatra developers")
#ifdef Q_OS_WIN
, i18n("<a href=https://www.gpg4win.org>Visit the Gpg4win homepage</a>")
#endif
)
{
using ::authors;
using ::credits;
for (unsigned int i = 0; i < sizeof authors / sizeof * authors; ++i) {
addAuthor(i18n(authors[i].name), i18n(authors[i].desc),
QLatin1String(authors[i].email), QLatin1String(authors[i].web));
}
for (unsigned int i = 0; i < sizeof credits / sizeof * credits; ++i) {
addCredit(i18n(credits[i].name), i18n(credits[i].desc),
QLatin1String(credits[i].email), QLatin1String(credits[i].web));
}
#ifdef Q_OS_WIN
setBugAddress("https://dev.gnupg.org/u/rgpg4win");
#endif
}
diff --git a/src/commands/genrevokecommand.cpp b/src/commands/genrevokecommand.cpp
index 611ee72a1..d8f8edfb3 100644
--- a/src/commands/genrevokecommand.cpp
+++ b/src/commands/genrevokecommand.cpp
@@ -1,213 +1,213 @@
/* -*- mode: c++; c-basic-offset:4 -*-
commands/genrevokecommand.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2017 by Bundesamt für Sicherheit in der Informationstechnik
Software engineering by Intevation GmbH
Kleopatra 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.
Kleopatra 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include <config-kleopatra.h>
#include "genrevokecommand.h"
#include <utils/gnupg-helper.h>
#include <Libkleo/Formatting>
#include <gpgme++/key.h>
#include <KLocalizedString>
#include <KMessageBox>
#include <QProcess>
#include <QTextStream>
#include <QFile>
#include <QFileDialog>
#include "kleopatra_debug.h"
#include "command_p.h"
using namespace Kleo;
using namespace Kleo::Commands;
using namespace GpgME;
GenRevokeCommand::GenRevokeCommand(QAbstractItemView *v, KeyListController *c) :
GnuPGProcessCommand(v, c)
{
}
GenRevokeCommand::GenRevokeCommand(KeyListController *c)
: GnuPGProcessCommand(c)
{
}
GenRevokeCommand::GenRevokeCommand(const Key &key)
: GnuPGProcessCommand(key)
{
}
// Fixup the revocation certificate similar to GnuPG
void GenRevokeCommand::postSuccessHook(QWidget *parentWidget)
{
QFile f(mOutputFileName);
if (!f.open(QIODevice::ReadOnly)) {
// Should never happen because in this case we would not have had a success.
KMessageBox::error(parentWidget, errorCaption(),
QStringLiteral("Failed to access the created output file."));
return;
}
const QString revCert = f.readAll();
f.close();
if (!f.open(QIODevice::WriteOnly)) {
KMessageBox::error(parentWidget, errorCaption(),
QStringLiteral("Failed to write to the created output file."));
return;
}
QTextStream s(&f);
s << i18n("This is a revocation certificate for the OpenPGP key:")
<< "\n\n " << Formatting::prettyNameAndEMail(d->key())
<< "\n Fingerprint: " << d->key().primaryFingerprint() << "\n\n"
<< i18n("A revocation certificate is a kind of \"kill switch\" to publicly\n"
"declare that a key shall not anymore be used. It is not possible\n"
"to retract such a revocation certificate once it has been published.")
<< "\n\n"
<< i18n("Use it to revoke this key in case of a compromise or loss of\n"
"the secret key.")
<< "\n\n"
<< i18n("To avoid an accidental use of this file, a colon has been inserted\n"
"before the 5 dashes below. Remove this colon with a text editor\n"
"before importing and publishing this revocation certificate.")
<< "\n\n:"
<< revCert;
s.flush();
qCDebug(KLEOPATRA_LOG) << "revocation certificate stored as:" << mOutputFileName;
f.close();
KMessageBox::information(d->parentWidgetOrView(),
i18nc("@info", "Certificate successfully created.<br><br>"
"Note:<br>To prevent accidental import of the revocation<br>"
"it is required to manually edit the certificate<br>"
"before it can be imported."),
i18n("Revocation certificate created"));
}
/* Well not much to do with GnuPGProcessCommand anymore I guess.. */
void GenRevokeCommand::doStart()
{
while (mOutputFileName.isEmpty()) {
mOutputFileName = QFileDialog::getSaveFileName(d->parentWidgetOrView(), i18n("Generate revocation certificate"),
QString(),
QStringLiteral("%1 (*.rev)").arg(i18n("Revocation Certificates ")));
if (mOutputFileName.isEmpty()) {
d->finished();
return;
}
if (!mOutputFileName.endsWith(QLatin1String(".rev"))) {
- mOutputFileName += ".rev";
+ mOutputFileName += QLatin1String(".rev");
}
if (QFileInfo(mOutputFileName).exists()) {
auto sel = KMessageBox::questionYesNo(d->parentWidgetOrView(), i18n("The file <b>%1</b> already exists.\n"
"Overwrite?", mOutputFileName),
i18n("Overwrite Existing File?"));
if (sel == KMessageBox::No) {
mOutputFileName = QString();
}
}
}
auto proc = process();
// We do custom io
disconnect(proc, SIGNAL(readyReadStandardError()),
this, SLOT(slotProcessReadyReadStandardError()));
proc->setReadChannel(QProcess::StandardOutput);
GnuPGProcessCommand::doStart();
connect(proc, &QProcess::readyReadStandardOutput,
this, [proc] () {
while (proc->canReadLine()) {
const QString line = QString::fromUtf8(proc->readLine()).trimmed();
// Command-fd is a stable interface, while this is all kind of hacky we
// are on a deadline :-/
if (line == QStringLiteral("[GNUPG:] GET_BOOL gen_revoke.okay")) {
proc->write("y\n");
} else if (line == QStringLiteral("[GNUPG:] GET_LINE ask_revocation_reason.code")) {
proc->write("0\n");
} else if (line == QStringLiteral("[GNUPG:] GET_LINE ask_revocation_reason.text")) {
proc->write("\n");
} else if (line == QStringLiteral("[GNUPG:] GET_BOOL openfile.overwrite.okay")) {
// We asked before
proc->write("y\n");
} else if (line == QStringLiteral("[GNUPG:] GET_BOOL ask_revocation_reason.okay")) {
proc->write("y\n");
}
}
});
}
QStringList GenRevokeCommand::arguments() const
{
const Key key = d->key();
QStringList result;
- result << gpgPath() << "--command-fd" << "0" << "--status-fd" << "1"
+ result << gpgPath() << QStringLiteral("--command-fd") << QStringLiteral("0") << QStringLiteral("--status-fd") << QStringLiteral("1")
<< QStringLiteral("-o") << mOutputFileName
<< QStringLiteral("--gen-revoke")
<< QLatin1String(key.primaryFingerprint());
return result;
}
QString GenRevokeCommand::errorCaption() const
{
return i18nc("@title:window", "Error creating revocation certificate");
}
QString GenRevokeCommand::crashExitMessage(const QStringList &) const
{
// We show a success message so a failure is either the user aborted
// or a bug.
qCDebug(KLEOPATRA_LOG) << "Crash exit of GenRevokeCommand";
return QString();
}
QString GenRevokeCommand::errorExitMessage(const QStringList &) const
{
// We show a success message so a failure is either the user aborted
// or a bug.
qCDebug(KLEOPATRA_LOG) << "Error exit of GenRevokeCommand";
return QString();
}
diff --git a/src/commands/keytocardcommand.cpp b/src/commands/keytocardcommand.cpp
index acc294dc7..7c6b0e9e2 100644
--- a/src/commands/keytocardcommand.cpp
+++ b/src/commands/keytocardcommand.cpp
@@ -1,269 +1,269 @@
/* commands/setinitialpincommand.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2017 by Bundesamt für Sicherheit in der Informationstechnik
Software engineering by Intevation GmbH
Kleopatra 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.
Kleopatra 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include <config-kleopatra.h>
#include "keytocardcommand.h"
#include "kleopatra_debug.h"
#include "command_p.h"
#include "smartcard/readerstatus.h"
#include "smartcard/openpgpcard.h"
#include <QInputDialog>
#include <QDateTime>
#include <QStringList>
#include <KLocalizedString>
#include <gpgme++/gpgmepp_version.h>
#if GPGMEPP_VERSION > 0x10801
# define GPGME_SUBKEY_HAS_KEYGRIP
#endif
using namespace Kleo;
using namespace Kleo::Commands;
using namespace Kleo::SmartCard;
using namespace GpgME;
bool KeyToCardCommand::supported()
{
#ifdef GPGME_SUBKEY_HAS_KEYGRIP
return true;
#else
return false;
#endif
}
class KeyToCardCommand::Private : public Command::Private
{
friend class ::Kleo::Commands::KeyToCardCommand;
KeyToCardCommand *q_func() const
{
return static_cast<KeyToCardCommand *>(q);
}
public:
explicit Private(KeyToCardCommand *qq, const GpgME::Subkey &key, const std::string &serialno);
~Private();
private:
void start()
{
// Check if we need to ask the user for the slot
if ((mKey.canSign() || mKey.canCertify()) && !mKey.canEncrypt() && !mKey.canAuthenticate()) {
// Signing only
slotDetermined(1);
return;
}
if (mKey.canEncrypt() && !(mKey.canSign() || mKey.canCertify()) && !mKey.canAuthenticate()) {
// Encrypt only
slotDetermined(2);
return;
}
if (mKey.canAuthenticate() && !(mKey.canSign() || mKey.canCertify()) && !mKey.canEncrypt()) {
// Auth only
slotDetermined(3);
return;
}
// Multiple uses, ask user.
QStringList options;
if (mKey.canSign() || mKey.canCertify()) {
options << i18n("Signature") + QStringLiteral(" (1)");
}
if (mKey.canEncrypt()) {
options << i18n("Encryption") + QStringLiteral(" (2)");
}
if (mKey.canAuthenticate()) {
options << i18n("Authentication") + QStringLiteral(" (3)");
}
dialog = std::shared_ptr<QInputDialog> (new QInputDialog(parentWidgetOrView()));
dialog->setComboBoxItems(options);
connect(dialog.get(), &QDialog::rejected, q_func(), [this] () {finished();});
connect(dialog.get(), &QInputDialog::textValueSelected, q_func(), [this] (const QString &text) {
slotDetermined(text.at(text.size() - 1).digitValue());
});
}
void slotDetermined(int slot)
{
// Check if we need to do the overwrite warning.
const auto cards = ReaderStatus::instance()->getCards();
qDebug() << "slot determined" << slot;
bool cardFound = false;
std::string existingKey;
QString encKeyWarning;
for (const auto &card: cards) {
if (card->serialNumber() == mSerial) {
const auto pgpCard = dynamic_cast<SmartCard::OpenPGPCard*>(card.get());
Q_ASSERT(pgpCard);
cardFound = true;
if (slot == 1) {
existingKey = pgpCard->sigFpr();
break;
}
if (slot == 2) {
existingKey = pgpCard->encFpr();
encKeyWarning = i18n("It will no longer be possible to decrypt past communication "
"encrypted for the existing key.");
break;
}
if (slot == 3) {
existingKey = pgpCard->authFpr();
break;
}
break;
}
}
if (!cardFound) {
- error(i18n("Failed to find the card with the serial number: %1", mSerial.c_str()));
+ error(i18n("Failed to find the card with the serial number: %1", QString::fromStdString(mSerial)));
finished();
return;
}
if (!existingKey.empty()) {
if (KMessageBox::warningContinueCancel(parentWidgetOrView(), i18nc("@info",
"<p>This card already contains a key in this slot. Continuing will <b>overwrite</b> that key.</p>"
"<p>If there is no backup the existing key will be irrecoverably lost.</p>") +
i18n("The existing key has the fingerprint:") + QStringLiteral("<pre>%1</pre>").arg(existingKey.c_str()) +
encKeyWarning,
i18nc("@title:window", "Overwrite existing key"),
KStandardGuiItem::cont(), KStandardGuiItem::cancel(), QString(), KMessageBox::Notify | KMessageBox::Dangerous)
!= KMessageBox::Continue) {
finished();
return;
}
}
// Now do the deed
const auto time = QDateTime::fromTime_t(mKey.creationTime());
const auto timestamp = time.toString(QStringLiteral("yyyyMMdd'T'HHmmss"));
#ifdef GPGME_SUBKEY_HAS_KEYGRIP
const QString cmd = QStringLiteral("KEYTOCARD --force %1 %2 OPENPGP.%3 %4").arg(mKey.keyGrip())
- .arg(mSerial.c_str())
+ .arg(QString::fromStdString(mSerial))
.arg(slot)
.arg(timestamp);
ReaderStatus::mutableInstance()->startSimpleTransaction(cmd.toUtf8(), q_func(), "keyToCardDone");
#else
finished();
#endif
}
private:
std::shared_ptr<QInputDialog> dialog;
std::string mSerial;
GpgME::Subkey mKey;
};
KeyToCardCommand::Private *KeyToCardCommand::d_func()
{
return static_cast<Private *>(d.get());
}
const KeyToCardCommand::Private *KeyToCardCommand::d_func() const
{
return static_cast<const Private *>(d.get());
}
#define q q_func()
#define d d_func()
void KeyToCardCommand::keyToCardDone(const GpgME::Error &err)
{
if (err) {
d->error(i18nc("@info",
"Moving the key to the card failed: %1", err.asString()),
i18nc("@title", "Error"));
} else if (!err.isCanceled()) {
/* TODO DELETE_KEY is too strong, because it also deletes the stub
* of the secret key. I could not find out how GnuPG does this. Question
* to GnuPG Developers is pending an answer
if (KMessageBox::questionYesNo(d->parentWidgetOrView(),
i18n("Do you want to delete the key on this computer?"),
i18nc("@title:window",
"Key transferred to card")) == KMessageBox::Yes) {
const QString cmd = QStringLiteral("DELETE_KEY --force %1").arg(d->mKey.keyGrip());
// Using readerstatus is a bit overkill but it's an easy way to talk to the agent.
ReaderStatus::mutableInstance()->startSimpleTransaction(cmd.toUtf8(), this, "deleteDone");
}
*/
KMessageBox::information(d->parentWidgetOrView(),
i18n("Successfully copied the key to the card."),
i18nc("@title", "Success"));
}
d->finished();
}
void KeyToCardCommand::deleteDone(const GpgME::Error &err)
{
if (err) {
d->error(i18nc("@info", "Failed to delete the key: %1", err.asString()),
i18nc("@title", "Error"));
}
d->finished();
}
KeyToCardCommand::Private::Private(KeyToCardCommand *qq,
const GpgME::Subkey &key,
const std::string &serialno)
: Command::Private(qq, nullptr),
dialog(),
mSerial(serialno),
mKey(key)
{
}
KeyToCardCommand::Private::~Private() {}
KeyToCardCommand::KeyToCardCommand(const GpgME::Subkey &key, const std::string &serialno)
: Command(new Private(this, key, serialno))
{
}
KeyToCardCommand::~KeyToCardCommand() {}
void KeyToCardCommand::doStart()
{
d->start();
}
void KeyToCardCommand::doCancel()
{
if (d->dialog) {
d->dialog->close();
}
}
#undef q_func
#undef d_func
diff --git a/src/crypto/autodecryptverifyfilescontroller.cpp b/src/crypto/autodecryptverifyfilescontroller.cpp
index 1da47447f..adf9b4459 100644
--- a/src/crypto/autodecryptverifyfilescontroller.cpp
+++ b/src/crypto/autodecryptverifyfilescontroller.cpp
@@ -1,550 +1,550 @@
/* -*- mode: c++; c-basic-offset:4 -*-
autodecryptverifyfilescontroller.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2008 Klarälvdalens Datakonsult AB
2016 by Bundesamt für Sicherheit in der Informationstechnik
Software engineering by Intevation GmbH
Kleopatra 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.
Kleopatra 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include <config-kleopatra.h>
#include "autodecryptverifyfilescontroller.h"
#include "fileoperationspreferences.h"
#include <crypto/gui/decryptverifyoperationwidget.h>
#include <crypto/gui/decryptverifyfilesdialog.h>
#include <crypto/decryptverifytask.h>
#include <crypto/taskcollection.h>
#include "commands/decryptverifyfilescommand.h"
#include <utils/gnupg-helper.h>
#include <utils/path-helper.h>
#include <utils/input.h>
#include <utils/output.h>
#include <utils/kleo_assert.h>
#include <utils/archivedefinition.h>
#include <Libkleo/Classify>
#include <KLocalizedString>
#include <KMessageBox>
#include "kleopatra_debug.h"
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QTimer>
#include <QFileDialog>
#include <QTemporaryDir>
#include <memory>
#include <vector>
using namespace GpgME;
using namespace Kleo;
using namespace Kleo::Crypto;
using namespace Kleo::Crypto::Gui;
class AutoDecryptVerifyFilesController::Private
{
AutoDecryptVerifyFilesController *const q;
public:
explicit Private(AutoDecryptVerifyFilesController *qq);
~Private() {
qCDebug(KLEOPATRA_LOG);
delete m_workDir;
}
void slotDialogCanceled();
void schedule();
void exec();
std::vector<std::shared_ptr<Task> > buildTasks(const QStringList &, QStringList &);
struct CryptoFile {
QString baseName;
QString fileName;
GpgME::Protocol protocol = GpgME::UnknownProtocol;
int classification = 0;
std::shared_ptr<Output> output;
};
QVector<CryptoFile> classifyAndSortFiles(const QStringList &files);
void reportError(int err, const QString &details)
{
q->setLastError(err, details);
q->emitDoneOrError();
}
void cancelAllTasks();
QStringList m_passedFiles, m_filesAfterPreparation;
std::vector<std::shared_ptr<const DecryptVerifyResult> > m_results;
std::vector<std::shared_ptr<Task> > m_runnableTasks, m_completedTasks;
std::shared_ptr<Task> m_runningTask;
bool m_errorDetected;
DecryptVerifyOperation m_operation;
DecryptVerifyFilesDialog *m_dialog;
QTemporaryDir *m_workDir;
};
AutoDecryptVerifyFilesController::Private::Private(AutoDecryptVerifyFilesController *qq) : q(qq),
m_errorDetected(false),
m_operation(DecryptVerify),
m_dialog(nullptr),
m_workDir(nullptr)
{
qRegisterMetaType<VerificationResult>();
}
void AutoDecryptVerifyFilesController::Private::slotDialogCanceled()
{
qCDebug(KLEOPATRA_LOG);
}
void AutoDecryptVerifyFilesController::Private::schedule()
{
if (!m_runningTask && !m_runnableTasks.empty()) {
const std::shared_ptr<Task> t = m_runnableTasks.back();
m_runnableTasks.pop_back();
t->start();
m_runningTask = t;
}
if (!m_runningTask) {
kleo_assert(m_runnableTasks.empty());
for (const std::shared_ptr<const DecryptVerifyResult> &i : qAsConst(m_results)) {
Q_EMIT q->verificationResult(i->verificationResult());
}
}
}
void AutoDecryptVerifyFilesController::Private::exec()
{
Q_ASSERT(!m_dialog);
QStringList undetected;
std::vector<std::shared_ptr<Task> > tasks = buildTasks(m_passedFiles, undetected);
if (!undetected.isEmpty()) {
// Since GpgME 1.7.0 Classification is supposed to be reliable
// so we really can't do anything with this data.
reportError(makeGnuPGError(GPG_ERR_GENERAL),
xi18n("Failed to find encrypted or signed data in one or more files.<nl/>"
"You can manually select what to do with the files now.<nl/>"
"If they contain signed or encrypted data please report a bug (see Help->Report Bug)."));
auto cmd = new Commands::DecryptVerifyFilesCommand(undetected, nullptr, true);
cmd->start();
}
if (tasks.empty()) {
q->emitDoneOrError();
return;
}
Q_ASSERT(m_runnableTasks.empty());
m_runnableTasks.swap(tasks);
std::shared_ptr<TaskCollection> coll(new TaskCollection);
Q_FOREACH (const std::shared_ptr<Task> &i, m_runnableTasks) {
q->connectTask(i);
}
coll->setTasks(m_runnableTasks);
m_dialog = new DecryptVerifyFilesDialog(coll);
m_dialog->setOutputLocation(heuristicBaseDirectory(m_passedFiles));
QTimer::singleShot(0, q, SLOT(schedule()));
if (m_dialog->exec() == QDialog::Accepted && m_workDir) {
// Without workdir there is nothing to move.
const QDir workdir(m_workDir->path());
const QDir outDir(m_dialog->outputLocation());
bool overWriteAll = false;
qCDebug(KLEOPATRA_LOG) << workdir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
for (const QFileInfo &fi: workdir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot)) {
const auto inpath = fi.absoluteFilePath();
if (fi.isDir()) {
// A directory. Assume that the input was an archive
// and avoid directory merges by trying to find a non
// existing directory.
auto candidate = fi.baseName();
if (candidate.startsWith(QLatin1Char('-'))) {
// Bug in GpgTar Extracts stdout passed archives to a dir named -
candidate = QFileInfo(m_passedFiles.first()).baseName();
}
QString suffix;
QFileInfo ofi;
int i = 0;
do {
ofi = QFileInfo(outDir.absoluteFilePath(candidate + suffix));
if (!ofi.exists()) {
break;
}
suffix = QStringLiteral("_%1").arg(++i);
} while (i < 1000);
if (!moveDir(inpath, ofi.absoluteFilePath())) {
reportError(makeGnuPGError(GPG_ERR_GENERAL),
xi18n("Failed to move <filename>%1</filename> to <filename>%2</filename>.",
inpath, ofi.absoluteFilePath()));
}
continue;
}
const auto outpath = outDir.absoluteFilePath(fi.fileName());
qCDebug(KLEOPATRA_LOG) << "Moving " << inpath << " to " << outpath;
const QFileInfo ofi(outpath);
if (ofi.exists()) {
int sel = KMessageBox::No;
if (!overWriteAll) {
sel = KMessageBox::questionYesNoCancel(m_dialog, i18n("The file <b>%1</b> already exists.\n"
"Overwrite?", outpath),
i18n("Overwrite Existing File?"),
KStandardGuiItem::overwrite(),
KGuiItem(i18n("Overwrite All")),
KStandardGuiItem::cancel());
}
if (sel == KMessageBox::Cancel) {
qCDebug(KLEOPATRA_LOG) << "Overwriting canceled for: " << outpath;
continue;
}
if (sel == KMessageBox::No) { //Overwrite All
overWriteAll = true;
}
if (!QFile::remove(outpath)) {
reportError(makeGnuPGError(GPG_ERR_GENERAL),
xi18n("Failed to delete <filename>%1</filename>.",
outpath));
continue;
}
}
if (!QFile::rename(inpath, outpath)) {
reportError(makeGnuPGError(GPG_ERR_GENERAL),
xi18n("Failed to move <filename>%1</filename> to <filename>%2</filename>.",
inpath, outpath));
}
}
}
q->emitDoneOrError();
delete m_dialog;
m_dialog = nullptr;
}
QVector<AutoDecryptVerifyFilesController::Private::CryptoFile> AutoDecryptVerifyFilesController::Private::classifyAndSortFiles(const QStringList &files)
{
const auto isSignature = [](int classification) -> bool {
return mayBeDetachedSignature(classification)
|| mayBeOpaqueSignature(classification)
|| (classification & Class::TypeMask) == Class::ClearsignedMessage;
};
QVector<CryptoFile> out;
for (const auto &file : files) {
CryptoFile cFile;
cFile.fileName = file;
cFile.baseName = file.left(file.length() - 4);
cFile.classification = classify(file);
cFile.protocol = findProtocol(cFile.classification);
auto it = std::find_if(out.begin(), out.end(),
[&cFile](const CryptoFile &other) {
return other.protocol == cFile.protocol
&& other.baseName == cFile.baseName;
});
if (it != out.end()) {
// If we found a file with the same basename, make sure that encrypted
// file is before the signature file, so that we first decrypt and then
// verify
if (isSignature(cFile.classification) && isCipherText(it->classification)) {
out.insert(it + 1, cFile);
} else if (isCipherText(cFile.classification) && isSignature(it->classification)) {
out.insert(it, cFile);
} else {
// both are signatures or both are encrypted files, in which
// case order does not matter
out.insert(it, cFile);
}
} else {
out.push_back(cFile);
}
}
return out;
}
std::vector< std::shared_ptr<Task> > AutoDecryptVerifyFilesController::Private::buildTasks(const QStringList &fileNames, QStringList &undetected)
{
// sort files so that we make sure we first decrypt and then verify
QVector<CryptoFile> cryptoFiles = classifyAndSortFiles(fileNames);
std::vector<std::shared_ptr<Task> > tasks;
for (auto it = cryptoFiles.begin(), end = cryptoFiles.end(); it != end; ++it) {
auto &cFile = (*it);
QFileInfo fi(cFile.fileName);
qCDebug(KLEOPATRA_LOG) << "classified" << cFile.fileName << "as" << printableClassification(cFile.classification);
if (!fi.isReadable()) {
reportError(makeGnuPGError(GPG_ERR_ASS_NO_INPUT),
xi18n("Cannot open <filename>%1</filename> for reading.", cFile.fileName));
continue;
}
if (mayBeAnyCertStoreType(cFile.classification)) {
// Trying to verify a certificate. Possible because extensions are often similar
// for PGP Keys.
reportError(makeGnuPGError(GPG_ERR_ASS_NO_INPUT),
xi18n("The file <filename>%1</filename> contains certificates and can't be decrypted or verified.", cFile.fileName));
qCDebug(KLEOPATRA_LOG) << "reported error";
continue;
}
// We can't reliably detect CMS detached signatures, so we will try to do
// our best to use the current file as a detached signature and fallback to
// opaque signature otherwise.
if (cFile.protocol == GpgME::CMS && mayBeDetachedSignature(cFile.classification)) {
// First, see if previous task was a decryption task for the same file
// and "pipe" it's output into our input
std::shared_ptr<Input> input;
bool prepend = false;
if (it != cryptoFiles.begin()) {
const auto prev = it - 1;
if (prev->protocol == cFile.protocol && prev->baseName == cFile.baseName) {
input = Input::createFromOutput(prev->output);
prepend = true;
}
}
if (!input) {
if (QFile::exists(cFile.baseName)) {
input = Input::createFromFile(cFile.baseName);
}
}
if (input) {
qCDebug(KLEOPATRA_LOG) << "Detached CMS verify: " << cFile.fileName;
std::shared_ptr<VerifyDetachedTask> t(new VerifyDetachedTask);
t->setInput(Input::createFromFile(cFile.fileName));
t->setSignedData(input);
t->setProtocol(cFile.protocol);
if (prepend) {
// Put the verify task BEFORE the decrypt task in the tasks queue,
// because the tasks are executed in reverse order!
tasks.insert(tasks.end() - 1, t);
} else {
tasks.push_back(t);
}
continue;
} else {
// No signed data, maybe not a detached signature
}
}
if (isDetachedSignature(cFile.classification)) {
// Detached signature, try to find data or ask the user.
QString signedDataFileName = cFile.baseName;
if (signedDataFileName.isEmpty()) {
signedDataFileName = QFileDialog::getOpenFileName(nullptr, xi18n("Select the file to verify with \"%1\"", fi.fileName()),
fi.dir().dirName());
}
if (signedDataFileName.isEmpty()) {
qCDebug(KLEOPATRA_LOG) << "No signed data selected. Verify abortet.";
} else {
qCDebug(KLEOPATRA_LOG) << "Detached verify: " << cFile.fileName << " Data: " << signedDataFileName;
std::shared_ptr<VerifyDetachedTask> t(new VerifyDetachedTask);
t->setInput(Input::createFromFile(cFile.fileName));
t->setSignedData(Input::createFromFile(signedDataFileName));
t->setProtocol(cFile.protocol);
tasks.push_back(t);
}
continue;
}
if (!mayBeAnyMessageType(cFile.classification)) {
// Not a Message? Maybe there is a signature for this file?
const auto signatures = findSignatures(cFile.fileName);
bool foundSig = false;
if (!signatures.empty()) {
for (const QString &sig : signatures) {
const auto classification = classify(sig);
qCDebug(KLEOPATRA_LOG) << "Guessing: " << sig << " is a signature for: " << cFile.fileName
<< "Classification: " << classification;
const auto proto = findProtocol(classification);
if (proto == GpgME::UnknownProtocol) {
qCDebug(KLEOPATRA_LOG) << "Could not determine protocol. Skipping guess.";
continue;
}
foundSig = true;
std::shared_ptr<VerifyDetachedTask> t(new VerifyDetachedTask);
t->setInput(Input::createFromFile(sig));
t->setSignedData(Input::createFromFile(cFile.fileName));
t->setProtocol(proto);
tasks.push_back(t);
}
}
if (!foundSig) {
undetected << cFile.fileName;
qCDebug(KLEOPATRA_LOG) << "Failed detection for: " << cFile.fileName << " adding to undetected.";
}
} else {
// Any Message type so we have input and output.
const auto input = Input::createFromFile(cFile.fileName);
const auto archiveDefinitions = ArchiveDefinition::getArchiveDefinitions();
const auto ad = q->pick_archive_definition(cFile.protocol, archiveDefinitions, cFile.fileName);
if (FileOperationsPreferences().dontUseTmpDir()) {
if (!m_workDir) {
- m_workDir = new QTemporaryDir(heuristicBaseDirectory(fileNames) + "/kleopatra-XXXXXX");
+ m_workDir = new QTemporaryDir(heuristicBaseDirectory(fileNames) + QStringLiteral("/kleopatra-XXXXXX"));
}
if (!m_workDir->isValid()) {
qCDebug(KLEOPATRA_LOG) << m_workDir->path() << "not a valid temporary directory.";
delete m_workDir;
m_workDir = new QTemporaryDir();
}
} else if (!m_workDir) {
m_workDir = new QTemporaryDir();
}
qCDebug(KLEOPATRA_LOG) << "Using:" << m_workDir->path() << "as temporary directory.";
const auto wd = QDir(m_workDir->path());
const auto output =
ad ? ad->createOutputFromUnpackCommand(cFile.protocol, cFile.fileName, wd) :
/*else*/ Output::createFromFile(wd.absoluteFilePath(outputFileName(fi.fileName())), false);
// If this might be opaque CMS signature, then try that. We already handled
// detached CMS signature above
const auto isCMSOpaqueSignature = cFile.protocol == GpgME::CMS && mayBeOpaqueSignature(cFile.classification);
if (isOpaqueSignature(cFile.classification) || isCMSOpaqueSignature) {
qCDebug(KLEOPATRA_LOG) << "creating a VerifyOpaqueTask";
std::shared_ptr<VerifyOpaqueTask> t(new VerifyOpaqueTask);
t->setInput(input);
t->setOutput(output);
t->setProtocol(cFile.protocol);
tasks.push_back(t);
} else {
// Any message. That is not an opaque signature needs to be
// decrypted. Verify we always do because we can't know if
// an encrypted message is also signed.
qCDebug(KLEOPATRA_LOG) << "creating a DecryptVerifyTask";
std::shared_ptr<DecryptVerifyTask> t(new DecryptVerifyTask);
t->setInput(input);
t->setOutput(output);
t->setProtocol(cFile.protocol);
cFile.output = output;
tasks.push_back(t);
}
}
}
return tasks;
}
void AutoDecryptVerifyFilesController::setFiles(const QStringList &files)
{
d->m_passedFiles = files;
}
AutoDecryptVerifyFilesController::AutoDecryptVerifyFilesController(QObject *parent) :
DecryptVerifyFilesController(parent), d(new Private(this))
{
}
AutoDecryptVerifyFilesController::AutoDecryptVerifyFilesController(const std::shared_ptr<const ExecutionContext> &ctx, QObject *parent) :
DecryptVerifyFilesController(ctx, parent), d(new Private(this))
{
}
AutoDecryptVerifyFilesController::~AutoDecryptVerifyFilesController()
{
qCDebug(KLEOPATRA_LOG);
}
void AutoDecryptVerifyFilesController::start()
{
d->exec();
}
void AutoDecryptVerifyFilesController::setOperation(DecryptVerifyOperation op)
{
d->m_operation = op;
}
DecryptVerifyOperation AutoDecryptVerifyFilesController::operation() const
{
return d->m_operation;
}
void AutoDecryptVerifyFilesController::Private::cancelAllTasks()
{
// we just kill all runnable tasks - this will not result in
// signal emissions.
m_runnableTasks.clear();
// a cancel() will result in a call to
if (m_runningTask) {
m_runningTask->cancel();
}
}
void AutoDecryptVerifyFilesController::cancel()
{
qCDebug(KLEOPATRA_LOG);
try {
d->m_errorDetected = true;
if (d->m_dialog) {
d->m_dialog->close();
}
d->cancelAllTasks();
} catch (const std::exception &e) {
qCDebug(KLEOPATRA_LOG) << "Caught exception: " << e.what();
}
}
void AutoDecryptVerifyFilesController::doTaskDone(const Task *task, const std::shared_ptr<const Task::Result> &result)
{
Q_ASSERT(task);
Q_UNUSED(task);
// We could just delete the tasks here, but we can't use
// Qt::QueuedConnection here (we need sender()) and other slots
// might not yet have executed. Therefore, we push completed tasks
// into a burial container
d->m_completedTasks.push_back(d->m_runningTask);
d->m_runningTask.reset();
if (const std::shared_ptr<const DecryptVerifyResult> &dvr = std::dynamic_pointer_cast<const DecryptVerifyResult>(result)) {
d->m_results.push_back(dvr);
}
QTimer::singleShot(0, this, SLOT(schedule()));
}
#include "moc_autodecryptverifyfilescontroller.cpp"
diff --git a/src/crypto/gui/resultitemwidget.cpp b/src/crypto/gui/resultitemwidget.cpp
index 031c7a428..7cc1f4130 100644
--- a/src/crypto/gui/resultitemwidget.cpp
+++ b/src/crypto/gui/resultitemwidget.cpp
@@ -1,387 +1,387 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/gui/resultitemwidget.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2008 Klarälvdalens Datakonsult AB
2016 by Bundesamt für Sicherheit in der Informationstechnik
Software engineering by Intevation GmbH
Kleopatra 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.
Kleopatra 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include <config-kleopatra.h>
#include "resultitemwidget.h"
#include "utils/auditlog.h"
#include "commands/command.h"
#include "commands/importcertificatefromfilecommand.h"
#include "commands/lookupcertificatescommand.h"
#include "crypto/decryptverifytask.h"
#include <libkleo/messagebox.h>
#include <Libkleo/Classify>
#include <gpgme++/key.h>
#include <gpgme++/gpgmepp_version.h>
#include <gpgme++/decryptionresult.h>
#include <KLocalizedString>
#include <QPushButton>
#include <KStandardGuiItem>
#include "kleopatra_debug.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QUrl>
#include <QVBoxLayout>
#include <KGuiItem>
#include <KColorScheme>
#if GPGMEPP_VERSION > 0x10B01 // > 1.11.1
# define GPGME_HAS_LEGACY_NOMDC
#endif
using namespace Kleo;
using namespace Kleo::Crypto;
using namespace Kleo::Crypto::Gui;
namespace
{
// TODO move out of here
static QColor colorForVisualCode(Task::Result::VisualCode code)
{
switch (code) {
case Task::Result::AllGood:
return KColorScheme(QPalette::Active, KColorScheme::View).background(KColorScheme::PositiveBackground).color();
case Task::Result::NeutralError:
case Task::Result::Warning:
return KColorScheme(QPalette::Active, KColorScheme::View).background(KColorScheme::NormalBackground).color();
case Task::Result::Danger:
return KColorScheme(QPalette::Active, KColorScheme::View).background(KColorScheme::NegativeBackground).color();
case Task::Result::NeutralSuccess:
default:
return QColor(0x00, 0x80, 0xFF); // light blue
}
}
static QColor txtColorForVisualCode(Task::Result::VisualCode code)
{
switch (code) {
case Task::Result::AllGood:
return KColorScheme(QPalette::Active, KColorScheme::View).foreground(KColorScheme::PositiveText).color();
case Task::Result::NeutralError:
case Task::Result::Warning:
return KColorScheme(QPalette::Active, KColorScheme::View).foreground(KColorScheme::NormalText).color();
case Task::Result::Danger:
return KColorScheme(QPalette::Active, KColorScheme::View).foreground(KColorScheme::NegativeText).color();
case Task::Result::NeutralSuccess:
default:
return QColor(0xFF, 0xFF, 0xFF); // white
}
}
}
class ResultItemWidget::Private
{
ResultItemWidget *const q;
public:
explicit Private(const std::shared_ptr<const Task::Result> &result, ResultItemWidget *qq) : q(qq), m_result(result), m_detailsLabel(nullptr), m_actionsLabel(nullptr), m_closeButton(nullptr), m_importCanceled(false)
{
Q_ASSERT(m_result);
}
void slotLinkActivated(const QString &);
void updateShowDetailsLabel();
void addKeyImportButton(QBoxLayout *lay, bool search);
void addIgnoreMDCButton(QBoxLayout *lay);
void oneImportFinished();
const std::shared_ptr<const Task::Result> m_result;
QLabel *m_detailsLabel;
QLabel *m_actionsLabel;
QPushButton *m_closeButton;
bool m_importCanceled;
};
void ResultItemWidget::Private::oneImportFinished()
{
if (m_importCanceled) {
return;
}
if (m_result->parentTask()) {
m_result->parentTask()->start();
}
q->setVisible(false);
}
void ResultItemWidget::Private::addIgnoreMDCButton(QBoxLayout *lay)
{
if (!m_result || !lay) {
return;
}
const auto dvResult = dynamic_cast<const DecryptVerifyResult *>(m_result.get());
if (!dvResult) {
return;
}
const auto decResult = dvResult->decryptionResult();
#ifdef GPGME_HAS_LEGACY_NOMDC
if (decResult.isNull() || !decResult.error() || !decResult.isLegacyCipherNoMDC())
#endif
{
return;
}
auto btn = new QPushButton(i18n("Force decryption"));
btn->setFixedSize(btn->sizeHint());
connect (btn, &QPushButton::clicked, q, [this] () {
if (m_result->parentTask()) {
const auto dvTask = dynamic_cast<DecryptVerifyTask*>(m_result->parentTask().data());
dvTask->setIgnoreMDCError(true);
dvTask->start();
q->setVisible(false);
} else {
qCWarning(KLEOPATRA_LOG) << "Failed to get parent task";
}
});
lay->addWidget(btn);
}
void ResultItemWidget::Private::addKeyImportButton(QBoxLayout *lay, bool search)
{
if (!m_result || !lay) {
return;
}
const auto dvResult = dynamic_cast<const DecryptVerifyResult *>(m_result.get());
if (!dvResult) {
return;
}
const auto verifyResult = dvResult->verificationResult();
if (verifyResult.isNull()) {
return;
}
for (const auto sig: verifyResult.signatures()) {
if (!(sig.summary() & GpgME::Signature::KeyMissing)) {
continue;
}
auto btn = new QPushButton;
QString suffix;
const auto keyid = QLatin1String(sig.fingerprint());
if (verifyResult.numSignatures() > 1) {
suffix = QLatin1Char(' ') + keyid;
}
btn = new QPushButton(search ? i18nc("1 is optional keyid. No space is intended as it can be empty.",
"Search%1", suffix)
: i18nc("1 is optional keyid. No space is intended as it can be empty.",
"Import%1", suffix));
if (search) {
- btn->setIcon(QIcon::fromTheme("edit-find"));
+ btn->setIcon(QIcon::fromTheme(QStringLiteral("edit-find")));
connect (btn, &QPushButton::clicked, q, [this, btn, keyid] () {
btn->setEnabled(false);
m_importCanceled = false;
auto cmd = new Kleo::Commands::LookupCertificatesCommand(keyid, nullptr);
connect(cmd, &Kleo::Commands::LookupCertificatesCommand::canceled,
q, [this]() { m_importCanceled = true; });
connect(cmd, &Kleo::Commands::LookupCertificatesCommand::finished,
q, [this, btn]() {
btn->setEnabled(true);
oneImportFinished();
});
cmd->setParentWidget(q);
cmd->start();
});
} else {
- btn->setIcon(QIcon::fromTheme("view-certificate-import"));
+ btn->setIcon(QIcon::fromTheme(QStringLiteral("view-certificate-import")));
connect (btn, &QPushButton::clicked, q, [this, btn] () {
btn->setEnabled(false);
m_importCanceled = false;
auto cmd = new Kleo::ImportCertificateFromFileCommand();
connect(cmd, &Kleo::ImportCertificateFromFileCommand::canceled,
q, [this]() { m_importCanceled = true; });
connect(cmd, &Kleo::ImportCertificateFromFileCommand::finished,
q, [this, btn]() {
btn->setEnabled(true);
oneImportFinished();
});
cmd->setParentWidget(q);
cmd->start();
});
}
btn->setFixedSize(btn->sizeHint());
lay->addWidget(btn);
}
}
static QUrl auditlog_url_template()
{
QUrl url(QStringLiteral("kleoresultitem://showauditlog"));
return url;
}
void ResultItemWidget::Private::updateShowDetailsLabel()
{
if (!m_actionsLabel || !m_detailsLabel) {
return;
}
const auto parentTask = m_result->parentTask();
QString auditLogLink;
if (parentTask && parentTask->protocol() == GpgME::OpenPGP) {
if (m_result->hasError()) {
auditLogLink = m_result->auditLog().formatLink(auditlog_url_template(), i18n("Diagnostics"));
}
} else {
auditLogLink = m_result->auditLog().formatLink(auditlog_url_template());
}
m_actionsLabel->setText(auditLogLink);
}
ResultItemWidget::ResultItemWidget(const std::shared_ptr<const Task::Result> &result, QWidget *parent, Qt::WindowFlags flags) : QWidget(parent, flags), d(new Private(result, this))
{
const QColor color = colorForVisualCode(d->m_result->code());
const QColor txtColor = txtColorForVisualCode(d->m_result->code());
const QString styleSheet = QStringLiteral("QFrame,QLabel { background-color: %1; margin: 0px; }"
"QFrame#resultFrame{ border-color: %2; border-style: solid; border-radius: 3px; border-width: 1px }"
"QLabel { color: %3; padding: 5px; border-radius: 3px }").arg(color.name()).arg(color.darker(150).name()).arg(txtColor.name());
QVBoxLayout *topLayout = new QVBoxLayout(this);
QFrame *frame = new QFrame;
frame->setObjectName(QStringLiteral("resultFrame"));
frame->setStyleSheet(styleSheet);
topLayout->addWidget(frame);
QHBoxLayout *layout = new QHBoxLayout(frame);
QVBoxLayout *vlay = new QVBoxLayout();
QLabel *overview = new QLabel;
overview->setWordWrap(true);
overview->setTextFormat(Qt::RichText);
overview->setText(d->m_result->overview());
overview->setFocusPolicy(Qt::StrongFocus);
overview->setStyleSheet(styleSheet);
connect(overview, SIGNAL(linkActivated(QString)), this, SLOT(slotLinkActivated(QString)));
vlay->addWidget(overview);
layout->addLayout(vlay);
const QString details = d->m_result->details();
QVBoxLayout *actionLayout = new QVBoxLayout;
layout->addLayout(actionLayout);
d->addKeyImportButton(actionLayout, false);
// TODO: Only show if auto-key-retrieve is not set.
d->addKeyImportButton(actionLayout, true);
d->addIgnoreMDCButton(actionLayout);
d->m_actionsLabel = new QLabel;
connect(d->m_actionsLabel, SIGNAL(linkActivated(QString)), this, SLOT(slotLinkActivated(QString)));
actionLayout->addWidget(d->m_actionsLabel);
d->m_actionsLabel->setFocusPolicy(Qt::StrongFocus);
d->m_actionsLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
d->m_actionsLabel->setStyleSheet(styleSheet);
d->m_detailsLabel = new QLabel;
d->m_detailsLabel->setWordWrap(true);
d->m_detailsLabel->setTextFormat(Qt::RichText);
d->m_detailsLabel->setText(details);
d->m_detailsLabel->setFocusPolicy(Qt::StrongFocus);
d->m_detailsLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
d->m_detailsLabel->setStyleSheet(styleSheet);
connect(d->m_detailsLabel, SIGNAL(linkActivated(QString)), this, SLOT(slotLinkActivated(QString)));
vlay->addWidget(d->m_detailsLabel);
d->m_closeButton = new QPushButton;
KGuiItem::assign(d->m_closeButton, KStandardGuiItem::close());
d->m_closeButton->setFixedSize(d->m_closeButton->sizeHint());
connect(d->m_closeButton, &QAbstractButton::clicked, this, &ResultItemWidget::closeButtonClicked);
actionLayout->addWidget(d->m_closeButton);
d->m_closeButton->setVisible(false);
layout->setStretch(0, 1);
actionLayout->addStretch(-1);
vlay->addStretch(-1);
d->updateShowDetailsLabel();
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Maximum);
}
ResultItemWidget::~ResultItemWidget()
{
}
void ResultItemWidget::showCloseButton(bool show)
{
d->m_closeButton->setVisible(show);
}
bool ResultItemWidget::hasErrorResult() const
{
return d->m_result->hasError();
}
void ResultItemWidget::Private::slotLinkActivated(const QString &link)
{
Q_ASSERT(m_result);
qCDebug(KLEOPATRA_LOG) << "Link activated: " << link;
if (link.startsWith(QLatin1String("key:"))) {
auto split = link.split(QLatin1Char(':'));
auto fpr = split.value(1);
if (split.size() == 2 && isFingerprint(fpr)) {
/* There might be a security consideration here if somehow
* a short keyid is used in a link and it collides with another.
* So we additionally check that it really is a fingerprint. */
auto cmd = Command::commandForQuery(fpr);
cmd->setParentWId(q->effectiveWinId());
cmd->start();
} else {
qCWarning(KLEOPATRA_LOG) << "key link invalid " << link;
}
return;
}
const QUrl url(link);
if (url.host() == QLatin1String("showauditlog")) {
q->showAuditLog();
return;
}
qCWarning(KLEOPATRA_LOG) << "Unexpected link scheme: " << link;
}
void ResultItemWidget::showAuditLog()
{
MessageBox::auditLog(parentWidget(), d->m_result->auditLog().text());
}
#include "moc_resultitemwidget.cpp"
diff --git a/src/crypto/gui/unknownrecipientwidget.cpp b/src/crypto/gui/unknownrecipientwidget.cpp
index e70dba9f6..dab90862d 100644
--- a/src/crypto/gui/unknownrecipientwidget.cpp
+++ b/src/crypto/gui/unknownrecipientwidget.cpp
@@ -1,84 +1,84 @@
/* crypto/gui/unknownrecipientwidget.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2018 by Intevation GmbH
Kleopatra 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.
Kleopatra 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include "unknownrecipientwidget.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QFont>
#include "commands/lookupcertificatescommand.h"
#include <KLocalizedString>
using namespace Kleo;
UnknownRecipientWidget::UnknownRecipientWidget(const char *keyid,
QWidget *parent):
QWidget(parent)
{
auto hLay = new QHBoxLayout(this);
auto caption = new QLabel(i18nc("Caption for an unknwon key/certificate where only ID is known.",
"Unknown Recipient:"));
mKeyID = QString::fromLatin1(keyid);
auto keyIdLabel = new QLabel(mKeyID);
- keyIdLabel->setFont(QFont("Monospace"));
+ keyIdLabel->setFont(QFont(QStringLiteral("Monospace")));
auto lookUpBtn = new QPushButton(i18n("Search"));
- lookUpBtn->setIcon(QIcon::fromTheme("edit-find"));
+ lookUpBtn->setIcon(QIcon::fromTheme(QStringLiteral("edit-find")));
lookUpBtn->setToolTip(i18n("Search on keyserver"));
connect (lookUpBtn, &QPushButton::clicked, this, [this, lookUpBtn] () {
lookUpBtn->setEnabled(false);
auto cmd = new Kleo::Commands::LookupCertificatesCommand(mKeyID, nullptr);
connect(cmd, &Kleo::Commands::LookupCertificatesCommand::finished,
this, [lookUpBtn]() {
lookUpBtn->setEnabled(true);
});
cmd->setParentWidget(this->parentWidget());
cmd->start();
});
hLay->addWidget(caption);
hLay->addWidget(keyIdLabel);
hLay->addWidget(lookUpBtn);
hLay->addStretch(1);
setToolTip(i18n("The data was encrypted to this key / certificate."));
}
QString UnknownRecipientWidget::keyID() const {
return mKeyID;
}
diff --git a/src/dialogs/exportdialog.cpp b/src/dialogs/exportdialog.cpp
index 74adcd25f..bffa23225 100644
--- a/src/dialogs/exportdialog.cpp
+++ b/src/dialogs/exportdialog.cpp
@@ -1,201 +1,201 @@
/* Copyright (c) 2017 Intevation GmbH
Kleopatra 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.
Kleopatra 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "exportdialog.h"
#include "kleopatra_debug.h"
#include "view/waitwidget.h"
#include <QDialog>
#include <QDialogButtonBox>
#include <QFontDatabase>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QTextEdit>
#include <QVBoxLayout>
#include <gpgme++/key.h>
#include <QGpgME/Protocol>
#include <QGpgME/ExportJob>
#include <KLocalizedString>
#include <KSharedConfig>
#include <KConfigGroup>
#include <Libkleo/Formatting>
using namespace Kleo;
class ExportWidget::Private
{
public:
Private(ExportWidget *qq)
: q(qq)
{}
void setupUi();
GpgME::Key key;
QTextEdit *textEdit;
WaitWidget *waitWidget;
private:
ExportWidget *q;
};
void ExportWidget::Private::setupUi()
{
auto vlay = new QVBoxLayout(q);
textEdit = new QTextEdit;
textEdit->setVisible(false);
textEdit->setReadOnly(true);
auto fixedFont = QFont("Monospace");
fixedFont.setStyleHint(QFont::TypeWriter);
textEdit->setFont(fixedFont);
textEdit->setReadOnly(true);
vlay->addWidget(textEdit);
waitWidget = new WaitWidget;
waitWidget->setText(i18n("Exporting ..."));
vlay->addWidget(waitWidget);
}
ExportWidget::ExportWidget(QWidget *parent)
: QWidget(parent)
, d(new Private(this))
{
d->setupUi();
}
ExportWidget::~ExportWidget()
{
}
static QString injectComments(const GpgME::Key &key, const QByteArray &data)
{
QString ret = QString::fromUtf8(data);
if (key.protocol() != GpgME::OpenPGP) {
return ret;
}
auto overView = Formatting::toolTip(key, Formatting::Fingerprint |
Formatting::UserIDs |
Formatting::Issuer |
Formatting::Subject |
Formatting::ExpiryDates |
Formatting::CertificateType |
Formatting::CertificateUsage);
// Fixup the HTML coming from the toolTip for our own format.
overView.remove(QLatin1String("<tr><th>"));
- overView.replace(QLatin1String("</th><td>"), "\t");
- overView.replace(QLatin1String("</td></tr>"), "\n");
+ overView.replace(QLatin1String("</th><td>"), QLatin1String("\t"));
+ overView.replace(QLatin1String("</td></tr>"), QLatin1String("\n"));
overView.remove(QLatin1String("<table border=\"0\">"));
overView.remove(QLatin1String("\n</table>"));
- overView.replace(QLatin1String("&lt;"), "<");
- overView.replace(QLatin1String("&gt;"), ">");
+ overView.replace(QLatin1String("&lt;"), QLatin1String("<"));
+ overView.replace(QLatin1String("&gt;"), QLatin1String(">"));
auto overViewLines = overView.split(QLatin1Char('\n'));
// Format comments so that they fit for RFC 4880
auto comments = QString::fromLatin1("Comment: ");
comments += overViewLines.join(QStringLiteral("\nComment: ")) + QLatin1Char('\n');
ret.insert(37 /* -----BEGIN PGP PUBLIC KEY BLOCK-----\n */, comments);
return ret;
}
void ExportWidget::exportResult(const GpgME::Error &err, const QByteArray &data)
{
d->waitWidget->setVisible(false);
d->textEdit->setVisible(true);
if (err) {
/* Should not happen. But well,.. */
- d->textEdit->setText(i18nc("%1 is error message", "Failed to export: '%1'",err.asString()));
+ d->textEdit->setText(i18nc("%1 is error message", "Failed to export: '%1'", QString::fromLatin1(err.asString())));
}
d->textEdit->setText(injectComments(d->key, data));
}
void ExportWidget::setKey(const GpgME::Key &key)
{
d->waitWidget->setVisible(true);
d->textEdit->setVisible(false);
d->key = key;
auto protocol = key.protocol() == GpgME::CMS ?
QGpgME::smime() : QGpgME::openpgp();
auto job = protocol->publicKeyExportJob(true);
/* New style connect does not work on Windows. */
connect(job, SIGNAL(result(GpgME::Error,QByteArray)),
this, SLOT(exportResult(GpgME::Error,QByteArray)));
job->start(QStringList() << key.primaryFingerprint());
}
GpgME::Key ExportWidget::key() const
{
return d->key;
}
ExportDialog::ExportDialog(QWidget *parent)
: QDialog(parent),
mWidget(new ExportWidget(this))
{
KConfigGroup dialog(KSharedConfig::openConfig(), "ExportDialog");
const auto size = dialog.readEntry("Size", QSize(600, 800));
if (size.isValid()) {
resize(size);
}
setWindowTitle(i18n("Export..."));
auto l = new QVBoxLayout(this);
l->addWidget(mWidget);
auto bbox = new QDialogButtonBox(this);
auto btn = bbox->addButton(QDialogButtonBox::Close);
connect(btn, &QPushButton::pressed, this, &QDialog::accept);
l->addWidget(bbox);
}
ExportDialog::~ExportDialog()
{
KConfigGroup dialog(KSharedConfig::openConfig(), "ExportDialog");
dialog.writeEntry("Size", size());
dialog.sync();
}
void ExportDialog::setKey(const GpgME::Key &key)
{
mWidget->setKey(key);
}
GpgME::Key ExportDialog::key() const
{
return mWidget->key();
}
diff --git a/src/dialogs/updatenotification.cpp b/src/dialogs/updatenotification.cpp
index 4e9b1c165..1ff9c03bf 100644
--- a/src/dialogs/updatenotification.cpp
+++ b/src/dialogs/updatenotification.cpp
@@ -1,244 +1,244 @@
/* dialogs/updatenotification.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2017 by Bundesamt für Sicherheit in der Informationstechnik
Software engineering by Intevation GmbH
Kleopatra 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.
Kleopatra 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include "updatenotification.h"
#include "utils/gnupg-helper.h"
#include "kleopatra_debug.h"
#include <QIcon>
#include <QGridLayout>
#include <QCheckBox>
#include <QDialogButtonBox>
#include <QDesktopServices>
#include <QProcess>
#include <QProgressDialog>
#include <QPushButton>
#include <QLabel>
#include <QUrl>
#include <QDateTime>
#include <KIconLoader>
#include <KLocalizedString>
#include <KConfigGroup>
#include <KSharedConfig>
#include <KMessageBox>
#include <QGpgME/CryptoConfig>
#include <QGpgME/Protocol>
#include <gpgme++/gpgmefw.h>
#include <gpgme++/swdbresult.h>
#include <gpgme++/error.h>
using namespace Kleo;
namespace
{
static void gpgconf_set_update_check(bool value)
{
auto conf = QGpgME::cryptoConfig();
auto entry = conf->entry(QStringLiteral("dirmngr"),
QStringLiteral("Enforcement"),
QStringLiteral("allow-version-check"));
if (!entry) {
qCDebug(KLEOPATRA_LOG) << "allow-version-check entry not found";
return;
}
if (entry->boolValue() != value) {
entry->setBoolValue(value);
conf->sync(true);
}
}
} // namespace
void UpdateNotification::forceUpdateCheck(QWidget *parent)
{
auto proc = new QProcess;
proc->setProgram(gnupgInstallPath() + QStringLiteral("/gpg-connect-agent.exe"));
proc->setArguments(QStringList() << QStringLiteral("--dirmngr")
<< QStringLiteral("loadswdb --force")
<< QStringLiteral("/bye"));
auto progress = new QProgressDialog(i18n("Searching for updates..."),
i18n("Cancel"), 0, 0, parent);
progress->setMinimumDuration(0);
progress->show();
connect(progress, &QProgressDialog::canceled, [progress, proc] () {
proc->kill();
qCDebug(KLEOPATRA_LOG) << "Update force cancled. Output:"
<< QString::fromLocal8Bit(proc->readAllStandardOutput())
<< "stderr:"
<< QString::fromLocal8Bit(proc->readAllStandardError());
});
connect(proc, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
[parent, progress, proc](int exitCode, QProcess::ExitStatus exitStatus) {
qCDebug(KLEOPATRA_LOG) << "Update force exited with status:" << exitStatus
<< "code:" << exitCode;
delete progress;
proc->deleteLater();
UpdateNotification::checkUpdate(parent, exitStatus == QProcess::NormalExit);
});
qCDebug(KLEOPATRA_LOG) << "Starting:" << proc->program() << "args" << proc->arguments();
proc->start();
}
void UpdateNotification::checkUpdate(QWidget *parent, bool force)
{
#ifdef Q_OS_WIN
KConfigGroup updatecfg(KSharedConfig::openConfig(), "UpdateNotification");
if (updatecfg.readEntry("NeverShow", false) && !force) {
return;
}
// Gpg defaults to no update check. For Gpg4win we want this
// enabled if the user does not explicitly disable update
// checks neverShow would be true in that case or
// we would have set AllowVersionCheck once and the user
// explicitly removed that.
if (force || updatecfg.readEntry("AllowVersionCheckSetOnce", false)) {
gpgconf_set_update_check (true);
updatecfg.writeEntry("AllowVersionCheckSetOnce", true);
}
const auto current = gpg4winVersion();
GpgME::Error err;
const auto lastshown = updatecfg.readEntry("LastShown", QDateTime());
if (!force && lastshown.isValid() &&
lastshown.addSecs(20 * 60 * 60) > QDateTime::currentDateTime()) {
qDebug() << QDateTime::currentDateTime().addSecs(20 * 60 * 60);
return;
}
const auto results = GpgME::SwdbResult::query("gpg4win",
current.toUtf8().constData(),
&err);
if (err) {
qCDebug(KLEOPATRA_LOG) << "update check failed: " << err.asString();
return;
}
if (results.size() != 1) {
/* Should not happen */
qCDebug(KLEOPATRA_LOG) << "more then one result";
return;
}
const auto result = results[0];
if (result.update()) {
const QString newVersion = QStringLiteral("%1.%2.%3").arg(result.version().major)
.arg(result.version().minor)
.arg(result.version().patch);
qCDebug(KLEOPATRA_LOG) << "Have update to version:" << newVersion;
UpdateNotification notifier(parent, newVersion);
notifier.exec();
updatecfg.writeEntry("LastShown", QDateTime::currentDateTime());
updatecfg.sync();
} else {
qCDebug(KLEOPATRA_LOG) << "No update for:" << current;
if (force) {
KMessageBox::information(parent,
i18nc("@info",
"No update found in the available version database."),
i18nc("@title", "Up to date"));
}
}
#else
Q_UNUSED(parent);
Q_UNUSED(force);
#endif
}
UpdateNotification::UpdateNotification(QWidget *parent, const QString &version) :
QDialog(parent)
{
resize(400, 200);
auto lay = new QGridLayout(this);
auto logo = new QLabel;
logo->setMaximumWidth(110);
setAttribute(Qt::WA_QuitOnClose, false);
KIconLoader *const il = KIconLoader::global();
const QString iconPath = il->iconPath(QLatin1String("gpg4win"),
KIconLoader::User);
logo->setPixmap(QIcon(iconPath).pixmap(100, 100));
auto label = new QLabel;
const QString boldVersion = QStringLiteral("<b>%1</b>").arg(version);
label->setText (i18nc("%1 is the version number", "Version %1 is available.", boldVersion) +
QStringLiteral("<br><br>") +
i18nc("Link to NEWS style changelog",
"See the <a href=\"https://www.gpg4win.org/change-history.html\">new features</a>."));
label->setOpenExternalLinks(true);
label->setTextInteractionFlags(Qt::TextBrowserInteraction);
label->setWordWrap(true);
setWindowTitle(i18n("Update available!"));
setWindowIcon(QIcon(QLatin1String("gpg4win")));
lay->addWidget(logo, 0, 0);
lay->addWidget(label, 0, 1);
const auto chk = new QCheckBox (i18n("Show this notification for future updates."));
lay->addWidget(chk, 1, 0, 1, -1);
KConfigGroup updatecfg(KSharedConfig::openConfig(), "UpdateNotification");
chk->setChecked(!updatecfg.readEntry("NeverShow", false));
const auto bb = new QDialogButtonBox();
const auto b = bb->addButton(i18n("&Get update"), QDialogButtonBox::AcceptRole);
b->setDefault(true);
- b->setIcon(QIcon::fromTheme("arrow-down"));
+ b->setIcon(QIcon::fromTheme(QStringLiteral("arrow-down")));
bb->addButton(QDialogButtonBox::Cancel);
lay->addWidget(bb, 2, 0, 1, -1);
connect (bb, &QDialogButtonBox::accepted, this, [this, chk]() {
- QDesktopServices::openUrl(QUrl("https://www.gpg4win.org/download.html"));
+ QDesktopServices::openUrl(QUrl(QStringLiteral("https://www.gpg4win.org/download.html")));
KConfigGroup updatecfg(KSharedConfig::openConfig(), "UpdateNotification");
updatecfg.writeEntry("NeverShow", !chk->isChecked());
gpgconf_set_update_check (chk->isChecked());
QDialog::accept();
});
connect (bb, &QDialogButtonBox::rejected, this, [this, chk]() {
KConfigGroup updatecfg(KSharedConfig::openConfig(), "UpdateNotification");
updatecfg.writeEntry("NeverShow", !chk->isChecked());
gpgconf_set_update_check (chk->isChecked());
QDialog::reject();
});
}
diff --git a/src/kleopatraapplication.cpp b/src/kleopatraapplication.cpp
index 3b90d0647..95a07b4ea 100644
--- a/src/kleopatraapplication.cpp
+++ b/src/kleopatraapplication.cpp
@@ -1,658 +1,658 @@
/*
kleopatraapplication.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2008 Klarälvdalens Datakonsult AB
2016 by Bundesamt für Sicherheit in der Informationstechnik
Software engineering by Intevation GmbH
Kleopatra 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.
Kleopatra 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include <config-kleopatra.h>
#include "kleopatraapplication.h"
#include "mainwindow.h"
#include "kleopatra_options.h"
#include "systrayicon.h"
#include <smartcard/readerstatus.h>
#include <conf/configuredialog.h>
#include <utils/gnupg-helper.h>
#include <utils/kdpipeiodevice.h>
#include <utils/log.h>
#include <gpgme++/key.h>
#include <Libkleo/FileSystemWatcher>
#include <Libkleo/KeyCache>
#include <Libkleo/Classify>
#ifdef HAVE_USABLE_ASSUAN
# include <uiserver/uiserver.h>
#endif
#include "commands/signencryptfilescommand.h"
#include "commands/decryptverifyfilescommand.h"
#include "commands/lookupcertificatescommand.h"
#include "commands/checksumcreatefilescommand.h"
#include "commands/checksumverifyfilescommand.h"
#include "commands/detailscommand.h"
#include "commands/newcertificatecommand.h"
#include "dialogs/updatenotification.h"
#include <KIconLoader>
#include <KLocalizedString>
#include "kleopatra_debug.h"
#include <KMessageBox>
#include <KWindowSystem>
#include <QFile>
#include <QDir>
#include <QPointer>
#include <memory>
#include <KSharedConfig>
using namespace Kleo;
using namespace Kleo::Commands;
static void add_resources()
{
KIconLoader::global()->addAppDir(QStringLiteral("libkleopatra"));
KIconLoader::global()->addAppDir(QStringLiteral("kwatchgnupg"));
}
static QList<QByteArray> default_logging_options()
{
QList<QByteArray> result;
result.push_back("io");
return result;
}
class KleopatraApplication::Private
{
friend class ::KleopatraApplication;
KleopatraApplication *const q;
public:
explicit Private(KleopatraApplication *qq)
: q(qq),
ignoreNewInstance(true),
firstNewInstance(true),
sysTray(nullptr)
{
}
~Private() {
delete sysTray;
}
void init()
{
KDAB_SET_OBJECT_NAME(readerStatus);
#ifndef QT_NO_SYSTEMTRAYICON
sysTray = new SysTrayIcon();
sysTray->setAnyCardHasNullPin(readerStatus.anyCardHasNullPin());
sysTray->setAnyCardCanLearnKeys(readerStatus.anyCardCanLearnKeys());
connect(&readerStatus, &SmartCard::ReaderStatus::anyCardHasNullPinChanged,
sysTray, &SysTrayIcon::setAnyCardHasNullPin);
connect(&readerStatus, &SmartCard::ReaderStatus::anyCardCanLearnKeysChanged,
sysTray, &SysTrayIcon::setAnyCardCanLearnKeys);
#endif
}
private:
void connectConfigureDialog()
{
if (configureDialog && q->mainWindow()) {
connect(configureDialog, SIGNAL(configCommitted()), q->mainWindow(), SLOT(slotConfigCommitted()));
}
}
void disconnectConfigureDialog()
{
if (configureDialog && q->mainWindow()) {
disconnect(configureDialog, SIGNAL(configCommitted()), q->mainWindow(), SLOT(slotConfigCommitted()));
}
}
public:
bool ignoreNewInstance;
bool firstNewInstance;
QPointer<ConfigureDialog> configureDialog;
QPointer<MainWindow> mainWindow;
SmartCard::ReaderStatus readerStatus;
#ifndef QT_NO_SYSTEMTRAYICON
SysTrayIcon *sysTray;
#endif
std::shared_ptr<KeyCache> keyCache;
std::shared_ptr<Log> log;
std::shared_ptr<FileSystemWatcher> watcher;
public:
void setupKeyCache()
{
keyCache = KeyCache::mutableInstance();
watcher.reset(new FileSystemWatcher);
watcher->whitelistFiles(gnupgFileWhitelist());
watcher->addPath(gnupgHomeDirectory());
watcher->setDelay(1000);
keyCache->addFileSystemWatcher(watcher);
}
void setupLogging()
{
log = Log::mutableInstance();
const QByteArray envOptions = qgetenv("KLEOPATRA_LOGOPTIONS");
const bool logAll = envOptions.trimmed() == "all";
const QList<QByteArray> options = envOptions.isEmpty() ? default_logging_options() : envOptions.split(',');
const QByteArray dirNative = qgetenv("KLEOPATRA_LOGDIR");
if (dirNative.isEmpty()) {
return;
}
const QString dir = QFile::decodeName(dirNative);
const QString logFileName = QDir(dir).absoluteFilePath(QStringLiteral("kleopatra.log.%1").arg(QCoreApplication::applicationPid()));
std::unique_ptr<QFile> logFile(new QFile(logFileName));
if (!logFile->open(QIODevice::WriteOnly | QIODevice::Append)) {
qCDebug(KLEOPATRA_LOG) << "Could not open file for logging: " << logFileName << "\nLogging disabled";
return;
}
log->setOutputDirectory(dir);
if (logAll || options.contains("io")) {
log->setIOLoggingEnabled(true);
}
qInstallMessageHandler(Log::messageHandler);
#ifdef HAVE_USABLE_ASSUAN
if (logAll || options.contains("pipeio")) {
KDPipeIODevice::setDebugLevel(KDPipeIODevice::Debug);
}
UiServer::setLogStream(log->logFile());
#endif
}
};
KleopatraApplication::KleopatraApplication(int &argc, char *argv[])
: QApplication(argc, argv), d(new Private(this))
{
}
void KleopatraApplication::init()
{
d->init();
add_resources();
d->setupKeyCache();
d->setupLogging();
#ifndef QT_NO_SYSTEMTRAYICON
d->sysTray->show();
#endif
setQuitOnLastWindowClosed(false);
KWindowSystem::allowExternalProcessWindowActivation();
}
KleopatraApplication::~KleopatraApplication()
{
// work around kdelibs bug https://bugs.kde.org/show_bug.cgi?id=162514
KSharedConfig::openConfig()->sync();
}
namespace
{
typedef void (KleopatraApplication::*Func)(const QStringList &, GpgME::Protocol);
}
void KleopatraApplication::slotActivateRequested(const QStringList &arguments,
const QString &workingDirectory)
{
QCommandLineParser parser;
kleopatra_options(&parser);
QString err;
if (!arguments.isEmpty() && !parser.parse(arguments)) {
err = parser.errorText();
} else if (arguments.isEmpty()) {
// KDBusServices omits the application name if no other
// arguments are provided. In that case the parser prints
// a warning.
parser.parse(QStringList() << QCoreApplication::applicationFilePath());
}
if (err.isEmpty()) {
err = newInstance(parser, workingDirectory);
}
if (!err.isEmpty()) {
KMessageBox::sorry(nullptr, err.toHtmlEscaped(), i18n("Failed to execute command"));
Q_EMIT setExitValue(1);
return;
}
Q_EMIT setExitValue(0);
}
QString KleopatraApplication::newInstance(const QCommandLineParser &parser,
const QString &workingDirectory)
{
if (d->ignoreNewInstance) {
qCDebug(KLEOPATRA_LOG) << "New instance ignored because of ignoreNewInstance";
return QString();
}
QStringList files;
const QDir cwd = QDir(workingDirectory);
Q_FOREACH (const QString &file, parser.positionalArguments()) {
// We do not check that file exists here. Better handle
// these errors in the UI.
if (QFileInfo(file).isAbsolute()) {
files << file;
} else {
files << cwd.absoluteFilePath(file);
}
}
GpgME::Protocol protocol = GpgME::UnknownProtocol;
if (parser.isSet(QStringLiteral("openpgp"))) {
qCDebug(KLEOPATRA_LOG) << "found OpenPGP";
protocol = GpgME::OpenPGP;
}
if (parser.isSet(QStringLiteral("cms"))) {
qCDebug(KLEOPATRA_LOG) << "found CMS";
if (protocol == GpgME::OpenPGP) {
return i18n("Ambiguous protocol: --openpgp and --cms");
}
protocol = GpgME::CMS;
}
// Check for Parent Window id
WId parentId = 0;
if (parser.isSet(QStringLiteral("parent-windowid"))) {
#ifdef Q_OS_WIN
// WId is not a portable type as it is a pointer type on Windows.
// casting it from an integer is ok though as the values are guranteed to
// be compatible in the documentation.
parentId = reinterpret_cast<WId>(parser.value(QStringLiteral("parent-windowid")).toUInt());
#else
parentId = parser.value(QStringLiteral("parent-windowid")).toUInt();
#endif
}
// Handle openpgp4fpr URI scheme
QString needle;
if (parser.isSet(QStringLiteral("search"))) {
needle = parser.value(QStringLiteral("search"));
} else if (parser.isSet(QStringLiteral("query"))) {
needle = parser.value(QStringLiteral("query"));
}
if (needle.startsWith(QLatin1String("openpgp4fpr:"))) {
needle.remove(0, 12);
}
// Check for --search command.
if (parser.isSet(QStringLiteral("search"))) {
// This is an extra command instead of a combination with the
// similar query to avoid changing the older query commands behavior
// and query's "show details if a certificate exist or search on a
// keyserver" logic is hard to explain and use consistently.
if (needle.isEmpty()) {
return i18n("No search string specified for --search");
}
LookupCertificatesCommand *const cmd = new LookupCertificatesCommand(needle, nullptr);
cmd->setParentWId(parentId);
cmd->start();
return QString();
}
// Check for --query command
if (parser.isSet(QStringLiteral("query"))) {
if (needle.isEmpty()) {
return i18n("No fingerprint argument specified for --query");
}
auto cmd = Command::commandForQuery(needle);
cmd->setParentWId(parentId);
cmd->start();
return QString();
}
// Check for --gen-key command
- if (parser.isSet("gen-key")) {
+ if (parser.isSet(QStringLiteral("gen-key"))) {
auto cmd = new NewCertificateCommand(nullptr);
cmd->setParentWId(parentId);
cmd->setProtocol(protocol);
cmd->start();
return QString();
}
// Check for --config command
- if (parser.isSet("config")) {
+ if (parser.isSet(QStringLiteral("config"))) {
openConfigDialogWithForeignParent(parentId);
return QString();
}
static const QMap<QString, Func> funcMap {
{ QStringLiteral("import-certificate"), &KleopatraApplication::importCertificatesFromFile },
{ QStringLiteral("encrypt"), &KleopatraApplication::encryptFiles },
{ QStringLiteral("sign"), &KleopatraApplication::signFiles },
{ QStringLiteral("encrypt-sign"), &KleopatraApplication::signEncryptFiles },
{ QStringLiteral("sign-encrypt"), &KleopatraApplication::signEncryptFiles },
{ QStringLiteral("decrypt"), &KleopatraApplication::decryptFiles },
{ QStringLiteral("verify"), &KleopatraApplication::verifyFiles },
{ QStringLiteral("decrypt-verify"), &KleopatraApplication::decryptVerifyFiles },
{ QStringLiteral("checksum"), &KleopatraApplication::checksumFiles },
};
QString found;
Q_FOREACH (const QString &opt, funcMap.keys()) {
if (parser.isSet(opt) && found.isEmpty()) {
found = opt;
} else if (parser.isSet(opt)) {
return i18n("Ambiguous commands \"%1\" and \"%2\"", found, opt);
}
}
QStringList errors;
if (!found.isEmpty()) {
if (files.empty()) {
return i18n("No files specified for \"%1\" command", found);
}
qCDebug(KLEOPATRA_LOG) << "found" << found;
(this->*funcMap.value(found))(files, protocol);
} else {
if (files.empty()) {
if (!(d->firstNewInstance && isSessionRestored())) {
qCDebug(KLEOPATRA_LOG) << "openOrRaiseMainWindow";
openOrRaiseMainWindow();
}
} else {
Q_FOREACH (const QString& fileName, files) {
QFileInfo fi(fileName);
if (!fi.isReadable()) {
errors << i18n("Cannot read \"%1\"", fileName);
}
}
Q_FOREACH (Command *cmd, Command::commandsForFiles(files)) {
if (parentId) {
cmd->setParentWId(parentId);
} else {
MainWindow *mw = mainWindow();
if (!mw) {
mw = new MainWindow;
mw->setAttribute(Qt::WA_DeleteOnClose);
setMainWindow(mw);
d->connectConfigureDialog();
}
cmd->setParentWidget(mw);
}
cmd->start();
}
}
}
d->firstNewInstance = false;
#ifdef Q_OS_WIN
// On Windows we might be started from the
// explorer in any working directory. E.g.
// a double click on a file. To avoid preventing
// the folder from deletion we set the
// working directory to the users homedir.
QDir::setCurrent(QDir::homePath());
#endif
- return errors.join('\n');
+ return errors.join(QLatin1Char('\n'));
}
#ifndef QT_NO_SYSTEMTRAYICON
const SysTrayIcon *KleopatraApplication::sysTrayIcon() const
{
return d->sysTray;
}
SysTrayIcon *KleopatraApplication::sysTrayIcon()
{
return d->sysTray;
}
#endif
const MainWindow *KleopatraApplication::mainWindow() const
{
return d->mainWindow;
}
MainWindow *KleopatraApplication::mainWindow()
{
return d->mainWindow;
}
void KleopatraApplication::setMainWindow(MainWindow *mainWindow)
{
if (mainWindow == d->mainWindow) {
return;
}
d->disconnectConfigureDialog();
d->mainWindow = mainWindow;
#ifndef QT_NO_SYSTEMTRAYICON
d->sysTray->setMainWindow(mainWindow);
#endif
d->connectConfigureDialog();
}
static void open_or_raise(QWidget *w)
{
if (w->isMinimized()) {
KWindowSystem::unminimizeWindow(w->winId());
w->raise();
} else if (w->isVisible()) {
w->raise();
} else {
w->show();
}
}
void KleopatraApplication::toggleMainWindowVisibility()
{
if (mainWindow()) {
mainWindow()->setVisible(!mainWindow()->isVisible());
} else {
openOrRaiseMainWindow();
}
}
void KleopatraApplication::restoreMainWindow()
{
qCDebug(KLEOPATRA_LOG) << "restoring main window";
// Sanity checks
if (!isSessionRestored()) {
qCDebug(KLEOPATRA_LOG) << "Not in session restore";
return;
}
if (mainWindow()) {
qCDebug(KLEOPATRA_LOG) << "Already have main window";
return;
}
MainWindow *mw = new MainWindow;
if (KMainWindow::canBeRestored(1)) {
// restore to hidden state, Mainwindow::readProperties() will
// restore saved visibility.
mw->restore(1, false);
}
mw->setAttribute(Qt::WA_DeleteOnClose);
setMainWindow(mw);
d->connectConfigureDialog();
}
void KleopatraApplication::openOrRaiseMainWindow()
{
MainWindow *mw = mainWindow();
if (!mw) {
mw = new MainWindow;
mw->setAttribute(Qt::WA_DeleteOnClose);
setMainWindow(mw);
d->connectConfigureDialog();
}
open_or_raise(mw);
UpdateNotification::checkUpdate(mw);
}
void KleopatraApplication::openConfigDialogWithForeignParent(WId parentWId)
{
if (!d->configureDialog) {
d->configureDialog = new ConfigureDialog;
d->configureDialog->setAttribute(Qt::WA_DeleteOnClose);
d->connectConfigureDialog();
}
// This is similar to what the commands do.
if (parentWId) {
if (QWidget *pw = QWidget::find(parentWId)) {
d->configureDialog->setParent(pw, d->configureDialog->windowFlags());
} else {
KWindowSystem::setMainWindow(d->configureDialog, parentWId);
}
}
open_or_raise(d->configureDialog);
// If we have a parent we want to raise over it.
if (parentWId) {
d->configureDialog->raise();
}
}
void KleopatraApplication::openOrRaiseConfigDialog()
{
openConfigDialogWithForeignParent(0);
}
#ifndef QT_NO_SYSTEMTRAYICON
void KleopatraApplication::startMonitoringSmartCard()
{
d->readerStatus.startMonitoring();
}
#endif // QT_NO_SYSTEMTRAYICON
void KleopatraApplication::importCertificatesFromFile(const QStringList &files, GpgME::Protocol /*proto*/)
{
openOrRaiseMainWindow();
if (!files.empty()) {
mainWindow()->importCertificatesFromFile(files);
}
}
void KleopatraApplication::encryptFiles(const QStringList &files, GpgME::Protocol proto)
{
SignEncryptFilesCommand *const cmd = new SignEncryptFilesCommand(files, nullptr);
cmd->setEncryptionPolicy(Force);
cmd->setSigningPolicy(Allow);
if (proto != GpgME::UnknownProtocol) {
cmd->setProtocol(proto);
}
cmd->start();
}
void KleopatraApplication::signFiles(const QStringList &files, GpgME::Protocol proto)
{
SignEncryptFilesCommand *const cmd = new SignEncryptFilesCommand(files, nullptr);
cmd->setSigningPolicy(Force);
cmd->setEncryptionPolicy(Deny);
if (proto != GpgME::UnknownProtocol) {
cmd->setProtocol(proto);
}
cmd->start();
}
void KleopatraApplication::signEncryptFiles(const QStringList &files, GpgME::Protocol proto)
{
SignEncryptFilesCommand *const cmd = new SignEncryptFilesCommand(files, nullptr);
if (proto != GpgME::UnknownProtocol) {
cmd->setProtocol(proto);
}
cmd->start();
}
void KleopatraApplication::decryptFiles(const QStringList &files, GpgME::Protocol /*proto*/)
{
DecryptVerifyFilesCommand *const cmd = new DecryptVerifyFilesCommand(files, nullptr);
cmd->setOperation(Decrypt);
cmd->start();
}
void KleopatraApplication::verifyFiles(const QStringList &files, GpgME::Protocol /*proto*/)
{
DecryptVerifyFilesCommand *const cmd = new DecryptVerifyFilesCommand(files, nullptr);
cmd->setOperation(Verify);
cmd->start();
}
void KleopatraApplication::decryptVerifyFiles(const QStringList &files, GpgME::Protocol /*proto*/)
{
DecryptVerifyFilesCommand *const cmd = new DecryptVerifyFilesCommand(files, nullptr);
cmd->start();
}
void KleopatraApplication::checksumFiles(const QStringList &files, GpgME::Protocol /*proto*/)
{
QStringList verifyFiles, createFiles;
for (const QString &file : files) {
if (isChecksumFile(file)) {
verifyFiles << file;
} else {
createFiles << file;
}
}
if (!verifyFiles.isEmpty()) {
auto *const cmd = new ChecksumVerifyFilesCommand(verifyFiles, nullptr);
cmd->start();
}
if (!createFiles.isEmpty()) {
auto *const cmd = new ChecksumCreateFilesCommand(createFiles, nullptr);
cmd->start();
}
}
void KleopatraApplication::setIgnoreNewInstance(bool ignore)
{
d->ignoreNewInstance = ignore;
}
bool KleopatraApplication::ignoreNewInstance() const
{
return d->ignoreNewInstance;
}
diff --git a/src/smartcard/openpgpcard.cpp b/src/smartcard/openpgpcard.cpp
index 20581dd09..cf963ad09 100644
--- a/src/smartcard/openpgpcard.cpp
+++ b/src/smartcard/openpgpcard.cpp
@@ -1,236 +1,236 @@
/* smartcard/openpgpcard.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2017 by Bundesamt für Sicherheit in der Informationstechnik
Software engineering by Intevation GmbH
Kleopatra 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.
Kleopatra 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
/* Code in this file is partly based on the GNU Privacy Assistant
* (cm-openpgp.c) git rev. 0a78795146661234070681737b3e08228616441f
*
* Whis is:
* Copyright (C) 2008, 2009 g10 Code GmbH
*
* And may be licensed under 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 "openpgpcard.h"
#include "kleopatra_debug.h"
using namespace Kleo;
using namespace Kleo::SmartCard;
#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
*(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
namespace
{
static const char * get_manufacturer (unsigned int no)
{
switch (no) {
case 0x0001: return "PPC Card Systems";
case 0x0002: return "Prism";
case 0x0003: return "OpenFortress";
case 0x0004: return "Wewid";
case 0x0005: return "ZeitControl";
case 0x0006: return "Yubico";
case 0x0007: return "OpenKMS";
case 0x0008: return "LogoEmail";
case 0x002A: return "Magrathea";
case 0x1337: return "Warsaw Hackerspace";
case 0xF517: return "FSIJ";
/* 0x0000 and 0xFFFF are defined as test cards per spec,
0xFF00 to 0xFFFE are assigned for use with randomly created
serial numbers. */
case 0x0000:
case 0xffff: return "test card";
default: return (no & 0xff00) == 0xff00? "unmanaged S/N range":"unknown";
}
}
} // namespace
OpenPGPCard::OpenPGPCard()
{
setAppType(Card::OpenPGPApplication);
}
OpenPGPCard::OpenPGPCard(const std::string &serialno): OpenPGPCard()
{
setSerialNumber(serialno);
}
std::string OpenPGPCard::sigFpr() const
{
return mMetaInfo.value("SIGKEY-FPR");
}
std::string OpenPGPCard::encFpr() const
{
return mMetaInfo.value("ENCKEY-FPR");
}
std::string OpenPGPCard::authFpr() const
{
return mMetaInfo.value("AUTHKEY-FPR");
}
void OpenPGPCard::setKeyPairInfo(const std::vector< std::pair<std::string, std::string> > &infos)
{
qCDebug(KLEOPATRA_LOG) << "Card" << serialNumber().c_str() << "info:";
for (const auto &pair: infos) {
qCDebug(KLEOPATRA_LOG) << pair.first.c_str() << ":" << pair.second.c_str();
if (pair.first == "KEY-FPR" ||
pair.first == "KEY-TIME") {
// Key fpr and key time need to be distinguished, the number
// of the key decides the usage.
const auto values = QString::fromStdString(pair.second).split(QLatin1Char(' '));
if (values.size() < 2) {
qCWarning(KLEOPATRA_LOG) << "Invalid entry.";
setStatus(Card::CardError);
continue;
}
const auto usage = values[0];
const auto fpr = values[1].toStdString();
- if (usage == "1") {
+ if (usage == QLatin1String("1")) {
mMetaInfo.insert(std::string("SIG") + pair.first, fpr);
- } else if (usage == "2") {
+ } else if (usage == QLatin1String("2")) {
mMetaInfo.insert(std::string("ENC") + pair.first, fpr);
- } else if (usage == "3") {
+ } else if (usage == QLatin1String("3")) {
mMetaInfo.insert(std::string("AUTH") + pair.first, fpr);
} else {
// Maybe more keyslots in the future?
qCDebug(KLEOPATRA_LOG) << "Unhandled keyslot";
}
} else if (pair.first == "KEYPAIRINFO") {
// Fun, same as above but the other way around.
const auto values = QString::fromStdString(pair.second).split(QLatin1Char(' '));
if (values.size() < 2) {
qCWarning(KLEOPATRA_LOG) << "Invalid entry.";
setStatus(Card::CardError);
continue;
}
const auto usage = values[1];
const auto grip = values[0].toStdString();
- if (usage == "OPENPGP.1") {
+ if (usage == QLatin1String("OPENPGP.1")) {
mMetaInfo.insert(std::string("SIG") + pair.first, grip);
- } else if (usage == "OPENPGP.2") {
+ } else if (usage == QLatin1String("OPENPGP.2")) {
mMetaInfo.insert(std::string("ENC") + pair.first, grip);
- } else if (usage == "OPENPGP.3") {
+ } else if (usage == QLatin1String("OPENPGP.3")) {
mMetaInfo.insert(std::string("AUTH") + pair.first, grip);
} else {
// Maybe more keyslots in the future?
qCDebug(KLEOPATRA_LOG) << "Unhandled keyslot";
}
} else {
mMetaInfo.insert(pair.first, pair.second);
}
}
}
void OpenPGPCard::setSerialNumber(const std::string &serialno)
{
char version_buffer[6];
const char *version = "";
const char *string = serialno.c_str();
Card::setSerialNumber(serialno);
if (strncmp(string, "D27600012401", 12) || strlen(string) != 32 ) {
/* Not a proper OpenPGP card serialnumber. Display the full
serialnumber. */
mManufacturer = "unknown";
} else {
/* Reformat the version number to be better human readable. */
char *p = version_buffer;
if (string[12] != '0') {
*p++ = string[12];
}
*p++ = string[13];
*p++ = '.';
if (string[14] != '0') {
*p++ = string[14];
}
*p++ = string[15];
*p++ = '\0';
version = version_buffer;
/* Get the manufactorer. */
mManufacturer = get_manufacturer(xtoi_2(string + 16)*256 + xtoi_2(string + 18));
}
mIsV2 = !((*version == '1' || *version == '0') && version[1] == '.');
mCardVersion = version;
}
bool OpenPGPCard::operator == (const Card& rhs) const
{
const OpenPGPCard *other = dynamic_cast<const OpenPGPCard *>(&rhs);
if (!other) {
return false;
}
return Card::operator ==(rhs)
&& sigFpr() == other->sigFpr()
&& encFpr() == other->encFpr()
&& authFpr() == other->authFpr()
&& manufacturer() == other->manufacturer()
&& cardVersion() == other->cardVersion()
&& cardHolder() == other->cardHolder()
&& pubkeyUrl() == other->pubkeyUrl();
}
std::string OpenPGPCard::manufacturer() const
{
return mManufacturer;
}
std::string OpenPGPCard::cardVersion() const
{
return mCardVersion;
}
std::string OpenPGPCard::cardHolder() const
{
- auto list = QString::fromStdString(mMetaInfo.value("DISP-NAME")).split("<<");
+ auto list = QString::fromStdString(mMetaInfo.value("DISP-NAME")).split(QStringLiteral("<<"));
std::reverse(list.begin(), list.end());
return list.join(QLatin1Char(' ')).toStdString();
}
std::string OpenPGPCard::pubkeyUrl() const
{
return mMetaInfo.value("PUBKEY-URL");
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, May 10, 9:12 AM (3 h, 14 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
a1/54/6396fd3828d3f6a15665ac27a1c4

Event Timeline