Page MenuHome GnuPG

No OneTemporary

diff --git a/src/crypto/gui/signencryptfileswizard.cpp b/src/crypto/gui/signencryptfileswizard.cpp
index ef6188b7c..8a91fdc9f 100644
--- a/src/crypto/gui/signencryptfileswizard.cpp
+++ b/src/crypto/gui/signencryptfileswizard.cpp
@@ -1,516 +1,518 @@
/* crypto/gui/signencryptfileswizard.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2009 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 "signencryptfileswizard.h"
#include "signencryptwidget.h"
#include "newresultpage.h"
#include <KLocalizedString>
#include <KSharedConfig>
#include <KColorScheme>
#include <KConfigGroup>
#include <KMessageBox>
#include "kleopatra_debug.h"
#include <utils/gnupg-helper.h>
#include <Libkleo/FileNameRequester>
#include <QVBoxLayout>
#include <QWizardPage>
#include <QGroupBox>
#include <QLabel>
#include <QIcon>
#include <QCheckBox>
#include <gpgme++/key.h>
using namespace GpgME;
using namespace Kleo;
using namespace Kleo::Crypto::Gui;
enum Page {
SigEncPageId,
ResultPageId,
NumPages
};
class SigEncPage: public QWizardPage
{
Q_OBJECT
public:
explicit SigEncPage(QWidget *parent = nullptr)
: QWizardPage(parent),
mParent((SignEncryptFilesWizard *) parent),
mWidget(new SignEncryptWidget),
mOutLayout(new QVBoxLayout),
mArchive(false),
mUseOutputDir(false)
{
setTitle(i18nc("@title", "Sign / Encrypt Files"));
auto vLay = new QVBoxLayout(this);
vLay->setMargin(0);
vLay->addWidget(mWidget);
connect(mWidget, &SignEncryptWidget::operationChanged, this,
&SigEncPage::updateCommitButton);
connect(mWidget, &SignEncryptWidget::keysChanged, this,
&SigEncPage::updateFileWidgets);
updateCommitButton(mWidget->currentOp());
auto outputGrp = new QGroupBox(i18n("Output"));
outputGrp->setLayout(mOutLayout);
mPlaceholderWidget = new QLabel(i18n("Please select an action."));
mOutLayout->addWidget(mPlaceholderWidget);
mUseOutputDirChk = new QCheckBox(i18n("Encrypt / Sign each file separately."));
mUseOutputDirChk->setToolTip(i18nc("@info",
"Keep each file separate instead of creating an archive for all."));
mOutLayout->addWidget(mUseOutputDirChk);
connect (mUseOutputDirChk, &QCheckBox::toggled, this, [this] (bool state) {
mUseOutputDir = state;
mArchive = !mUseOutputDir;
updateFileWidgets();
});
vLay->addWidget(outputGrp);
setMinimumHeight(300);
}
+ void setEncryptionPreset(bool value)
+ {
+ mWidget->setEncryptionChecked(value);
+ }
+
+ void setSigningPreset(bool value)
+ {
+ mWidget->setSigningChecked(value);
+ }
+
bool isComplete() const override
{
return !mWidget->currentOp().isNull();
}
int nextId() const override
{
return ResultPageId;
}
void initializePage() override
{
setCommitPage(true);
}
void setArchiveForced(bool archive)
{
mArchive = archive;
setArchiveMutable(!archive);
}
void setArchiveMutable(bool archive)
{
mUseOutputDirChk->setVisible(archive);
if (archive) {
const KConfigGroup archCfg(KSharedConfig::openConfig(), "SignEncryptFilesWizard");
mUseOutputDirChk->setChecked(archCfg.readEntry("LastUseOutputDir", false));
} else {
mUseOutputDirChk->setChecked(false);
}
}
bool validatePage() override
{
bool sign = !mWidget->signKey().isNull();
bool encrypt = !mWidget->selfKey().isNull() || !mWidget->recipients().empty();
mWidget->saveOwnKeys();
if (mUseOutputDirChk->isVisible()) {
KConfigGroup archCfg(KSharedConfig::openConfig(), "SignEncryptFilesWizard");
archCfg.writeEntry("LastUseOutputDir", mUseOutputDir);
}
if (sign && !encrypt && mArchive) {
return KMessageBox::warningContinueCancel(this,
xi18nc("@info",
"<para>Archiving in combination with sign-only currently requires what are known as opaque signatures - "
"unlike detached ones, these embed the content in the signature.</para>"
"<para>This format is rather unusual. You might want to archive the files separately, "
"and then sign the archive as one file with Kleopatra.</para>"
"<para>Future versions of Kleopatra are expected to also support detached signatures in this case.</para>"),
i18nc("@title:window", "Unusual Signature Warning"),
KStandardGuiItem::cont(), KStandardGuiItem::cancel(),
QStringLiteral("signencryptfileswizard-archive+sign-only-warning"))
== KMessageBox::Continue;
} else if (sign && !encrypt) {
return true;
}
if (!mWidget->selfKey().isNull()) {
return true;
}
bool hasSecret = false;
Q_FOREACH (const Key k, mWidget->recipients()) {
if (k.hasSecret()) {
hasSecret = true;
break;
}
}
if (!hasSecret && !mWidget->encryptSymmetric()) {
if (KMessageBox::warningContinueCancel(this,
xi18nc("@info",
"<para>None of the recipients you are encrypting to seems to be your own.</para>"
"<para>This means that you will not be able to decrypt the data anymore, once encrypted.</para>"
"<para>Do you want to continue, or cancel to change the recipient selection?</para>"),
i18nc("@title:window", "Encrypt-To-Self Warning"),
KStandardGuiItem::cont(),
KStandardGuiItem::cancel(),
QStringLiteral("warn-encrypt-to-non-self"), KMessageBox::Notify | KMessageBox::Dangerous)
== KMessageBox::Cancel) {
return false;
}
}
return true;
}
QVector<Key> recipients() const
{
return mWidget->recipients();
}
/* In the future we might find a usecase for multiple
* signers */
QVector<Key> signers() const
{
QVector<Key> ret;
const Key k = mWidget->signKey();
if (!k.isNull()) {
ret << k;
}
return ret;
}
private:
QWidget *createRequester(int forKind, QBoxLayout *lay) {
static const QMap <int, QString> icons = {
{ SignEncryptFilesWizard::SignatureCMS, QStringLiteral("document-sign") },
{ SignEncryptFilesWizard::SignaturePGP, QStringLiteral("document-sign") },
{ SignEncryptFilesWizard::CombinedPGP, QStringLiteral("document-edit-sign-encrypt") },
{ SignEncryptFilesWizard::EncryptedPGP, QStringLiteral("document-encrypt") },
{ SignEncryptFilesWizard::EncryptedCMS, QStringLiteral("document-encrypt") },
{ SignEncryptFilesWizard::Directory, QStringLiteral("folder") }
};
static const QMap <int, QString> toolTips = {
{ SignEncryptFilesWizard::SignatureCMS, i18n("The S/MIME signature.") },
{ SignEncryptFilesWizard::SignaturePGP, i18n("The signature.") },
{ SignEncryptFilesWizard::CombinedPGP, i18n("The signed and encrypted file.") },
{ SignEncryptFilesWizard::EncryptedPGP, i18n("The encrypted file.") },
{ SignEncryptFilesWizard::EncryptedCMS, i18n("The S/MIME encrypted file.") },
{ SignEncryptFilesWizard::Directory, i18n("Output directory.") }
};
FileNameRequester *req = new FileNameRequester(forKind == SignEncryptFilesWizard::Directory ?
QDir::Dirs : QDir::Files, this);
req->setFileName(mOutNames[forKind]);
QHBoxLayout *hLay = new QHBoxLayout;
QLabel *iconLabel = new QLabel;
QWidget *ret = new QWidget;
iconLabel->setPixmap(QIcon::fromTheme(icons[forKind]).pixmap(32,32));
hLay->addWidget(iconLabel);
iconLabel->setToolTip(toolTips[forKind]);
req->setToolTip(toolTips[forKind]);
hLay->addWidget(req);
ret->setLayout(hLay);
lay->addWidget(ret);
connect (req, &FileNameRequester::fileNameChanged, this,
[this, forKind](const QString &newName) {
mOutNames[forKind] = newName;
});
return ret;
}
public:
void setOutputNames(const QMap<int, QString> &names) {
Q_ASSERT(mOutNames.isEmpty());
mOutNames = names;
Q_FOREACH (int i, mOutNames.keys()) {
mRequester[i] = createRequester(i, mOutLayout);
}
updateFileWidgets();
}
QMap <int, QString> outputNames() const {
if (!mUseOutputDir) {
auto ret = mOutNames;
ret.remove(SignEncryptFilesWizard::Directory);
return ret;
}
return mOutNames;
}
bool encryptSymmetric() const
{
return mWidget->encryptSymmetric();
}
private Q_SLOTS:
void updateCommitButton(const QString &label)
{
auto btn = mParent->button(QWizard::CommitButton);
if (!label.isEmpty()) {
btn->setText(label);
if (Kleo::gpgComplianceP("de-vs")) {
bool de_vs = mWidget->isDeVsAndValid();
btn->setIcon(QIcon::fromTheme(de_vs
? "security-high"
: "security-medium"));
btn->setStyleSheet(QStringLiteral("background-color: ") + (de_vs
? KColorScheme(QPalette::Active, KColorScheme::View).background(KColorScheme::PositiveBackground).color().name()
: KColorScheme(QPalette::Active, KColorScheme::View).background(KColorScheme::NegativeBackground).color().name()));
mParent->setLabelText(de_vs
? i18nc("VS-NfD-conforming is a German standard for restricted documents for which special restrictions about algorithms apply. The string states that all cryptographic operations necessary for the communication are compliant with that.",
"VS-NfD-compliant communication possible.")
: i18nc("VS-NfD-conforming is a German standard for restricted documents for which special restrictions about algorithms apply. The string states that all cryptographic operations necessary for the communication are compliant with that.",
"VS-NfD-compliant communication not possible."));
}
} else {
btn->setText(i18n("Next"));
btn->setIcon(QIcon());
btn->setStyleSheet("");
}
Q_EMIT completeChanged();
}
void updateFileWidgets()
{
if (mRequester.isEmpty()) {
return;
}
const QVector<Key> recipients = mWidget->recipients();
const Key sigKey = mWidget->signKey();
bool pgp = mWidget->encryptSymmetric();
bool cms = false;
for (const Key &k : recipients) {
if (pgp && cms) {
break;
}
if (k.protocol() == Protocol::OpenPGP) {
pgp = true;
} else {
cms = true;
}
}
mOutLayout->setEnabled(false);
mPlaceholderWidget->setVisible(!cms && !pgp && sigKey.isNull());
mRequester[SignEncryptFilesWizard::SignatureCMS]->setVisible(!mUseOutputDir && sigKey.protocol() == Protocol::CMS);
mRequester[SignEncryptFilesWizard::EncryptedCMS]->setVisible(!mUseOutputDir && cms);
mRequester[SignEncryptFilesWizard::CombinedPGP]->setVisible(!mUseOutputDir && sigKey.protocol() == Protocol::OpenPGP && pgp);
mRequester[SignEncryptFilesWizard::EncryptedPGP]->setVisible(!mUseOutputDir && pgp && sigKey.protocol() != Protocol::OpenPGP);
mRequester[SignEncryptFilesWizard::SignaturePGP]->setVisible(!mUseOutputDir && sigKey.protocol() == Protocol::OpenPGP && !pgp);
mRequester[SignEncryptFilesWizard::Directory]->setVisible(mUseOutputDir && !mPlaceholderWidget->isVisible());
mOutLayout->setEnabled(true);
}
private:
SignEncryptFilesWizard *mParent;
SignEncryptWidget *mWidget;
QMap <int, QString> mOutNames;
QMap <int, QWidget *> mRequester;
QVBoxLayout *mOutLayout;
QWidget *mPlaceholderWidget;
QCheckBox *mUseOutputDirChk;
bool mArchive;
bool mUseOutputDir;
};
class ResultPage : public NewResultPage
{
Q_OBJECT
public:
explicit ResultPage(QWidget *parent = nullptr)
: NewResultPage(parent),
mParent((SignEncryptFilesWizard *) parent)
{
setTitle(i18nc("@title", "Results"));
setSubTitle(i18nc("@title",
"Status and progress of the crypto operations is shown here."));
}
void initializePage() override
{
mParent->setLabelText(QString());
}
private:
SignEncryptFilesWizard *mParent;
};
SignEncryptFilesWizard::SignEncryptFilesWizard(QWidget *parent, Qt::WindowFlags f)
: QWizard(parent, f)
- , mSigningPreset(false)
- , mSigningUserMutable(false)
- , mEncryptionUserMutable(false)
- , mEncryptionPreset(false)
+ , mSigningUserMutable(true)
+ , mEncryptionUserMutable(true)
{
bool de_vs = Kleo::gpgComplianceP("de-vs");
#ifdef Q_OS_WIN
// Enforce modern style to avoid vista style ugliness.
setWizardStyle(QWizard::ModernStyle);
#endif
mSigEncPage = new SigEncPage(this);
mResultPage = new ResultPage(this);
connect(this, &QWizard::currentIdChanged, this,
&SignEncryptFilesWizard::slotCurrentIdChanged);
setPage(SigEncPageId, mSigEncPage);
setPage(ResultPageId, mResultPage);
setOptions(QWizard::IndependentPages |
(de_vs ? QWizard::HaveCustomButton1 : (QWizard::WizardOption) 0) |
QWizard::NoBackButtonOnLastPage |
QWizard::NoBackButtonOnStartPage);
if (de_vs) {
/* We use a custom button to display a label next to the
buttons. */
mLabel = button(QWizard::CustomButton1);
/* We style the button so that it looks and acts like a
label. */
mLabel->setStyleSheet("border: none");
mLabel->setFocusPolicy(Qt::NoFocus);
} else {
mLabel = NULL;
}
KConfigGroup cfgGroup(KSharedConfig::openConfig(), "SignEncryptFilesWizard");
const QByteArray geom = cfgGroup.readEntry("geometry", QByteArray());
if (!geom.isEmpty()) {
restoreGeometry(geom);
return;
}
}
void SignEncryptFilesWizard::setLabelText(const QString &label) const
{
if (mLabel) {
mLabel->setText(label);
}
}
void SignEncryptFilesWizard::slotCurrentIdChanged(int id)
{
if (id == ResultPageId) {
Q_EMIT operationPrepared();
}
}
SignEncryptFilesWizard::~SignEncryptFilesWizard()
{
qCDebug(KLEOPATRA_LOG);
KConfigGroup cfgGroup(KSharedConfig::openConfig(), "SignEncryptFilesWizard");
cfgGroup.writeEntry("geometry", saveGeometry());
cfgGroup.sync();
}
void SignEncryptFilesWizard::setSigningPreset(bool preset)
{
- if (preset == mSigningPreset) {
- return;
- }
- mSigningPreset = preset;
+ mSigEncPage->setSigningPreset(preset);
}
void SignEncryptFilesWizard::setSigningUserMutable(bool mut)
{
if (mut == mSigningUserMutable) {
return;
}
mSigningUserMutable = mut;
}
void SignEncryptFilesWizard::setEncryptionPreset(bool preset)
{
- if (preset == mEncryptionPreset) {
- return;
- }
- mEncryptionPreset = preset;
+ mSigEncPage->setEncryptionPreset(preset);
}
void SignEncryptFilesWizard::setEncryptionUserMutable(bool mut)
{
if (mut == mEncryptionUserMutable) {
return;
}
mEncryptionUserMutable = mut;
}
void SignEncryptFilesWizard::setArchiveForced(bool archive)
{
mSigEncPage->setArchiveForced(archive);
}
void SignEncryptFilesWizard::setArchiveMutable(bool archive)
{
mSigEncPage->setArchiveMutable(archive);
}
QVector<Key> SignEncryptFilesWizard::resolvedRecipients() const
{
return mSigEncPage->recipients();
}
QVector<Key> SignEncryptFilesWizard::resolvedSigners() const
{
return mSigEncPage->signers();
}
void SignEncryptFilesWizard::setTaskCollection(const std::shared_ptr<Kleo::Crypto::TaskCollection> &coll)
{
mResultPage->setTaskCollection(coll);
}
void SignEncryptFilesWizard::setOutputNames(const QMap<int, QString> &map) const
{
mSigEncPage->setOutputNames(map);
}
QMap<int, QString> SignEncryptFilesWizard::outputNames() const
{
return mSigEncPage->outputNames();
}
bool SignEncryptFilesWizard::encryptSymmetric() const
{
return mSigEncPage->encryptSymmetric();
}
#include "signencryptfileswizard.moc"
diff --git a/src/crypto/gui/signencryptfileswizard.h b/src/crypto/gui/signencryptfileswizard.h
index 2e8015379..c74457136 100644
--- a/src/crypto/gui/signencryptfileswizard.h
+++ b/src/crypto/gui/signencryptfileswizard.h
@@ -1,125 +1,123 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/gui/signencryptfileswizard.h
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2009 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.
*/
#ifndef __KLEOPATRA_CRYPTO_GUI_SIGNENCRYPTFILESWIZARD_H__
#define __KLEOPATRA_CRYPTO_GUI_SIGNENCRYPTFILESWIZARD_H__
#include <utils/pimpl_ptr.h>
#include <gpgme++/global.h>
#include <QWizard>
#include <QVector>
#include <QMap>
#include <memory>
namespace GpgME
{
class Key;
}
namespace Kleo
{
namespace Crypto
{
class TaskCollection;
}
}
class ResultPage;
class SigEncPage;
namespace Kleo
{
class SignEncryptFilesWizard : public QWizard
{
Q_OBJECT
public:
enum KindNames{
SignatureCMS,
CombinedPGP,
EncryptedPGP,
EncryptedCMS,
SignaturePGP,
Directory
};
explicit SignEncryptFilesWizard(QWidget *parent = nullptr, Qt::WindowFlags f = 0);
~SignEncryptFilesWizard();
// Inputs
void setSigningPreset(bool preset);
void setSigningUserMutable(bool mut);
void setEncryptionPreset(bool preset);
void setEncryptionUserMutable(bool mut);
void setArchiveForced(bool archive);
void setArchiveMutable(bool archive);
void setOutputNames(const QMap<int, QString> &nameMap) const;
QMap<int, QString> outputNames() const;
void setTaskCollection(const std::shared_ptr<Kleo::Crypto::TaskCollection> &coll);
// Outputs
QVector<GpgME::Key> resolvedRecipients() const;
QVector<GpgME::Key> resolvedSigners() const;
bool encryptSymmetric() const;
void setLabelText(const QString &label) const;
Q_SIGNALS:
void operationPrepared();
private Q_SLOTS:
void slotCurrentIdChanged(int);
private:
SigEncPage *mSigEncPage;
ResultPage *mResultPage;
QAbstractButton *mLabel;
- bool mSigningPreset,
- mSigningUserMutable,
- mEncryptionUserMutable,
- mEncryptionPreset;
+ bool mSigningUserMutable,
+ mEncryptionUserMutable;
};
}
#endif /* __KLEOPATRA_CRYPTO_GUI_SIGNENCRYPTFILESWIZARD_H__ */
diff --git a/src/crypto/gui/signencryptwidget.cpp b/src/crypto/gui/signencryptwidget.cpp
index 95d2af8db..61d18abf7 100644
--- a/src/crypto/gui/signencryptwidget.cpp
+++ b/src/crypto/gui/signencryptwidget.cpp
@@ -1,385 +1,396 @@
/* crypto/gui/signencryptwidget.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 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 "signencryptwidget.h"
#include "kleopatra_debug.h"
#include "certificatelineedit.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGroupBox>
#include <QCheckBox>
#include <QScrollArea>
#include <QScrollBar>
#include <Libkleo/DefaultKeyFilter>
#include <Libkleo/KeyCache>
#include <Libkleo/KeyListModel>
#include <Libkleo/KeySelectionCombo>
#include <Libkleo/KeyListSortFilterProxyModel>
#include <utils/gnupg-helper.h>
#include <KLocalizedString>
#include <KConfigGroup>
#include <KSharedConfig>
using namespace Kleo;
using namespace Kleo::Dialogs;
using namespace GpgME;
namespace {
class SignCertificateFilter: public DefaultKeyFilter
{
public:
SignCertificateFilter() : DefaultKeyFilter()
{
setRevoked(DefaultKeyFilter::NotSet);
setExpired(DefaultKeyFilter::NotSet);
setHasSecret(DefaultKeyFilter::Set);
setCanSign(DefaultKeyFilter::Set);
}
};
class EncryptCertificateFilter: public DefaultKeyFilter
{
public:
EncryptCertificateFilter(): DefaultKeyFilter()
{
setRevoked(DefaultKeyFilter::NotSet);
setExpired(DefaultKeyFilter::NotSet);
setCanEncrypt(DefaultKeyFilter::Set);
}
};
class EncryptSelfCertificateFilter: public EncryptCertificateFilter
{
public:
EncryptSelfCertificateFilter(): EncryptCertificateFilter()
{
setRevoked(DefaultKeyFilter::NotSet);
setExpired(DefaultKeyFilter::NotSet);
setCanEncrypt(DefaultKeyFilter::Set);
setHasSecret(DefaultKeyFilter::Set);
}
};
}
SignEncryptWidget::SignEncryptWidget(QWidget *parent)
: QWidget(parent),
mModel(AbstractKeyListModel::createFlatKeyListModel(this)),
mRecpRowCount(2)
{
QVBoxLayout *lay = new QVBoxLayout(this);
lay->setMargin(0);
mModel->useKeyCache(true, false);
/* The signature selection */
QHBoxLayout *sigLay = new QHBoxLayout;
QGroupBox *sigGrp = new QGroupBox(i18n("Prove authenticity (sign)"));
- QCheckBox *sigChk = new QCheckBox(i18n("Sign as:"));
- sigChk->setChecked(true);
+ mSigChk = new QCheckBox(i18n("Sign as:"));
+ mSigChk->setChecked(true);
mSigSelect = new KeySelectionCombo();
mSigSelect->setKeyFilter(std::shared_ptr<KeyFilter>(new SignCertificateFilter()));
- sigLay->addWidget(sigChk);
+ sigLay->addWidget(mSigChk);
sigLay->addWidget(mSigSelect, 1);
sigGrp->setLayout(sigLay);
lay->addWidget(sigGrp);
- connect(sigChk, &QCheckBox::toggled, mSigSelect, &QWidget::setEnabled);
- connect(sigChk, &QCheckBox::toggled, this, &SignEncryptWidget::updateOp);
+ connect(mSigChk, &QCheckBox::toggled, mSigSelect, &QWidget::setEnabled);
+ connect(mSigChk, &QCheckBox::toggled, this, &SignEncryptWidget::updateOp);
connect(mSigSelect, &KeySelectionCombo::currentKeyChanged,
this, &SignEncryptWidget::updateOp);
// Recipient selection
mRecpLayout = new QGridLayout;
mRecpLayout->setAlignment(Qt::AlignTop);
QVBoxLayout *encBoxLay = new QVBoxLayout;
QGroupBox *encBox = new QGroupBox(i18nc("@action", "Encrypt"));
encBox->setLayout(encBoxLay);
encBox->setAlignment(Qt::AlignLeft);
// Own key
mSelfSelect = new KeySelectionCombo();
mSelfSelect->setKeyFilter(std::shared_ptr<KeyFilter>(new EncryptSelfCertificateFilter()));
- QCheckBox *encSelfChk = new QCheckBox(i18n("Encrypt for me:"));
- encSelfChk->setChecked(true);
- mRecpLayout->addWidget(encSelfChk, 0, 0);
+ mEncSelfChk = new QCheckBox(i18n("Encrypt for me:"));
+ mEncSelfChk->setChecked(true);
+ mRecpLayout->addWidget(mEncSelfChk, 0, 0);
mRecpLayout->addWidget(mSelfSelect, 0, 1);
// Checkbox for other keys
- QCheckBox *encOtherChk = new QCheckBox(i18n("Encrypt for others:"));
- mRecpLayout->addWidget(encOtherChk, 1, 0);
- encOtherChk->setChecked(true);
- connect(encOtherChk, &QCheckBox::toggled, this,
+ mEncOtherChk = new QCheckBox(i18n("Encrypt for others:"));
+ mRecpLayout->addWidget(mEncOtherChk, 1, 0);
+ mEncOtherChk->setChecked(true);
+ connect(mEncOtherChk, &QCheckBox::toggled, this,
[this](bool toggled) {
Q_FOREACH (CertificateLineEdit *edit, mRecpWidgets) {
edit->setEnabled(toggled);
}
updateOp();
});
// Scroll area for other keys
QWidget *recipientWidget = new QWidget;
QScrollArea *recipientScroll = new QScrollArea;
recipientWidget->setLayout(mRecpLayout);
recipientScroll->setWidget(recipientWidget);
recipientScroll->setWidgetResizable(true);
recipientScroll->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow);
recipientScroll->setFrameStyle(QFrame::NoFrame);
mRecpLayout->setMargin(0);
encBoxLay->addWidget(recipientScroll, 1);
auto bar = recipientScroll->verticalScrollBar();
connect (bar, &QScrollBar::rangeChanged, this, [bar] (int, int max) {
bar->setValue(max);
});
// Checkbox for password
mSymmetric = new QCheckBox(i18n("Encrypt with password. Anyone you share the password with can read the data."));
mSymmetric->setToolTip(i18nc("Tooltip information for symetric encryption",
"Additionally to the keys of the recipients you can encrypt your data with a password. "
"Anyone who has the password can read the data without any secret key. "
"Using a password is <b>less secure</b> then public key cryptography. Even if you pick a very strong password."));
encBoxLay->addWidget(mSymmetric);
// Connect it
connect(encBox, &QGroupBox::toggled, recipientWidget, &QWidget::setEnabled);
connect(encBox, &QGroupBox::toggled, this, &SignEncryptWidget::updateOp);
- connect(encSelfChk, &QCheckBox::toggled, mSelfSelect, &QWidget::setEnabled);
- connect(encSelfChk, &QCheckBox::toggled, this, &SignEncryptWidget::updateOp);
+ connect(mEncSelfChk, &QCheckBox::toggled, mSelfSelect, &QWidget::setEnabled);
+ connect(mEncSelfChk, &QCheckBox::toggled, this, &SignEncryptWidget::updateOp);
connect(mSymmetric, &QCheckBox::toggled, this, &SignEncryptWidget::updateOp);
connect(mSelfSelect, &KeySelectionCombo::currentKeyChanged,
this, &SignEncryptWidget::updateOp);
- // Ensure that the sigChk is aligned togehter with the encryption check boxes.
- sigChk->setMinimumWidth(qMax(encOtherChk->width(), encSelfChk->width()));
+ // Ensure that the mSigChk is aligned togehter with the encryption check boxes.
+ mSigChk->setMinimumWidth(qMax(mEncOtherChk->width(), mEncSelfChk->width()));
lay->addWidget(encBox);
loadKeys();
addRecipient(Key());
updateOp();
}
void SignEncryptWidget::addRecipient()
{
addRecipient(Key());
}
void SignEncryptWidget::addRecipient(const Key &key)
{
CertificateLineEdit *certSel = new CertificateLineEdit(mModel, this,
new EncryptCertificateFilter());
mRecpWidgets << certSel;
if (!mRecpLayout->itemAtPosition(mRecpRowCount - 1, 1)) {
// First widget. Should align with the row above that
// contians the encrypt for others checkbox.
mRecpLayout->addWidget(certSel, mRecpRowCount - 1, 1);
} else {
mRecpLayout->addWidget(certSel, mRecpRowCount++, 1);
}
connect(certSel, &CertificateLineEdit::keyChanged,
this, &SignEncryptWidget::recipientsChanged);
connect(certSel, &CertificateLineEdit::wantsRemoval,
this, &SignEncryptWidget::recpRemovalRequested);
connect(certSel, &CertificateLineEdit::editingStarted,
this, static_cast<void (SignEncryptWidget::*)()>(&SignEncryptWidget::addRecipient));
connect(certSel, &CertificateLineEdit::addRequested,
this, static_cast<void (SignEncryptWidget::*)(const Key&)>(&SignEncryptWidget::addRecipient));
if (!key.isNull()) {
certSel->setKey(key);
}
}
void SignEncryptWidget::recipientsChanged()
{
bool oneEmpty = false;
Q_FOREACH (const CertificateLineEdit *w, mRecpWidgets) {
if (w->key().isNull()) {
oneEmpty = true;
break;
}
}
if (!oneEmpty) {
addRecipient();
}
updateOp();
}
Key SignEncryptWidget::signKey() const
{
if (mSigSelect->isEnabled()) {
return mSigSelect->currentKey();
}
return Key();
}
Key SignEncryptWidget::selfKey() const
{
if (mSelfSelect->isEnabled()) {
return mSelfSelect->currentKey();
}
return Key();
}
QVector <Key> SignEncryptWidget::recipients() const
{
QVector<Key> ret;
Q_FOREACH (const CertificateLineEdit *w, mRecpWidgets) {
if (!w->isEnabled()) {
// If one is disabled, all are disabled.
break;
}
const Key k = w->key();
if (!k.isNull()) {
ret << k;
}
}
const Key k = selfKey();
if (!k.isNull()) {
ret << k;
}
return ret;
}
bool SignEncryptWidget::isDeVsAndValid() const
{
if (!signKey().isNull()
&& (!IS_DE_VS(signKey()) || keyValidity(signKey()) < GpgME::UserID::Validity::Full)) {
return false;
}
if (!selfKey().isNull()
&& (!IS_DE_VS(selfKey()) || keyValidity(selfKey()) < GpgME::UserID::Validity::Full)) {
return false;
}
for (const auto &key: recipients()) {
if (!IS_DE_VS(key) || keyValidity(key) < GpgME::UserID::Validity::Full) {
return false;
}
}
return true;
}
void SignEncryptWidget::updateOp()
{
const Key sigKey = signKey();
const QVector<Key> recp = recipients();
QString newOp;
if (!sigKey.isNull() && (!recp.isEmpty() || encryptSymmetric())) {
newOp = i18nc("@action", "Sign / Encrypt");
} else if (!recp.isEmpty() || encryptSymmetric()) {
newOp = i18nc("@action", "Encrypt");
} else if (!sigKey.isNull()) {
newOp = i18nc("@action", "Sign");
} else {
newOp = QString();
}
mOp = newOp;
Q_EMIT operationChanged(mOp);
Q_EMIT keysChanged();
}
QString SignEncryptWidget::currentOp() const
{
return mOp;
}
void SignEncryptWidget::recpRemovalRequested(CertificateLineEdit *w)
{
if (!w) {
return;
}
int emptyEdits = 0;
Q_FOREACH (const CertificateLineEdit *edit, mRecpWidgets) {
if (edit->isEmpty()) {
emptyEdits++;
}
if (emptyEdits > 1) {
int row, col, rspan, cspan;
mRecpLayout->getItemPosition(mRecpLayout->indexOf(w), &row, &col, &rspan, &cspan);
mRecpLayout->removeWidget(w);
mRecpWidgets.removeAll(w);
// The row count of the grid layout does not reflect the actual
// items so we keep our internal count.
mRecpRowCount--;
for (int i = row + 1; i <= mRecpRowCount; i++) {
// move widgets one up
auto item = mRecpLayout->itemAtPosition(i, 1);
if (!item) {
break;
}
mRecpLayout->removeItem(item);
mRecpLayout->addItem(item, i - 1, 1);
}
w->deleteLater();
return;
}
}
}
bool SignEncryptWidget::encryptSymmetric() const
{
return mSymmetric->isChecked();
}
void SignEncryptWidget::loadKeys()
{
KConfigGroup keys(KSharedConfig::openConfig(), "SignEncryptKeys");
auto cache = KeyCache::instance();
mSigSelect->setDefaultKey(keys.readEntry("SigningKey", QString()));
mSelfSelect->setDefaultKey(keys.readEntry("EncryptKey", QString()));
}
void SignEncryptWidget::saveOwnKeys() const
{
KConfigGroup keys(KSharedConfig::openConfig(), "SignEncryptKeys");
auto sigKey = mSigSelect->currentKey();
auto encKey = mSelfSelect->currentKey();
if (!sigKey.isNull()) {
keys.writeEntry("SigningKey", sigKey.primaryFingerprint());
}
if (!encKey.isNull()) {
keys.writeEntry("EncryptKey", encKey.primaryFingerprint());
}
}
+
+void SignEncryptWidget::setSigningChecked(bool value)
+{
+ mSigChk->setChecked(value);
+}
+
+void SignEncryptWidget::setEncryptionChecked(bool value)
+{
+ mEncSelfChk->setChecked(value);
+ mEncOtherChk->setChecked(value);
+}
diff --git a/src/crypto/gui/signencryptwidget.h b/src/crypto/gui/signencryptwidget.h
index 29f4f297c..ebb30ab43 100644
--- a/src/crypto/gui/signencryptwidget.h
+++ b/src/crypto/gui/signencryptwidget.h
@@ -1,111 +1,120 @@
/* crypto/gui/signencryptwidget.h
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 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.
*/
#ifndef CRYPTO_GUI_SIGNENCRYPTWIDGET_H
#define CRYPTO_GUI_SIGNENCRYPTWIDGET_H
#include <QWidget>
#include <QVector>
#include <gpgme++/key.h>
class QGridLayout;
class QCheckBox;
namespace Kleo
{
class CertificateLineEdit;
class KeySelectionCombo;
class AbstractKeyListModel;
class SignEncryptWidget: public QWidget
{
Q_OBJECT
public:
explicit SignEncryptWidget(QWidget *parent = nullptr);
/** Returns the list of recipients selected in the dialog
* or an empty list if encryption is disabled */
QVector <GpgME::Key> recipients() const;
/** Returns the selected signing key or a null key if signing
* is disabled. */
GpgME::Key signKey() const;
/** Returns the selected encrypt to self key or a null key if
* encrypt to self is disabled. */
GpgME::Key selfKey() const;
/** Returns the operation based on the current selection or
* a null string if nothing would happen. */
QString currentOp() const;
/** Whether or not symmetric encryption should also be used. */
bool encryptSymmetric() const;
/** Save the currently selected signing and encrypt to self keys. */
void saveOwnKeys() const;
/** Return whether or not all keys involved in the operation are
compliant with CO_DE_VS, and all keys are valid (i.e. all
userIDs have Validity >= Full). */
bool isDeVsAndValid() const;
+ /** Set wether or not signing group should be checked */
+ void setSigningChecked(bool value);
+
+ /** Set wether or not encryption group should be checked */
+ void setEncryptionChecked(bool value);
+
protected Q_SLOTS:
void updateOp();
void recipientsChanged();
void recpRemovalRequested(CertificateLineEdit *w);
void addRecipient();
void addRecipient(const GpgME::Key &key);
protected:
void loadKeys();
Q_SIGNALS:
/* Emitted when the certificate selection changed the operation
* with that selection. e.g. "Sign" or "Sign/Encrypt".
* If no crypto operation is selected this returns a null string. */
void operationChanged(const QString &op);
/* Emitted when the certificate selection might be changed. */
void keysChanged();
private:
KeySelectionCombo *mSigSelect,
*mSelfSelect;
QVector<CertificateLineEdit *> mRecpWidgets;
QGridLayout *mRecpLayout;
QString mOp;
AbstractKeyListModel *mModel;
- QCheckBox *mSymmetric;
+ QCheckBox *mSymmetric,
+ *mSigChk,
+ *mEncOtherChk,
+ *mEncSelfChk;
int mRecpRowCount;
};
} // namespace Kleo
#endif // CRYPTO_GUI_SIGNENCRYPTWIDGET_H
diff --git a/src/crypto/signencryptfilescontroller.cpp b/src/crypto/signencryptfilescontroller.cpp
index ccface905..b209f3fbd 100644
--- a/src/crypto/signencryptfilescontroller.cpp
+++ b/src/crypto/signencryptfilescontroller.cpp
@@ -1,733 +1,726 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/signencryptfilescontroller.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2007 Klarälvdalens Datakonsult AB
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 "signencryptfilescontroller.h"
#include "signencryptfilestask.h"
#include "certificateresolver.h"
#include "crypto/gui/signencryptfileswizard.h"
#include "crypto/taskcollection.h"
#include "fileoperationspreferences.h"
#include "utils/input.h"
#include "utils/output.h"
#include "utils/kleo_assert.h"
#include "utils/archivedefinition.h"
#include "utils/path-helper.h"
#include <Libkleo/Exception>
#include <Libkleo/Classify>
#include <kmime/kmime_header_parsing.h>
#include <KLocalizedString>
#include "kleopatra_debug.h"
#include <QPointer>
#include <QTimer>
#include <QFileInfo>
#include <QDir>
using namespace Kleo;
using namespace Kleo::Crypto;
using namespace GpgME;
using namespace KMime::Types;
class SignEncryptFilesController::Private
{
friend class ::Kleo::Crypto::SignEncryptFilesController;
SignEncryptFilesController *const q;
public:
explicit Private(SignEncryptFilesController *qq);
~Private();
private:
void slotWizardOperationPrepared();
void slotWizardCanceled();
private:
void ensureWizardCreated();
void ensureWizardVisible();
void updateWizardMode();
void cancelAllTasks();
void reportError(int err, const QString &details)
{
q->setLastError(err, details);
q->emitDoneOrError();
}
void schedule();
std::shared_ptr<SignEncryptFilesTask> takeRunnable(GpgME::Protocol proto);
static void assertValidOperation(unsigned int);
static QString titleForOperation(unsigned int op);
private:
std::vector< std::shared_ptr<SignEncryptFilesTask> > runnable, completed;
std::shared_ptr<SignEncryptFilesTask> cms, openpgp;
QPointer<SignEncryptFilesWizard> wizard;
QStringList files;
unsigned int operation;
Protocol protocol;
};
SignEncryptFilesController::Private::Private(SignEncryptFilesController *qq)
: q(qq),
runnable(),
cms(),
openpgp(),
wizard(),
files(),
operation(SignAllowed | EncryptAllowed | ArchiveAllowed),
protocol(UnknownProtocol)
{
}
SignEncryptFilesController::Private::~Private()
{
qCDebug(KLEOPATRA_LOG);
}
QString SignEncryptFilesController::Private::titleForOperation(unsigned int op)
{
const bool signDisallowed = (op & SignMask) == SignDisallowed;
const bool encryptDisallowed = (op & EncryptMask) == EncryptDisallowed;
const bool archiveSelected = (op & ArchiveMask) == ArchiveForced;
kleo_assert(!signDisallowed || !encryptDisallowed);
if (!signDisallowed && encryptDisallowed) {
if (archiveSelected) {
return i18n("Archive and Sign Files");
} else {
return i18n("Sign Files");
}
}
if (signDisallowed && !encryptDisallowed) {
if (archiveSelected) {
return i18n("Archive and Encrypt Files");
} else {
return i18n("Encrypt Files");
}
}
if (archiveSelected) {
return i18n("Archive and Sign/Encrypt Files");
} else {
return i18n("Sign/Encrypt Files");
}
}
SignEncryptFilesController::SignEncryptFilesController(QObject *p)
: Controller(p), d(new Private(this))
{
}
SignEncryptFilesController::SignEncryptFilesController(const std::shared_ptr<const ExecutionContext> &ctx, QObject *p)
: Controller(ctx, p), d(new Private(this))
{
}
SignEncryptFilesController::~SignEncryptFilesController()
{
qCDebug(KLEOPATRA_LOG);
if (d->wizard && !d->wizard->isVisible()) {
delete d->wizard;
}
//d->wizard->close(); ### ?
}
void SignEncryptFilesController::setProtocol(Protocol proto)
{
kleo_assert(d->protocol == UnknownProtocol ||
d->protocol == proto);
d->protocol = proto;
d->ensureWizardCreated();
}
Protocol SignEncryptFilesController::protocol() const
{
return d->protocol;
}
// static
void SignEncryptFilesController::Private::assertValidOperation(unsigned int op)
{
kleo_assert((op & SignMask) == SignDisallowed ||
(op & SignMask) == SignAllowed ||
(op & SignMask) == SignSelected);
kleo_assert((op & EncryptMask) == EncryptDisallowed ||
(op & EncryptMask) == EncryptAllowed ||
(op & EncryptMask) == EncryptSelected);
kleo_assert((op & ArchiveMask) == ArchiveDisallowed ||
(op & ArchiveMask) == ArchiveAllowed ||
(op & ArchiveMask) == ArchiveForced);
kleo_assert((op & ~(SignMask | EncryptMask | ArchiveMask)) == 0);
}
void SignEncryptFilesController::setOperationMode(unsigned int mode)
{
Private::assertValidOperation(mode);
d->operation = mode;
d->updateWizardMode();
}
void SignEncryptFilesController::Private::updateWizardMode()
{
if (!wizard) {
return;
}
wizard->setWindowTitle(titleForOperation(operation));
const unsigned int signOp = (operation & SignMask);
const unsigned int encrOp = (operation & EncryptMask);
const unsigned int archOp = (operation & ArchiveMask);
if (signOp == SignDisallowed) {
wizard->setSigningUserMutable(false);
wizard->setSigningPreset(false);
} else {
wizard->setSigningUserMutable(true);
- wizard->setSigningPreset(false);
-
- if (signOp == SignSelected) {
- wizard->setSigningPreset(true);
- }
+ wizard->setSigningPreset(signOp == SignSelected);
}
if (encrOp == EncryptDisallowed) {
wizard->setEncryptionPreset(false);
wizard->setEncryptionUserMutable(false);
} else {
wizard->setEncryptionUserMutable(true);
wizard->setEncryptionPreset(false);
-
- if (encrOp == EncryptSelected) {
- wizard->setEncryptionPreset(true);
- }
+ wizard->setEncryptionPreset(encrOp == EncryptSelected);
}
wizard->setArchiveForced(archOp == ArchiveForced);
wizard->setArchiveMutable(archOp == ArchiveAllowed);
}
unsigned int SignEncryptFilesController::operationMode() const
{
return d->operation;
}
static const char *extension(bool pgp, bool sign, bool encrypt, bool ascii, bool detached)
{
unsigned int cls = pgp ? Class::OpenPGP : Class::CMS;
if (encrypt) {
cls |= Class::CipherText;
} else if (sign) {
cls |= detached ? Class::DetachedSignature : Class::OpaqueSignature;
}
cls |= ascii ? Class::Ascii : Class::Binary;
const bool usePGPFileExt = FileOperationsPreferences().usePGPFileExt();
if (const char *const ext = outputFileExtension(cls, usePGPFileExt)) {
return ext;
} else {
return "out";
}
}
static std::shared_ptr<ArchiveDefinition> getDefaultAd()
{
std::vector<std::shared_ptr<ArchiveDefinition> > ads = ArchiveDefinition::getArchiveDefinitions();
Q_ASSERT(!ads.empty());
std::shared_ptr<ArchiveDefinition> ad = ads.front();
const FileOperationsPreferences prefs;
Q_FOREACH (const std::shared_ptr<ArchiveDefinition> toCheck, ads) {
if (toCheck->id() == prefs.archiveCommand()) {
ad = toCheck;
break;
}
}
return ad;
}
static QMap <int, QString> buildOutputNames(const QStringList &files, const bool archive)
{
QMap <int, QString> nameMap;
// Build the default names for the wizard.
QString baseNameCms;
QString baseNamePgp;
const QFileInfo firstFile(files.first());
if (archive) {
QString baseName;
baseName = QDir(heuristicBaseDirectory(files)).absoluteFilePath(files.size() > 1 ?
i18nc("base name of an archive file, e.g. archive.zip or archive.tar.gz", "archive") :
firstFile.baseName());
const auto ad = getDefaultAd();
baseNamePgp = baseName + QLatin1Char('.') + ad->extensions(GpgME::OpenPGP).first() + QLatin1Char('.');
baseNameCms = baseName + QLatin1Char('.') + ad->extensions(GpgME::CMS).first() + QLatin1Char('.');
} else {
baseNameCms = baseNamePgp = files.first() + QLatin1Char('.');
}
const FileOperationsPreferences prefs;
const bool ascii = prefs.addASCIIArmor();
nameMap.insert(SignEncryptFilesWizard::SignatureCMS, baseNameCms + extension(false, true, false, ascii, true));
nameMap.insert(SignEncryptFilesWizard::EncryptedCMS, baseNameCms + extension(false, false, true, ascii, false));
nameMap.insert(SignEncryptFilesWizard::CombinedPGP, baseNamePgp + extension(true, true, true, ascii, false));
nameMap.insert(SignEncryptFilesWizard::EncryptedPGP, baseNamePgp + extension(true, false, true, ascii, false));
nameMap.insert(SignEncryptFilesWizard::SignaturePGP, baseNamePgp + extension(true, true, false, ascii, true));
nameMap.insert(SignEncryptFilesWizard::Directory, heuristicBaseDirectory(files));
return nameMap;
}
static QMap <int, QString> buildOutputNamesForDir(const QString &file, const QMap <int, QString> orig)
{
QMap <int, QString> ret;
const QString dir = orig.value(SignEncryptFilesWizard::Directory);
if (dir.isEmpty()) {
return orig;
}
// Build the default names for the wizard.
const QFileInfo fi(file);
const QString baseName = dir + QLatin1Char('/') + fi.fileName() + QStringLiteral(".");
const FileOperationsPreferences prefs;
const bool ascii = prefs.addASCIIArmor();
ret.insert(SignEncryptFilesWizard::SignatureCMS, baseName + extension(false, true, false, ascii, true));
ret.insert(SignEncryptFilesWizard::EncryptedCMS, baseName + extension(false, false, true, ascii, false));
ret.insert(SignEncryptFilesWizard::CombinedPGP, baseName + extension(true, true, true, ascii, false));
ret.insert(SignEncryptFilesWizard::EncryptedPGP, baseName + extension(true, false, true, ascii, false));
ret.insert(SignEncryptFilesWizard::SignaturePGP, baseName + extension(true, true, false, ascii, true));
return ret;
}
void SignEncryptFilesController::setFiles(const QStringList &files)
{
kleo_assert(!files.empty());
d->files = files;
bool archive = false;
if (files.size() > 1) {
setOperationMode((operationMode() & ~ArchiveMask) | ArchiveAllowed);
archive = true;
}
for (const auto &file: files) {
if (QFileInfo(file).isDir()) {
setOperationMode((operationMode() & ~ArchiveMask) | ArchiveForced);
archive = true;
break;
}
}
d->ensureWizardCreated();
d->wizard->setOutputNames(buildOutputNames(files, archive));
}
void SignEncryptFilesController::Private::slotWizardCanceled()
{
qCDebug(KLEOPATRA_LOG);
reportError(gpg_error(GPG_ERR_CANCELED), i18n("User cancel"));
}
void SignEncryptFilesController::start()
{
d->ensureWizardVisible();
}
static std::shared_ptr<SignEncryptFilesTask>
createSignEncryptTaskForFileInfo(const QFileInfo &fi, bool ascii,
const std::vector<Key> &recipients, const std::vector<Key> &signers,
const QString &outputName, bool symmetric)
{
const std::shared_ptr<SignEncryptFilesTask> task(new SignEncryptFilesTask);
Q_ASSERT(!signers.empty() || !recipients.empty() || symmetric);
task->setAsciiArmor(ascii);
if (!signers.empty()) {
task->setSign(true);
task->setSigners(signers);
task->setDetachedSignature(true);
} else {
task->setSign(false);
}
if (!recipients.empty()) {
task->setEncrypt(true);
task->setRecipients(recipients);
task->setDetachedSignature(false);
} else {
task->setEncrypt(false);
}
task->setEncryptSymmetric(symmetric);
const QString input = fi.absoluteFilePath();
task->setInputFileName(input);
task->setInput(Input::createFromFile(input));
task->setOutputFileName(outputName);
return task;
}
static std::shared_ptr<SignEncryptFilesTask>
createArchiveSignEncryptTaskForFiles(const QStringList &files,
const std::shared_ptr<ArchiveDefinition> &ad, bool pgp, bool ascii,
const std::vector<Key> &recipients, const std::vector<Key> &signers,
const QString& outputName, bool symmetric)
{
const std::shared_ptr<SignEncryptFilesTask> task(new SignEncryptFilesTask);
task->setEncryptSymmetric(symmetric);
Q_ASSERT(!signers.empty() || !recipients.empty() || symmetric);
task->setAsciiArmor(ascii);
if (!signers.empty()) {
task->setSign(true);
task->setSigners(signers);
task->setDetachedSignature(false);
} else {
task->setSign(false);
}
if (!recipients.empty()) {
task->setEncrypt(true);
task->setRecipients(recipients);
} else {
task->setEncrypt(false);
}
kleo_assert(ad);
const Protocol proto = pgp ? OpenPGP : CMS;
task->setInputFileNames(files);
task->setInput(ad->createInputFromPackCommand(proto, files));
task->setOutputFileName(outputName);
return task;
}
static std::vector< std::shared_ptr<SignEncryptFilesTask> >
createSignEncryptTasksForFileInfo(const QFileInfo &fi, bool ascii, const std::vector<Key> &pgpRecipients, const std::vector<Key> &pgpSigners,
const std::vector<Key> &cmsRecipients, const std::vector<Key> &cmsSigners, const QMap<int, QString> outputNames,
bool symmetric)
{
std::vector< std::shared_ptr<SignEncryptFilesTask> > result;
const bool pgp = !pgpSigners.empty() || !pgpRecipients.empty();
const bool cms = !cmsSigners.empty() || !cmsRecipients.empty();
result.reserve(pgp + cms);
if (pgp || symmetric) {
// Symmetric encryption is only supported for PGP
int outKind = 0;
if ((!pgpRecipients.empty() || symmetric)&& !pgpSigners.empty()) {
outKind = SignEncryptFilesWizard::CombinedPGP;
} else if (!pgpRecipients.empty() || symmetric) {
outKind = SignEncryptFilesWizard::EncryptedPGP;
} else {
outKind = SignEncryptFilesWizard::SignaturePGP;
}
result.push_back(createSignEncryptTaskForFileInfo(fi, ascii, pgpRecipients, pgpSigners, outputNames[outKind], symmetric));
}
if (cms) {
// There is no combined sign / encrypt in gpgsm so we create one sign task
// and one encrypt task. Which leaves us with the age old dilemma, encrypt
// then sign, or sign then encrypt. Ugly.
if (!cmsSigners.empty()) {
result.push_back(createSignEncryptTaskForFileInfo(fi, ascii, std::vector<Key>(),
cmsSigners, outputNames[SignEncryptFilesWizard::SignatureCMS],
false));
}
if (!cmsRecipients.empty()) {
result.push_back(createSignEncryptTaskForFileInfo(fi, ascii, cmsRecipients,
std::vector<Key>(), outputNames[SignEncryptFilesWizard::EncryptedCMS],
false));
}
}
return result;
}
static std::vector< std::shared_ptr<SignEncryptFilesTask> >
createArchiveSignEncryptTasksForFiles(const QStringList &files, const std::shared_ptr<ArchiveDefinition> &ad,
bool ascii, const std::vector<Key> &pgpRecipients,
const std::vector<Key> &pgpSigners, const std::vector<Key> &cmsRecipients, const std::vector<Key> &cmsSigners,
const QMap<int, QString> outputNames, bool symmetric)
{
std::vector< std::shared_ptr<SignEncryptFilesTask> > result;
const bool pgp = !pgpSigners.empty() || !pgpRecipients.empty();
const bool cms = !cmsSigners.empty() || !cmsRecipients.empty();
result.reserve(pgp + cms);
if (pgp || symmetric) {
int outKind = 0;
if ((!pgpRecipients.empty() || symmetric) && !pgpSigners.empty()) {
outKind = SignEncryptFilesWizard::CombinedPGP;
} else if (!pgpRecipients.empty() || symmetric) {
outKind = SignEncryptFilesWizard::EncryptedPGP;
} else {
outKind = SignEncryptFilesWizard::SignaturePGP;
}
result.push_back(createArchiveSignEncryptTaskForFiles(files, ad, true, ascii, pgpRecipients, pgpSigners, outputNames[outKind], symmetric));
}
if (cms) {
if (!cmsSigners.empty()) {
result.push_back(createArchiveSignEncryptTaskForFiles(files, ad, false, ascii,
std::vector<Key>(), cmsSigners, outputNames[SignEncryptFilesWizard::SignatureCMS],
false));
}
if (!cmsRecipients.empty()) {
result.push_back(createArchiveSignEncryptTaskForFiles(files, ad, false, ascii,
cmsRecipients, std::vector<Key>(), outputNames[SignEncryptFilesWizard::EncryptedCMS],
false));
}
}
return result;
}
void SignEncryptFilesController::Private::slotWizardOperationPrepared()
{
try {
kleo_assert(wizard);
kleo_assert(!files.empty());
const bool archive = (wizard->outputNames().value(SignEncryptFilesWizard::Directory).isNull() && files.size() > 1) ||
((operation & ArchiveMask) == ArchiveForced);
const QVector<Key> recipients = wizard->resolvedRecipients();
const QVector<Key> signers = wizard->resolvedSigners();
const FileOperationsPreferences prefs;
const bool ascii = prefs.addASCIIArmor();
QVector<Key> pgpRecipients, cmsRecipients, pgpSigners, cmsSigners;
Q_FOREACH (const Key k, recipients) {
if (k.protocol() == GpgME::OpenPGP) {
pgpRecipients << k;
} else {
cmsRecipients << k;
}
}
Q_FOREACH (Key k, signers) {
if (k.protocol() == GpgME::OpenPGP) {
pgpSigners << k;
} else {
cmsSigners << k;
}
}
std::vector< std::shared_ptr<SignEncryptFilesTask> > tasks;
if (!archive) {
tasks.reserve(files.size());
}
if (archive) {
tasks = createArchiveSignEncryptTasksForFiles(files,
getDefaultAd(),
ascii,
pgpRecipients.toStdVector(),
pgpSigners.toStdVector(),
cmsRecipients.toStdVector(),
cmsSigners.toStdVector(),
wizard->outputNames(),
wizard->encryptSymmetric());
} else {
Q_FOREACH (const QString &file, files) {
const std::vector< std::shared_ptr<SignEncryptFilesTask> > created =
createSignEncryptTasksForFileInfo(QFileInfo(file), ascii,
pgpRecipients.toStdVector(),
pgpSigners.toStdVector(),
cmsRecipients.toStdVector(),
cmsSigners.toStdVector(),
buildOutputNamesForDir(file, wizard->outputNames()),
wizard->encryptSymmetric());
tasks.insert(tasks.end(), created.begin(), created.end());
}
}
const std::shared_ptr<OverwritePolicy> overwritePolicy(new OverwritePolicy(wizard));
Q_FOREACH (const std::shared_ptr<SignEncryptFilesTask> &i, tasks) {
i->setOverwritePolicy(overwritePolicy);
}
kleo_assert(runnable.empty());
runnable.swap(tasks);
Q_FOREACH (const std::shared_ptr<Task> &task, runnable) {
q->connectTask(task);
}
std::shared_ptr<TaskCollection> coll(new TaskCollection);
std::vector<std::shared_ptr<Task> > tmp;
std::copy(runnable.begin(), runnable.end(), std::back_inserter(tmp));
coll->setTasks(tmp);
wizard->setTaskCollection(coll);
QTimer::singleShot(0, q, SLOT(schedule()));
} catch (const Kleo::Exception &e) {
reportError(e.error().encodedError(), e.message());
} catch (const std::exception &e) {
reportError(gpg_error(GPG_ERR_UNEXPECTED),
i18n("Caught unexpected exception in SignEncryptFilesController::Private::slotWizardOperationPrepared: %1",
QString::fromLocal8Bit(e.what())));
} catch (...) {
reportError(gpg_error(GPG_ERR_UNEXPECTED),
i18n("Caught unknown exception in SignEncryptFilesController::Private::slotWizardOperationPrepared"));
}
}
void SignEncryptFilesController::Private::schedule()
{
if (!cms)
if (const std::shared_ptr<SignEncryptFilesTask> t = takeRunnable(CMS)) {
t->start();
cms = t;
}
if (!openpgp)
if (const std::shared_ptr<SignEncryptFilesTask> t = takeRunnable(OpenPGP)) {
t->start();
openpgp = t;
}
if (!cms && !openpgp) {
kleo_assert(runnable.empty());
q->emitDoneOrError();
}
}
std::shared_ptr<SignEncryptFilesTask> SignEncryptFilesController::Private::takeRunnable(GpgME::Protocol proto)
{
const auto it = std::find_if(runnable.begin(), runnable.end(),
[proto](const std::shared_ptr<Task> &task) { return task->protocol() == proto; });
if (it == runnable.end()) {
return std::shared_ptr<SignEncryptFilesTask>();
}
const std::shared_ptr<SignEncryptFilesTask> result = *it;
runnable.erase(it);
return result;
}
void SignEncryptFilesController::doTaskDone(const Task *task, const std::shared_ptr<const Task::Result> &result)
{
Q_UNUSED(result)
Q_ASSERT(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
if (task == d->cms.get()) {
d->completed.push_back(d->cms);
d->cms.reset();
} else if (task == d->openpgp.get()) {
d->completed.push_back(d->openpgp);
d->openpgp.reset();
}
QTimer::singleShot(0, this, SLOT(schedule()));
}
void SignEncryptFilesController::cancel()
{
qCDebug(KLEOPATRA_LOG);
try {
if (d->wizard) {
d->wizard->close();
}
d->cancelAllTasks();
} catch (const std::exception &e) {
qCDebug(KLEOPATRA_LOG) << "Caught exception: " << e.what();
}
}
void SignEncryptFilesController::Private::cancelAllTasks()
{
// we just kill all runnable tasks - this will not result in
// signal emissions.
runnable.clear();
// a cancel() will result in a call to
if (cms) {
cms->cancel();
}
if (openpgp) {
openpgp->cancel();
}
}
void SignEncryptFilesController::Private::ensureWizardCreated()
{
if (wizard) {
return;
}
std::unique_ptr<SignEncryptFilesWizard> w(new SignEncryptFilesWizard);
w->setAttribute(Qt::WA_DeleteOnClose);
connect(w.get(), SIGNAL(operationPrepared()), q, SLOT(slotWizardOperationPrepared()), Qt::QueuedConnection);
connect(w.get(), SIGNAL(rejected()), q, SLOT(slotWizardCanceled()), Qt::QueuedConnection);
wizard = w.release();
updateWizardMode();
}
void SignEncryptFilesController::Private::ensureWizardVisible()
{
ensureWizardCreated();
q->bringToForeground(wizard);
}
#include "moc_signencryptfilescontroller.cpp"

File Metadata

Mime Type
text/x-diff
Expires
Wed, Jan 14, 12:48 AM (2 h, 54 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
d0/ad/9dcbef6409c63646c7448c8d47ec

Event Timeline