Commit 7e19bcc3 authored by Andre Heinecke's avatar Andre Heinecke
Browse files

Add support for output file name changing

The Output filenames are also used to indicate the status of
an operation. E.g. if you select CMS and OpenPGP Certificates
together it will make it visibile that this will cause two
files to be created.

In case no operation is requested the Output group was
otherwise empty.
parent 60e9f5d2
......@@ -42,8 +42,13 @@
#include <KMessageBox>
#include "kleopatra_debug.h"
#include <Libkleo/FileNameRequester>
#include <QVBoxLayout>
#include <QWizardPage>
#include <QGroupBox>
#include <QLabel>
#include <QIcon>
#include <QPointer>
......@@ -84,18 +89,31 @@ FIXME: Either show this warning or fix detached signatures for archives.
class SigEncPage: public QWizardPage
{
Q_OBJECT
public:
explicit SigEncPage(QWidget *parent = Q_NULLPTR)
: QWizardPage(parent),
mWidget(new SignEncryptWidget)
mWidget(new SignEncryptWidget),
mOutLayout(new QVBoxLayout)
{
setTitle(i18nc("@title", "Sign / Encrypt Files"));
QVBoxLayout *vLay = new QVBoxLayout(this);
auto vLay = new QVBoxLayout(this);
vLay->addWidget(mWidget);
connect(mWidget, &SignEncryptWidget::operationChanged, this,
&SigEncPage::updateCommitButton);
connect(mWidget, &SignEncryptWidget::keysChanged, this,
&SigEncPage::updateFileWidgets);
setLayout(vLay);
updateCommitButton(mWidget->currentOp());
auto outputGrp = new QGroupBox(i18n("Output"));
outputGrp->setLayout(mOutLayout);
mPlaceholderWidget = new QLabel(i18n("Please select an action."));
mOutLayout->addWidget(mPlaceholderWidget);
vLay->addWidget(outputGrp);
setMinimumHeight(480);
}
bool isComplete() const Q_DECL_OVERRIDE
......@@ -108,11 +126,13 @@ public:
return ResultPageId;
}
void initializePage() Q_DECL_OVERRIDE {
void initializePage() Q_DECL_OVERRIDE
{
setCommitPage(true);
}
bool validatePage() Q_DECL_OVERRIDE {
bool validatePage() Q_DECL_OVERRIDE
{
if (!mWidget->selfKey().isNull()) {
return true;
}
......@@ -158,6 +178,57 @@ public:
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") }
};
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.") }
};
FileNameRequester *req = new FileNameRequester(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) {
assert(mOutNames.isEmpty());
mOutNames = names;
Q_FOREACH (int i, mOutNames.keys()) {
mRequester[i] = createRequester(i, mOutLayout);
}
updateFileWidgets();
}
QMap <int, QString> outputNames() const {
return mOutNames;
}
private Q_SLOTS:
void updateCommitButton(const QString &label)
{
......@@ -169,8 +240,42 @@ private Q_SLOTS:
Q_EMIT completeChanged();
}
void updateFileWidgets()
{
if (mRequester.isEmpty()) {
return;
}
const QVector<Key> recipients = mWidget->recipients();
const Key sigKey = mWidget->signKey();
bool pgp = false;
bool cms = false;
Q_FOREACH (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);
mRequester[SignEncryptFilesWizard::SignatureCMS]->setVisible(sigKey.protocol() == Protocol::CMS);
mRequester[SignEncryptFilesWizard::EncryptedCMS]->setVisible(cms);
mRequester[SignEncryptFilesWizard::CombinedPGP]->setVisible(sigKey.protocol() == Protocol::OpenPGP && pgp);
mRequester[SignEncryptFilesWizard::EncryptedPGP]->setVisible(pgp && sigKey.protocol() != Protocol::OpenPGP);
mRequester[SignEncryptFilesWizard::SignaturePGP]->setVisible(sigKey.protocol() == Protocol::OpenPGP && !pgp);
mOutLayout->setEnabled(true);
}
private:
SignEncryptWidget *mWidget;
QMap <int, QString> mOutNames;
QMap <int, QWidget *> mRequester;
QVBoxLayout *mOutLayout;
QWidget *mPlaceholderWidget;
};
class ResultPage : public NewResultPage
......@@ -261,4 +366,14 @@ void SignEncryptFilesWizard::setTaskCollection(const boost::shared_ptr<Kleo::Cry
mResultPage->setTaskCollection(coll);
}
void SignEncryptFilesWizard::setOutputNames(const QMap<int, QString> &map) const
{
mSigEncPage->setOutputNames(map);
}
QMap<int, QString> SignEncryptFilesWizard::outputNames() const
{
return mSigEncPage->outputNames();
}
#include "signencryptfileswizard.moc"
......@@ -40,6 +40,7 @@
#include <QWizard>
#include <QVector>
#include <QMap>
#include <boost/shared_ptr.hpp>
......@@ -69,6 +70,14 @@ class SignEncryptFilesWizard : public QWizard
{
Q_OBJECT
public:
enum KindNames{
SignatureCMS,
CombinedPGP,
EncryptedPGP,
EncryptedCMS,
SignaturePGP
};
explicit SignEncryptFilesWizard(QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = 0);
~SignEncryptFilesWizard();
......@@ -79,6 +88,9 @@ public:
void setEncryptionPreset(bool preset);
void setEncryptionUserMutable(bool mut);
void setOutputNames(const QMap<int, QString> &nameMap) const;
QMap<int, QString> outputNames() const;
void setTaskCollection(const boost::shared_ptr<Kleo::Crypto::TaskCollection> &coll);
// Outputs
......
......@@ -127,7 +127,6 @@ void SignEncryptWidget::addRecipient()
true);
mRecpWidgets << certSel;
mRecpLayout->insertWidget(mRecpLayout->count() - 1, certSel);
qCDebug(KLEOPATRA_LOG) << "Adding recipient widget.";
connect(certSel, &CertificateSelectionWidget::keyChanged,
this, &SignEncryptWidget::recipientsChanged);
}
......@@ -144,6 +143,7 @@ void SignEncryptWidget::recipientsChanged()
if (!oneEmpty) {
addRecipient();
}
updateOp();
}
Key SignEncryptWidget::signKey() const
......@@ -186,6 +186,7 @@ void SignEncryptWidget::updateOp()
{
const Key sigKey = signKey();
const QVector<Key> recp = recipients();
QString newOp;
if (!sigKey.isNull() && !recp.isEmpty()) {
newOp = i18nc("@action", "Sign / Encrypt");
......@@ -200,6 +201,7 @@ void SignEncryptWidget::updateOp()
mOp = newOp;
Q_EMIT operationChanged(mOp);
}
Q_EMIT keysChanged();
}
QString SignEncryptWidget::currentOp() const
......
......@@ -33,6 +33,7 @@
#include <QWidget>
#include <QVector>
#include <QMap>
#include <gpgme++/key.h>
class QVBoxLayout;
......@@ -76,6 +77,9 @@ Q_SIGNALS:
* 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:
CertificateSelectionWidget *mSigSelect,
*mSelfSelect;
......
......@@ -37,14 +37,15 @@
#include "signencryptfilestask.h"
#include "certificateresolver.h"
#include <crypto/gui/signencryptfileswizard.h>
#include <crypto/taskcollection.h>
#include "crypto/gui/signencryptfileswizard.h"
#include "crypto/taskcollection.h"
#include <utils/input.h>
#include <utils/output.h>
#include <utils/classify.h>
#include <utils/kleo_assert.h>
#include <utils/archivedefinition.h>
#include "utils/input.h"
#include "utils/output.h"
#include "utils/classify.h"
#include "utils/kleo_assert.h"
#include "utils/archivedefinition.h"
#include "utils/path-helper.h"
#include <Libkleo/Stl_Util>
#include <Libkleo/Exception>
......@@ -57,6 +58,7 @@
#include <QPointer>
#include <QTimer>
#include <QFileInfo>
#include <QDir>
#include <boost/bind.hpp>
......@@ -267,6 +269,47 @@ 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;
if (const char *const ext = outputFileExtension(cls)) {
return ext;
} else {
return "out";
}
}
static QMap <int, QString> buildOutputNames(const QStringList &files)
{
QMap <int, QString> nameMap;
// Build the default names for the wizard.
QString baseName;
if (files.size() > 1) {
baseName = QDir(heuristicBaseDirectory(files)).absoluteFilePath(
i18nc("base name of an archive file, e.g. archive.zip or archive.tar.gz", "archive"));
std::vector<boost::shared_ptr<ArchiveDefinition> > ads = ArchiveDefinition::getArchiveDefinitions();
assert(!ads.empty());
// TODO read from config
boost::shared_ptr<ArchiveDefinition> ad = ads.front();
baseName += QStringLiteral(".") + ad->extensions(GpgME::CMS).first();
} else {
baseName = files.first() + QStringLiteral(".");
}
nameMap.insert(SignEncryptFilesWizard::SignatureCMS, baseName + extension(false, true, false, false, true));
nameMap.insert(SignEncryptFilesWizard::EncryptedCMS, baseName + extension(false, false, true, false, false));
nameMap.insert(SignEncryptFilesWizard::CombinedPGP, baseName + extension(true, true, true, false, false));
nameMap.insert(SignEncryptFilesWizard::EncryptedPGP, baseName + extension(true, false, true, false, false));
nameMap.insert(SignEncryptFilesWizard::SignaturePGP, baseName + extension(true, true, false, false, true));
return nameMap;
}
void SignEncryptFilesController::setFiles(const QStringList &files)
{
kleo_assert(!files.empty());
......@@ -275,6 +318,7 @@ void SignEncryptFilesController::setFiles(const QStringList &files)
setOperationMode((operationMode() & ~ArchiveMask) | ArchiveForced);
}
d->ensureWizardCreated();
d->wizard->setOutputNames(buildOutputNames(files));
}
void SignEncryptFilesController::Private::slotWizardCanceled()
......@@ -288,22 +332,6 @@ void SignEncryptFilesController::start()
d->ensureWizardVisible();
}
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;
if (const char *const ext = outputFileExtension(cls)) {
return ext;
} else {
return "out";
}
}
static shared_ptr<SignEncryptFilesTask>
createSignEncryptTaskForFileInfo(const QFileInfo &fi, bool pgp, bool ascii, const std::vector<Key> &recipients, const std::vector<Key> &signers)
{
......@@ -313,10 +341,14 @@ createSignEncryptTaskForFileInfo(const QFileInfo &fi, bool pgp, bool ascii, cons
task->setSign(true);
task->setSigners(signers);
task->setDetachedSignature(true);
} else {
task->setSign(false);
}
if (!recipients.empty()) {
task->setEncrypt(true);
task->setRecipients(recipients);
} else {
task->setSign(false);
}
const QString input = fi.absoluteFilePath();
......@@ -333,18 +365,22 @@ createSignEncryptTaskForFileInfo(const QFileInfo &fi, bool pgp, bool ascii, cons
}
static shared_ptr<SignEncryptFilesTask>
createArchiveSignEncryptTaskForFiles(const QStringList &files, const QString &outputFileBaseName, const shared_ptr<ArchiveDefinition> &ad, bool pgp, bool sign, bool encrypt, bool ascii, const std::vector<Key> &recipients, const std::vector<Key> &signers)
createArchiveSignEncryptTaskForFiles(const QStringList &files, const QString &outputName, const shared_ptr<ArchiveDefinition> &ad, bool pgp, bool ascii, const std::vector<Key> &recipients, const std::vector<Key> &signers)
{
const shared_ptr<SignEncryptFilesTask> task(new SignEncryptFilesTask);
task->setSign(sign);
task->setEncrypt(encrypt);
task->setAsciiArmor(ascii);
if (sign) {
if (!signers.empty()) {
task->setSign(true);
task->setSigners(signers);
task->setDetachedSignature(false);
} else {
task->setSign(false);
}
if (encrypt) {
if (!recipients.empty()) {
task->setEncrypt(true);
task->setRecipients(recipients);
} else {
task->setEncrypt(false);
}
kleo_assert(ad);
......@@ -354,17 +390,13 @@ createArchiveSignEncryptTaskForFiles(const QStringList &files, const QString &ou
task->setInputFileNames(files);
task->setInput(ad->createInputFromPackCommand(proto, files));
const char *const ext = extension(pgp, sign, encrypt, ascii, false);
kleo_assert(ext);
kleo_assert(!ad->extensions(proto).empty());
task->setOutputFileName(outputFileBaseName + QLatin1Char('.') + QLatin1String(ext));
task->setOutputFileName(outputName);
return task;
}
static std::vector< 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)
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> outNames)
{
std::vector< shared_ptr<SignEncryptFilesTask> > result;
......@@ -385,25 +417,21 @@ createSignEncryptTasksForFileInfo(const QFileInfo &fi, bool ascii, const std::ve
}
static std::vector< shared_ptr<SignEncryptFilesTask> >
createArchiveSignEncryptTasksForFiles(const QStringList &files, const QString &pgpOutputFileBaseName, const QString &cmsOutputFileBaseName, const shared_ptr<ArchiveDefinition> &ad, bool sign, bool encrypt, bool ascii, const std::vector<Key> &pgpRecipients, const std::vector<Key> &pgpSigners, const std::vector<Key> &cmsRecipients, const std::vector<Key> &cmsSigners)
createArchiveSignEncryptTasksForFiles(const QStringList &files, const QString &pgpOutputFileName, const QString &cmsOutputFileName, const shared_ptr<ArchiveDefinition> &ad, bool sign, bool encrypt, bool ascii, const std::vector<Key> &pgpRecipients, const std::vector<Key> &pgpSigners, const std::vector<Key> &cmsRecipients, const std::vector<Key> &cmsSigners)
{
std::vector< shared_ptr<SignEncryptFilesTask> > result;
const bool shallPgpSign = sign && !pgpSigners.empty();
const bool shallPgpEncrypt = encrypt && !pgpRecipients.empty();
const bool pgp = (shallPgpEncrypt && (!sign || shallPgpSign)) || (!encrypt && shallPgpSign);
const bool pgp = !pgpSigners.empty() || !pgpRecipients.empty();
const bool shallCmsSign = sign && !cmsSigners.empty();
const bool shallCmsEncrypt = encrypt && !cmsRecipients.empty();
const bool cms = (shallCmsEncrypt && (!sign || shallCmsSign)) || (!encrypt && shallCmsSign);
const bool cms = !cmsSigners.empty() || !cmsRecipients.empty();
result.reserve(pgp + cms);
if (pgp) {
result.push_back(createArchiveSignEncryptTaskForFiles(files, pgpOutputFileBaseName, ad, true, sign, encrypt, ascii, pgpRecipients, pgpSigners));
result.push_back(createArchiveSignEncryptTaskForFiles(files, pgpOutputFileName, ad, true, ascii, pgpRecipients, pgpSigners));
}
if (cms) {
result.push_back(createArchiveSignEncryptTaskForFiles(files, cmsOutputFileBaseName, ad, false, sign, encrypt, ascii, cmsRecipients, cmsSigners));
result.push_back(createArchiveSignEncryptTaskForFiles(files, cmsOutputFileName, ad, false, ascii, cmsRecipients, cmsSigners));
}
return result;
......@@ -462,7 +490,8 @@ void SignEncryptFilesController::Private::slotWizardOperationPrepared()
pgpRecipients.toStdVector(),
pgpSigners.toStdVector(),
cmsRecipients.toStdVector(),
cmsSigners.toStdVector());
cmsSigners.toStdVector(),
wizard->outputNames());
tasks.insert(tasks.end(), created.begin(), created.end());
}
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment