From e608315392cc5b7ddf51e16dce5fe7e99b83f011 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20Kl=C3=B6cker?= Date: Mon, 19 Jun 2023 17:52:30 +0200 Subject: [PATCH] qt: Support writing signed/encrypted archives directly to a file * lang/qt/src/encryptarchivejob.cpp, lang/qt/src/encryptarchivejob.h (EncryptArchiveJob): Add member functions setRecipients, recipients, setInputPaths, inputPaths, setOutputFile, outputFile, setEncryptionFlags, encryptionFlags. * lang/qt/src/encryptarchivejob_p.h (EncryptArchiveJobPrivate): Add members m_recipients, m_inputPaths, m_outputFilePath, m_encryptionFlags. * lang/qt/src/qgpgmeencryptarchivejob.cpp (encrypt): Move creation of outdata to encrypt_to_io_device. (encrypt_to_io_device, encrypt_to_filename): New. (QGpgMEEncryptArchiveJob::start): Use encrypt_to_io_device instead of encrypt. (QGpgMEEncryptArchiveJobPrivate::startIt): Start the job with the values from member variables. * lang/qt/src/qgpgmesignarchivejob.cpp (sign): Move creation of outdata to sign_to_io_device. (sign_to_io_device, sign_to_filename): New. (QGpgMESignArchiveJob::start): Use sign_to_io_device instead of sign. (QGpgMESignArchiveJobPrivate::startIt): Start the job with the values from member variables. * lang/qt/src/qgpgmesignencryptarchivejob.cpp (sign_encrypt): Move creation of outdata to sign_encrypt_to_io_device. (sign_encrypt_to_io_device, sign_encrypt_to_filename): New. (QGpgMESignEncryptArchiveJob::start): Use sign_encrypt_to_io_device instead of sign_encrypt. (QGpgMESignEncryptArchiveJobPrivate::startIt): Start the job with the values from member variables. * lang/qt/src/signarchivejob.cpp, lang/qt/src/signarchivejob.h (SignArchiveJob): Add member functions setSigner, signers, setInputPaths, inputPaths, setOutputFile, outputFile. * lang/qt/src/signarchivejob_p.h (SignArchiveJobPrivate): Add members m_signers, m_inputPaths, m_outputFilePath. * lang/qt/src/signencryptarchivejob.cpp, lang/qt/src/signencryptarchivejob.h (SignEncryptArchiveJob): Add member functions setSigner, signers, setRecipients, recipients, setInputPaths, inputPaths, setOutputFile, outputFile, setEncryptionFlags, encryptionFlags. * lang/qt/src/signencryptarchivejob_p.h (SignEncryptArchiveJobPrivate): Add members m_signers, m_recipients, m_inputPaths, m_outputFilePath, m_encryptionFlags. * lang/qt/tests/run-encryptarchivejob.cpp (createOutput): Remove. (checkOutputFilePath): New. (main): Create file output writing to stdout if no archive name (or "-") is given. Exit if file with given archive name already exists. Make the jobs write the created archive directly to the given archive name. * lang/qt/tests/run-signarchivejob.cpp (createOutput): Remove. (checkOutputFilePath): New. (main): Create file output writing to stdout if no archive name (or "-") is given. Exit if file with given archive name already exists. Make the jobs write the created archive directly to the given archive name. -- This makes it possible to tell gpgtar to write the created archive directly to a specified file bypassing GpgME's Data IO. GnuPG-bug-id: 6530 --- NEWS | 43 +++++++++++-- lang/qt/src/encryptarchivejob.cpp | 48 ++++++++++++++ lang/qt/src/encryptarchivejob.h | 47 ++++++++++++++ lang/qt/src/encryptarchivejob_p.h | 4 ++ lang/qt/src/qgpgmeencryptarchivejob.cpp | 61 +++++++++++++----- lang/qt/src/qgpgmesignarchivejob.cpp | 60 +++++++++++++----- lang/qt/src/qgpgmesignencryptarchivejob.cpp | 70 ++++++++++++++------- lang/qt/src/signarchivejob.cpp | 36 +++++++++++ lang/qt/src/signarchivejob.h | 38 +++++++++++ lang/qt/src/signarchivejob_p.h | 3 + lang/qt/src/signencryptarchivejob.cpp | 60 ++++++++++++++++++ lang/qt/src/signencryptarchivejob.h | 55 ++++++++++++++++ lang/qt/src/signencryptarchivejob_p.h | 5 ++ lang/qt/tests/run-encryptarchivejob.cpp | 54 ++++++++++------ lang/qt/tests/run-signarchivejob.cpp | 45 +++++++------ 15 files changed, 535 insertions(+), 94 deletions(-) diff --git a/NEWS b/NEWS index f61b354b..ce72d610 100644 --- a/NEWS +++ b/NEWS @@ -1,18 +1,49 @@ Noteworthy changes in version 1.21.0 (unreleased) ------------------------------------------------- - * Qt Jobs working with QIODeviceDataProvider now properly - handle input-size hints and progress for files larger. - 2^32 bytes in 32 bit builds. [T6534] + * Extended gpgme_op_encrypt*, gpgme_op_encrypt_sign*, and + gpgme_op_sign* to allow writing the output directly to a + file. [T6530] - * Error::isCanceled now also returns true for error code + * qt: Allow writing the created archives directly to a + file. [T6530] + + * qt: Qt Jobs working with QIODeviceDataProvider now properly + handle input-size hints and progress for files larger. + 2^32 bytes in 32 bit builds. [T6534] + + * cpp: Error::isCanceled now also returns true for error code GPG_ERR_FULLY_CANCELED. [T6510] -* Interface changes relative to the 1.20.0 release: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Interface changes relative to the 1.20.0 release: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ cpp: Data::setFlag NEW. cpp: Data::setSizeHint NEW. qt: Job::startIt NEW. + qt: EncryptArchiveJob::setRecipients NEW. + qt: EncryptArchiveJob::recipients NEW. + qt: EncryptArchiveJob::setInputPaths NEW. + qt: EncryptArchiveJob::inputPaths NEW. + qt: EncryptArchiveJob::setOutputFile NEW. + qt: EncryptArchiveJob::outputFile NEW. + qt: EncryptArchiveJob::setEncryptionFlags NEW. + qt: EncryptArchiveJob::encryptionFlags NEW. + qt: SignArchiveJob::setSigners NEW. + qt: SignArchiveJob::signers NEW. + qt: SignArchiveJob::setInputPaths NEW. + qt: SignArchiveJob::inputPaths NEW. + qt: SignArchiveJob::setOutputFile NEW. + qt: SignArchiveJob::outputFile NEW. + qt: SignEncryptArchiveJob::setSigners NEW. + qt: SignEncryptArchiveJob::signers NEW. + qt: SignEncryptArchiveJob::setRecipients NEW. + qt: SignEncryptArchiveJob::recipients NEW. + qt: SignEncryptArchiveJob::setInputPaths NEW. + qt: SignEncryptArchiveJob::inputPaths NEW. + qt: SignEncryptArchiveJob::setOutputFile NEW. + qt: SignEncryptArchiveJob::outputFile NEW. + qt: SignEncryptArchiveJob::setEncryptionFlags NEW. + qt: SignEncryptArchiveJob::encryptionFlags NEW. Noteworthy changes in version 1.20.0 (2023-04-20) ------------------------------------------------- diff --git a/lang/qt/src/encryptarchivejob.cpp b/lang/qt/src/encryptarchivejob.cpp index a99de13f..aa51bcf3 100644 --- a/lang/qt/src/encryptarchivejob.cpp +++ b/lang/qt/src/encryptarchivejob.cpp @@ -56,6 +56,54 @@ bool EncryptArchiveJob::isSupported() return (gpgVersion >= "2.4.1") || (gpgVersion >= "2.2.42" && gpgVersion < "2.3.0"); } +void EncryptArchiveJob::setRecipients(const std::vector &recipients) +{ + auto d = jobPrivate(this); + d->m_recipients = recipients; +} + +std::vector EncryptArchiveJob::recipients() const +{ + auto d = jobPrivate(this); + return d->m_recipients; +} + +void EncryptArchiveJob::setInputPaths(const std::vector &paths) +{ + auto d = jobPrivate(this); + d->m_inputPaths = paths; +} + +std::vector EncryptArchiveJob::inputPaths() const +{ + auto d = jobPrivate(this); + return d->m_inputPaths; +} + +void EncryptArchiveJob::setOutputFile(const QString &path) +{ + auto d = jobPrivate(this); + d->m_outputFilePath = path; +} + +QString EncryptArchiveJob::outputFile() const +{ + auto d = jobPrivate(this); + return d->m_outputFilePath; +} + +void EncryptArchiveJob::setEncryptionFlags(GpgME::Context::EncryptionFlags flags) +{ + auto d = jobPrivate(this); + d->m_encryptionFlags = static_cast(flags | GpgME::Context::EncryptArchive); +} + +GpgME::Context::EncryptionFlags EncryptArchiveJob::encryptionFlags() const +{ + auto d = jobPrivate(this); + return d->m_encryptionFlags; +} + void EncryptArchiveJob::setBaseDirectory(const QString &baseDirectory) { auto d = jobPrivate(this); diff --git a/lang/qt/src/encryptarchivejob.h b/lang/qt/src/encryptarchivejob.h index b3c16c3a..66d45619 100644 --- a/lang/qt/src/encryptarchivejob.h +++ b/lang/qt/src/encryptarchivejob.h @@ -63,6 +63,53 @@ public: static bool isSupported(); + /** + * Sets the keys to use for encrypting the archive. + * + * Used if the job is started with startIt(). + */ + void setRecipients(const std::vector &recipients); + std::vector recipients() const; + + /** + * Sets the paths of the files and folders to put into the archive. + * + * If base directory is set, then the paths must be relative to the + * base directory. + * + * Used if the job is started with startIt(). + */ + void setInputPaths(const std::vector &paths); + std::vector inputPaths() const; + + /** + * Sets the path of the file to write the created archive to. + * + * If \a path is a relative path and base directory is set, then the + * path is interpreted relative to the base directory. + * + * Used if the job is started with startIt(). + * + * \note If a file with this path exists, then the job will fail, i.e. you + * need to delete an existing file that shall be overwritten before you + * start the job. + */ + void setOutputFile(const QString &path); + QString outputFile() const; + + /** + * Sets the flags to use for encryption. Defaults to \c EncryptArchive. + * The \c EncryptArchive flag is always assumed set for this job. + * + * Used if the job is started with startIt(). + */ + void setEncryptionFlags(GpgME::Context::EncryptionFlags flags); + GpgME::Context::EncryptionFlags encryptionFlags() const; + + /** + * Sets the base directory for the relative paths of the input files and + * the output file. + */ void setBaseDirectory(const QString &baseDirectory); QString baseDirectory() const; diff --git a/lang/qt/src/encryptarchivejob_p.h b/lang/qt/src/encryptarchivejob_p.h index 798096db..f2d5eea9 100644 --- a/lang/qt/src/encryptarchivejob_p.h +++ b/lang/qt/src/encryptarchivejob_p.h @@ -41,7 +41,11 @@ namespace QGpgME struct EncryptArchiveJobPrivate : public JobPrivate { + std::vector m_recipients; + std::vector m_inputPaths; + QString m_outputFilePath; QString m_baseDirectory; + GpgME::Context::EncryptionFlags m_encryptionFlags = GpgME::Context::EncryptArchive; }; } diff --git a/lang/qt/src/qgpgmeencryptarchivejob.cpp b/lang/qt/src/qgpgmeencryptarchivejob.cpp index 6ae310e7..c7f84182 100644 --- a/lang/qt/src/qgpgmeencryptarchivejob.cpp +++ b/lang/qt/src/qgpgmeencryptarchivejob.cpp @@ -44,6 +44,8 @@ #include "encryptarchivejob_p.h" #include "filelistdataprovider.h" +#include + #include using namespace QGpgME; @@ -65,11 +67,7 @@ public: ~QGpgMEEncryptArchiveJobPrivate() override = default; private: - GpgME::Error startIt() override - { - Q_ASSERT(!"Not supported by this Job class."); - return Error::fromCode(GPG_ERR_NOT_SUPPORTED); - } + GpgME::Error startIt() override; void startNow() override { @@ -90,25 +88,18 @@ QGpgMEEncryptArchiveJob::QGpgMEEncryptArchiveJob(Context *context) } static QGpgMEEncryptArchiveJob::result_type encrypt(Context *ctx, - QThread *thread, const std::vector &recipients, const std::vector &paths, - const std::weak_ptr &cipherText_, + GpgME::Data &outdata, Context::EncryptionFlags flags, const QString &baseDirectory) { - const std::shared_ptr cipherText = cipherText_.lock(); - const _detail::ToThreadMover ctMover(cipherText, thread); - QGpgME::FileListDataProvider in{paths}; Data indata(&in); if (!baseDirectory.isEmpty()) { indata.setFileName(baseDirectory.toStdString()); } - QGpgME::QIODeviceDataProvider out{cipherText}; - Data outdata(&out); - flags = static_cast(flags | Context::EncryptArchive); const EncryptionResult res = ctx->encrypt(recipients, indata, outdata, flags); Error ae; @@ -116,6 +107,35 @@ static QGpgMEEncryptArchiveJob::result_type encrypt(Context *ctx, return std::make_tuple(res, log, ae); } +static QGpgMEEncryptArchiveJob::result_type encrypt_to_io_device(Context *ctx, + QThread *thread, + const std::vector &recipients, + const std::vector &paths, + const std::weak_ptr &cipherText_, + Context::EncryptionFlags flags, + const QString &baseDirectory) +{ + const std::shared_ptr cipherText = cipherText_.lock(); + const _detail::ToThreadMover ctMover(cipherText, thread); + QGpgME::QIODeviceDataProvider out{cipherText}; + Data outdata(&out); + + return encrypt(ctx, recipients, paths, outdata, flags, baseDirectory); +} + +static QGpgMEEncryptArchiveJob::result_type encrypt_to_filename(Context *ctx, + const std::vector &recipients, + const std::vector &paths, + const QString &outputFile, + Context::EncryptionFlags flags, + const QString &baseDirectory) +{ + Data outdata; + outdata.setFileName(QFile::encodeName(outputFile).constData()); + + return encrypt(ctx, recipients, paths, outdata, flags, baseDirectory); +} + GpgME::Error QGpgMEEncryptArchiveJob::start(const std::vector &recipients, const std::vector &paths, const std::shared_ptr &cipherText, @@ -125,7 +145,7 @@ GpgME::Error QGpgMEEncryptArchiveJob::start(const std::vector &recip return Error::fromCode(GPG_ERR_INV_VALUE); } - run(std::bind(&encrypt, + run(std::bind(&encrypt_to_io_device, std::placeholders::_1, std::placeholders::_2, recipients, @@ -137,4 +157,17 @@ GpgME::Error QGpgMEEncryptArchiveJob::start(const std::vector &recip return {}; } +GpgME::Error QGpgMEEncryptArchiveJobPrivate::startIt() +{ + if (m_outputFilePath.isEmpty()) { + return Error::fromCode(GPG_ERR_INV_VALUE); + } + + q->run([=](Context *ctx) { + return encrypt_to_filename(ctx, m_recipients, m_inputPaths, m_outputFilePath, m_encryptionFlags, m_baseDirectory); + }); + + return {}; +} + #include "qgpgmeencryptarchivejob.moc" diff --git a/lang/qt/src/qgpgmesignarchivejob.cpp b/lang/qt/src/qgpgmesignarchivejob.cpp index c25ea89f..005b3e44 100644 --- a/lang/qt/src/qgpgmesignarchivejob.cpp +++ b/lang/qt/src/qgpgmesignarchivejob.cpp @@ -44,6 +44,8 @@ #include "signarchivejob_p.h" #include "filelistdataprovider.h" +#include + #include using namespace QGpgME; @@ -65,11 +67,7 @@ public: ~QGpgMESignArchiveJobPrivate() override = default; private: - GpgME::Error startIt() override - { - Q_ASSERT(!"Not supported by this Job class."); - return Error::fromCode(GPG_ERR_NOT_SUPPORTED); - } + GpgME::Error startIt() override; void startNow() override { @@ -90,24 +88,17 @@ QGpgMESignArchiveJob::QGpgMESignArchiveJob(Context *context) } static QGpgMESignArchiveJob::result_type sign(Context *ctx, - QThread *thread, const std::vector &signers, const std::vector &paths, - const std::weak_ptr &output_, + GpgME::Data &outdata, const QString &baseDirectory) { - const std::shared_ptr output = output_.lock(); - const _detail::ToThreadMover ctMover(output, thread); - QGpgME::FileListDataProvider in{paths}; Data indata(&in); if (!baseDirectory.isEmpty()) { indata.setFileName(baseDirectory.toStdString()); } - QGpgME::QIODeviceDataProvider out{output}; - Data outdata(&out); - ctx->clearSigningKeys(); for (const Key &signer : signers) { if (!signer.isNull()) { @@ -123,6 +114,33 @@ static QGpgMESignArchiveJob::result_type sign(Context *ctx, return std::make_tuple(res, log, ae); } +static QGpgMESignArchiveJob::result_type sign_to_io_device(Context *ctx, + QThread *thread, + const std::vector &signers, + const std::vector &paths, + const std::weak_ptr &output_, + const QString &baseDirectory) +{ + const std::shared_ptr output = output_.lock(); + const _detail::ToThreadMover ctMover(output, thread); + QGpgME::QIODeviceDataProvider out{output}; + Data outdata(&out); + + return sign(ctx, signers, paths, outdata, baseDirectory); +} + +static QGpgMESignArchiveJob::result_type sign_to_filename(Context *ctx, + const std::vector &signers, + const std::vector &paths, + const QString &outputFile, + const QString &baseDirectory) +{ + Data outdata; + outdata.setFileName(QFile::encodeName(outputFile).constData()); + + return sign(ctx, signers, paths, outdata, baseDirectory); +} + GpgME::Error QGpgMESignArchiveJob::start(const std::vector &signers, const std::vector &paths, const std::shared_ptr &output) @@ -131,7 +149,7 @@ GpgME::Error QGpgMESignArchiveJob::start(const std::vector &signers, return Error::fromCode(GPG_ERR_INV_VALUE); } - run(std::bind(&sign, + run(std::bind(&sign_to_io_device, std::placeholders::_1, std::placeholders::_2, signers, @@ -142,4 +160,18 @@ GpgME::Error QGpgMESignArchiveJob::start(const std::vector &signers, return {}; } + +GpgME::Error QGpgMESignArchiveJobPrivate::startIt() +{ + if (m_outputFilePath.isEmpty()) { + return Error::fromCode(GPG_ERR_INV_VALUE); + } + + q->run([=](Context *ctx) { + return sign_to_filename(ctx, m_signers, m_inputPaths, m_outputFilePath, m_baseDirectory); + }); + + return {}; +} + #include "qgpgmesignarchivejob.moc" diff --git a/lang/qt/src/qgpgmesignencryptarchivejob.cpp b/lang/qt/src/qgpgmesignencryptarchivejob.cpp index 2c029a25..e47bfa0c 100644 --- a/lang/qt/src/qgpgmesignencryptarchivejob.cpp +++ b/lang/qt/src/qgpgmesignencryptarchivejob.cpp @@ -44,14 +44,9 @@ #include "signencryptarchivejob_p.h" #include "filelistdataprovider.h" -// #include +#include + #include -// #include -// -// #include -// #include -// -// #include using namespace QGpgME; using namespace GpgME; @@ -72,11 +67,7 @@ public: ~QGpgMESignEncryptArchiveJobPrivate() override = default; private: - GpgME::Error startIt() override - { - Q_ASSERT(!"Not supported by this Job class."); - return Error::fromCode(GPG_ERR_NOT_SUPPORTED); - } + GpgME::Error startIt() override; void startNow() override { @@ -97,26 +88,19 @@ QGpgMESignEncryptArchiveJob::QGpgMESignEncryptArchiveJob(Context *context) } static QGpgMESignEncryptArchiveJob::result_type sign_encrypt(Context *ctx, - QThread *thread, const std::vector &signers, const std::vector &recipients, const std::vector &paths, - const std::weak_ptr &cipherText_, + GpgME::Data &outdata, Context::EncryptionFlags encryptionFlags, const QString &baseDirectory) { - const std::shared_ptr cipherText = cipherText_.lock(); - const _detail::ToThreadMover ctMover(cipherText, thread); - QGpgME::FileListDataProvider in{paths}; Data indata(&in); if (!baseDirectory.isEmpty()) { indata.setFileName(baseDirectory.toStdString()); } - QGpgME::QIODeviceDataProvider out{cipherText}; - Data outdata(&out); - ctx->clearSigningKeys(); for (const Key &signer : signers) { if (!signer.isNull()) { @@ -133,6 +117,37 @@ static QGpgMESignEncryptArchiveJob::result_type sign_encrypt(Context *ctx, return std::make_tuple(res.first, res.second, log, ae); } +static QGpgMESignEncryptArchiveJob::result_type sign_encrypt_to_io_device(Context *ctx, + QThread *thread, + const std::vector &signers, + const std::vector &recipients, + const std::vector &paths, + const std::weak_ptr &cipherText_, + Context::EncryptionFlags encryptionFlags, + const QString &baseDirectory) +{ + const std::shared_ptr cipherText = cipherText_.lock(); + const _detail::ToThreadMover ctMover(cipherText, thread); + QGpgME::QIODeviceDataProvider out{cipherText}; + Data outdata(&out); + + return sign_encrypt(ctx, signers, recipients, paths, outdata, encryptionFlags, baseDirectory); +} + +static QGpgMESignEncryptArchiveJob::result_type sign_encrypt_to_filename(Context *ctx, + const std::vector &signers, + const std::vector &recipients, + const std::vector &paths, + const QString &outputFile, + Context::EncryptionFlags encryptionFlags, + const QString &baseDirectory) +{ + Data outdata; + outdata.setFileName(QFile::encodeName(outputFile).constData()); + + return sign_encrypt(ctx, signers, recipients, paths, outdata, encryptionFlags, baseDirectory); +} + GpgME::Error QGpgMESignEncryptArchiveJob::start(const std::vector &signers, const std::vector &recipients, const std::vector &paths, @@ -143,7 +158,7 @@ GpgME::Error QGpgMESignEncryptArchiveJob::start(const std::vector &s return Error::fromCode(GPG_ERR_INV_VALUE); } - run(std::bind(&sign_encrypt, + run(std::bind(&sign_encrypt_to_io_device, std::placeholders::_1, std::placeholders::_2, signers, @@ -156,4 +171,17 @@ GpgME::Error QGpgMESignEncryptArchiveJob::start(const std::vector &s return {}; } +GpgME::Error QGpgMESignEncryptArchiveJobPrivate::startIt() +{ + if (m_outputFilePath.isEmpty()) { + return Error::fromCode(GPG_ERR_INV_VALUE); + } + + q->run([=](Context *ctx) { + return sign_encrypt_to_filename(ctx, m_signers, m_recipients, m_inputPaths, m_outputFilePath, m_encryptionFlags, m_baseDirectory); + }); + + return {}; +} + #include "qgpgmesignencryptarchivejob.moc" diff --git a/lang/qt/src/signarchivejob.cpp b/lang/qt/src/signarchivejob.cpp index d185ae9f..411dbc57 100644 --- a/lang/qt/src/signarchivejob.cpp +++ b/lang/qt/src/signarchivejob.cpp @@ -56,6 +56,42 @@ bool SignArchiveJob::isSupported() return (gpgVersion >= "2.4.1") || (gpgVersion >= "2.2.42" && gpgVersion < "2.3.0"); } +void SignArchiveJob::setSigners(const std::vector &signers) +{ + auto d = jobPrivate(this); + d->m_signers = signers; +} + +std::vector SignArchiveJob::signers() const +{ + auto d = jobPrivate(this); + return d->m_signers; +} + +void SignArchiveJob::setInputPaths(const std::vector &paths) +{ + auto d = jobPrivate(this); + d->m_inputPaths = paths; +} + +std::vector SignArchiveJob::inputPaths() const +{ + auto d = jobPrivate(this); + return d->m_inputPaths; +} + +void SignArchiveJob::setOutputFile(const QString &path) +{ + auto d = jobPrivate(this); + d->m_outputFilePath = path; +} + +QString SignArchiveJob::outputFile() const +{ + auto d = jobPrivate(this); + return d->m_outputFilePath; +} + void SignArchiveJob::setBaseDirectory(const QString &baseDirectory) { auto d = jobPrivate(this); diff --git a/lang/qt/src/signarchivejob.h b/lang/qt/src/signarchivejob.h index ef2b6754..7d1f6513 100644 --- a/lang/qt/src/signarchivejob.h +++ b/lang/qt/src/signarchivejob.h @@ -63,6 +63,44 @@ public: static bool isSupported(); + /** + * Sets the keys to use for signing the archive. + * + * Used if the job is started with startIt(). + */ + void setSigners(const std::vector &signers); + std::vector signers() const; + + /** + * Sets the paths of the files and folders to put into the archive. + * + * If base directory is set, then the paths must be relative to the + * base directory. + * + * Used if the job is started with startIt(). + */ + void setInputPaths(const std::vector &paths); + std::vector inputPaths() const; + + /** + * Sets the path of the file to write the created archive to. + * + * If \a path is a relative path and base directory is set, then the + * path is interpreted relative to the base directory. + * + * Used if the job is started with startIt(). + * + * \note If a file with this path exists, then the job will fail, i.e. you + * need to delete an existing file that shall be overwritten before you + * start the job. + */ + void setOutputFile(const QString &path); + QString outputFile() const; + + /** + * Sets the base directory for the relative paths of the input files and + * the output file. + */ void setBaseDirectory(const QString &baseDirectory); QString baseDirectory() const; diff --git a/lang/qt/src/signarchivejob_p.h b/lang/qt/src/signarchivejob_p.h index 9176e7b4..9ec921bb 100644 --- a/lang/qt/src/signarchivejob_p.h +++ b/lang/qt/src/signarchivejob_p.h @@ -41,6 +41,9 @@ namespace QGpgME struct SignArchiveJobPrivate : public JobPrivate { + std::vector m_signers; + std::vector m_inputPaths; + QString m_outputFilePath; QString m_baseDirectory; }; diff --git a/lang/qt/src/signencryptarchivejob.cpp b/lang/qt/src/signencryptarchivejob.cpp index b1d5e170..429b6bf1 100644 --- a/lang/qt/src/signencryptarchivejob.cpp +++ b/lang/qt/src/signencryptarchivejob.cpp @@ -56,6 +56,66 @@ bool SignEncryptArchiveJob::isSupported() return (gpgVersion >= "2.4.1") || (gpgVersion >= "2.2.42" && gpgVersion < "2.3.0"); } +void SignEncryptArchiveJob::setSigners(const std::vector &signers) +{ + auto d = jobPrivate(this); + d->m_signers = signers; +} + +std::vector SignEncryptArchiveJob::signers() const +{ + auto d = jobPrivate(this); + return d->m_signers; +} + +void SignEncryptArchiveJob::setRecipients(const std::vector &recipients) +{ + auto d = jobPrivate(this); + d->m_recipients = recipients; +} + +std::vector SignEncryptArchiveJob::recipients() const +{ + auto d = jobPrivate(this); + return d->m_recipients; +} + +void SignEncryptArchiveJob::setInputPaths(const std::vector &paths) +{ + auto d = jobPrivate(this); + d->m_inputPaths = paths; +} + +std::vector SignEncryptArchiveJob::inputPaths() const +{ + auto d = jobPrivate(this); + return d->m_inputPaths; +} + +void SignEncryptArchiveJob::setOutputFile(const QString &path) +{ + auto d = jobPrivate(this); + d->m_outputFilePath = path; +} + +QString SignEncryptArchiveJob::outputFile() const +{ + auto d = jobPrivate(this); + return d->m_outputFilePath; +} + +void SignEncryptArchiveJob::setEncryptionFlags(GpgME::Context::EncryptionFlags flags) +{ + auto d = jobPrivate(this); + d->m_encryptionFlags = static_cast(flags | GpgME::Context::EncryptArchive); +} + +GpgME::Context::EncryptionFlags SignEncryptArchiveJob::encryptionFlags() const +{ + auto d = jobPrivate(this); + return d->m_encryptionFlags; +} + void SignEncryptArchiveJob::setBaseDirectory(const QString &baseDirectory) { auto d = jobPrivate(this); diff --git a/lang/qt/src/signencryptarchivejob.h b/lang/qt/src/signencryptarchivejob.h index a14b6d64..fddf3012 100644 --- a/lang/qt/src/signencryptarchivejob.h +++ b/lang/qt/src/signencryptarchivejob.h @@ -63,6 +63,61 @@ public: static bool isSupported(); + /** + * Sets the keys to use for signing the archive. + * + * Used if the job is started with startIt(). + */ + void setSigners(const std::vector &signers); + std::vector signers() const; + + /** + * Sets the keys to use for encrypting the archive. + * + * Used if the job is started with startIt(). + */ + void setRecipients(const std::vector &recipients); + std::vector recipients() const; + + /** + * Sets the paths of the files and folders to put into the archive. + * + * If base directory is set, then the paths must be relative to the + * base directory. + * + * Used if the job is started with startIt(). + */ + void setInputPaths(const std::vector &paths); + std::vector inputPaths() const; + + /** + * Sets the path of the file to write the created archive to. + * + * If \a path is a relative path and base directory is set, then the + * path is interpreted relative to the base directory. + * + * Used if the job is started with startIt(). + * + * \note If a file with this path exists, then the job will fail, i.e. you + * need to delete an existing file that shall be overwritten before you + * start the job. + */ + void setOutputFile(const QString &path); + QString outputFile() const; + + /** + * Sets the flags to use for encryption. Defaults to \c EncryptArchive. + * The \c EncryptArchive flag is always assumed set for this job. + * + * Used if the job is started with startIt(). + */ + void setEncryptionFlags(GpgME::Context::EncryptionFlags flags); + GpgME::Context::EncryptionFlags encryptionFlags() const; + + /** + * Sets the base directory for the relative paths of the input files and + * the output file. + */ void setBaseDirectory(const QString &baseDirectory); QString baseDirectory() const; diff --git a/lang/qt/src/signencryptarchivejob_p.h b/lang/qt/src/signencryptarchivejob_p.h index 2732fd0a..3ae7a4c1 100644 --- a/lang/qt/src/signencryptarchivejob_p.h +++ b/lang/qt/src/signencryptarchivejob_p.h @@ -41,7 +41,12 @@ namespace QGpgME struct SignEncryptArchiveJobPrivate : public JobPrivate { + std::vector m_signers; + std::vector m_recipients; + std::vector m_inputPaths; + QString m_outputFilePath; QString m_baseDirectory; + GpgME::Context::EncryptionFlags m_encryptionFlags = GpgME::Context::EncryptArchive; }; } diff --git a/lang/qt/tests/run-encryptarchivejob.cpp b/lang/qt/tests/run-encryptarchivejob.cpp index 9ce79b6c..afbb13c0 100644 --- a/lang/qt/tests/run-encryptarchivejob.cpp +++ b/lang/qt/tests/run-encryptarchivejob.cpp @@ -41,7 +41,9 @@ #include #include #include +#include #include +#include #include #include @@ -95,23 +97,14 @@ CommandLineOptions parseCommandLine(const QStringList &arguments) return options; } -std::shared_ptr createOutput(const QString &fileName) +QString checkOutputFilePath(const QString &fileName, const QString &baseDirectory) { - std::shared_ptr output; - - if (fileName.isEmpty()) { - output.reset(new QFile); - output->open(stdout, QIODevice::WriteOnly); - } else { - if (QFile::exists(fileName)) { - qCritical() << "File" << fileName << "exists. Bailing out."; - } else { - output.reset(new QFile{fileName}); - output->open(QIODevice::WriteOnly); - } + const QFileInfo fi{QDir{baseDirectory}, fileName}; + if (fi.exists()) { + qCritical() << "File" << fi.filePath() << "exists. Bailing out."; + return {}; } - - return output; + return fileName; } int main(int argc, char **argv) @@ -129,9 +122,16 @@ int main(int argc, char **argv) return 1; } - auto output = createOutput(options.archiveName); - if (!output) { - return 1; + std::shared_ptr output; + QString outputFilePath; + if (options.archiveName.isEmpty() || options.archiveName == QLatin1String{"-"}) { + output.reset(new QFile); + output->open(stdout, QIODevice::WriteOnly); + } else { + outputFilePath = checkOutputFilePath(options.archiveName, options.baseDirectory); + if (outputFilePath.isEmpty()) { + return 1; + } } if (options.sign) { @@ -148,7 +148,14 @@ int main(int argc, char **argv) qApp->quit(); }); - const auto err = job->start({}, {}, options.filesAndDirectories, output, GpgME::Context::None); + GpgME::Error err; + if (output) { + err = job->start({}, {}, options.filesAndDirectories, output, GpgME::Context::None); + } else { + job->setInputPaths(options.filesAndDirectories); + job->setOutputFile(outputFilePath); + err = job->startIt(); + } if (err) { std::cerr << "Error: Starting the job failed: " << err.asString() << std::endl; return 1; @@ -166,7 +173,14 @@ int main(int argc, char **argv) qApp->quit(); }); - const auto err = job->start({}, options.filesAndDirectories, output, GpgME::Context::None); + GpgME::Error err; + if (output) { + err = job->start({}, options.filesAndDirectories, output, GpgME::Context::None); + } else { + job->setInputPaths(options.filesAndDirectories); + job->setOutputFile(outputFilePath); + err = job->startIt(); + } if (err) { std::cerr << "Error: Starting the job failed: " << err.asString() << std::endl; return 1; diff --git a/lang/qt/tests/run-signarchivejob.cpp b/lang/qt/tests/run-signarchivejob.cpp index affd8e4d..4bf769b2 100644 --- a/lang/qt/tests/run-signarchivejob.cpp +++ b/lang/qt/tests/run-signarchivejob.cpp @@ -40,7 +40,9 @@ #include #include #include +#include #include +#include #include #include @@ -90,23 +92,14 @@ CommandLineOptions parseCommandLine(const QStringList &arguments) return options; } -std::shared_ptr createOutput(const QString &fileName) +QString checkOutputFilePath(const QString &fileName, const QString &baseDirectory) { - std::shared_ptr output; - - if (fileName.isEmpty()) { - output.reset(new QFile); - output->open(stdout, QIODevice::WriteOnly); - } else { - if (QFile::exists(fileName)) { - qCritical() << "File" << fileName << "exists. Bailing out."; - } else { - output.reset(new QFile{fileName}); - output->open(QIODevice::WriteOnly); - } + const QFileInfo fi{QDir{baseDirectory}, fileName}; + if (fi.exists()) { + qCritical() << "File" << fi.filePath() << "exists. Bailing out."; + return {}; } - - return output; + return fileName; } int main(int argc, char **argv) @@ -123,9 +116,16 @@ int main(int argc, char **argv) return 1; } - auto output = createOutput(options.archiveName); - if (!output) { - return 1; + std::shared_ptr output; + QString outputFilePath; + if (options.archiveName.isEmpty() || options.archiveName == QLatin1String{"-"}) { + output.reset(new QFile); + output->open(stdout, QIODevice::WriteOnly); + } else { + outputFilePath = checkOutputFilePath(options.archiveName, options.baseDirectory); + if (outputFilePath.isEmpty()) { + return 1; + } } auto job = QGpgME::openpgp()->signArchiveJob(options.armor); @@ -140,7 +140,14 @@ int main(int argc, char **argv) qApp->quit(); }); - const auto err = job->start({}, options.filesAndDirectories, output); + GpgME::Error err; + if (output) { + err = job->start({}, options.filesAndDirectories, output); + } else { + job->setInputPaths(options.filesAndDirectories); + job->setOutputFile(outputFilePath); + err = job->startIt(); + } if (err) { std::cerr << "Error: Starting the job failed: " << err.asString() << std::endl; return 1;