diff --git a/cmake/modules/FindAssuan2.cmake b/cmake/modules/FindAssuan2.cmake
index ae8d62cde..27a194805 100644
--- a/cmake/modules/FindAssuan2.cmake
+++ b/cmake/modules/FindAssuan2.cmake
@@ -1,251 +1,251 @@
# - Try :to find the assuan v2 library
# Variables set:
# ASSUAN2_{INCLUDES,FOUND,LIBRARIES} will be set for each of the above
#if this is built-in, please replace, if it isn't, export into a MacroToBool.cmake of it's own
macro( macro_bool_to_bool FOUND_VAR )
foreach( _current_VAR ${ARGN} )
if ( ${FOUND_VAR} )
set( ${_current_VAR} TRUE )
else()
set( ${_current_VAR} FALSE )
endif()
endforeach()
endmacro()
if ( WIN32 )
# On Windows, we don't have a libassuan-config script, so we need to
# look for the stuff ourselves:
# in cmake, AND and OR have the same precedence, there's no
# subexpressions, and expressions are evaluated short-circuit'ed
# IOW: CMake if() suxx.
set( _seem_to_have_cached_assuan2 false )
if ( ASSUAN2_INCLUDES )
if ( ASSUAN2_VANILLA_LIBRARIES )#OR ASSUAN2_QT_LIBRARIES OR ASSUAN2_GLIB_LIBRARIES )
set( _seem_to_have_cached_assuan2 true )
endif()
endif()
if ( _seem_to_have_cached_assuan2 )
macro_bool_to_bool( ASSUAN2_VANILLA_LIBRARIES ASSUAN2_VANILLA_FOUND )
# this would have been preferred:
#set( ASSUAN2_*_FOUND macro_bool_to_bool(ASSUAN2_*_LIBRARIES) )
if ( ASSUAN2_VANILLA_FOUND ) #OR ASSUAN2_GLIB_FOUND OR ASSUAN2_QT_FOUND )
set( ASSUAN2_FOUND true )
else()
set( ASSUAN2_FOUND false )
endif()
else()
set( ASSUAN2_FOUND false )
set( ASSUAN2_VANILLA_FOUND false )
#set( ASSUAN2_GLIB_FOUND false )
#set( ASSUAN2_QT_FOUND false )
find_path( ASSUAN2_INCLUDES assuan.h
${CMAKE_INCLUDE_PATH}
${CMAKE_INSTALL_PREFIX}/include
)
find_library( _assuan2_library NAMES assuan2 libassuan2 assuan-0 libassuan-0 #sic!
PATHS
${CMAKE_LIBRARY_PATH}
${CMAKE_INSTALL_PREFIX}/lib
)
find_library( _gpg_error_library NAMES gpg-error libgpg-error gpg-error-0 libgpg-error-0
PATHS
${CMAKE_LIBRARY_PATH}
${CMAKE_INSTALL_PREFIX}/lib
)
set( ASSUAN2_INCLUDES ${ASSUAN2_INCLUDES} )
if ( _assuan2_library AND _gpg_error_library )
set( ASSUAN2_LIBRARIES ${_assuan2_library} ${_gpg_error_library} ws2_32 )
set( ASSUAN2_FOUND true )
endif()
endif()
if (ASSUAN2_FOUND)
set (HAVE_ASSUAN2 1)
else()
set (HAVE_ASSUAN2 0)
endif()
else() # not WIN32
# On *nix, we have the libassuan-config script which can tell us all we
# need to know:
# see WIN32 case for an explanation of what this does:
set( _seem_to_have_cached_assuan2 false )
if ( ASSUAN2_INCLUDES AND ASSUAN2_LIBRARIES )
set( _seem_to_have_cached_assuan2 true )
endif()
if ( _seem_to_have_cached_assuan2 )
set( ASSUAN2_FOUND true )
else()
set( ASSUAN2_FOUND false )
find_program( _ASSUAN2CONFIG_EXECUTABLE NAMES libassuan-config )
# if libassuan-config has been found
if ( _ASSUAN2CONFIG_EXECUTABLE )
message( STATUS "Found libassuan-config at ${_ASSUAN2CONFIG_EXECUTABLE}" )
exec_program( ${_ASSUAN2CONFIG_EXECUTABLE} ARGS --version OUTPUT_VARIABLE ASSUAN2_VERSION )
set( _ASSUAN2_MIN_VERSION "2.0.0" )
if( ASSUAN2_VERSION VERSION_GREATER ${_ASSUAN2_MIN_VERSION} )
set( _ASSUAN2_INSTALLED_VERSION_OK TRUE )
endif()
if ( NOT _ASSUAN2_INSTALLED_VERSION_OK )
message( STATUS "The installed version of assuan is too old: ${ASSUAN2_VERSION} (required: >= ${_ASSUAN2_MIN_VERSION})" )
else()
message( STATUS "Found assuan v${ASSUAN2_VERSION}" )
exec_program( ${_ASSUAN2CONFIG_EXECUTABLE} ARGS --libs OUTPUT_VARIABLE _assuan2_config_libs RETURN_VALUE _ret )
if ( _ret )
set( _assuan2_config_libs )
endif()
# append -lgpg-error to the list of libraries, if necessary
if ( _assuan2_config_libs AND NOT _assuan2_config_libs MATCHES "lgpg-error" )
set( _assuan2_config_libs "${_assuan2_config_libs} -lgpg-error" )
endif()
if ( _assuan2_config_libs )
exec_program( ${_ASSUAN2CONFIG_EXECUTABLE} ARGS --cflags OUTPUT_VARIABLE _ASSUAN2_CFLAGS )
if ( _ASSUAN2_CFLAGS )
string( REGEX REPLACE "(\r?\n)+$" " " _ASSUAN2_CFLAGS "${_ASSUAN2_CFLAGS}" )
string( REGEX REPLACE " *-I" ";" ASSUAN2_INCLUDES "${_ASSUAN2_CFLAGS}" )
endif()
if ( _assuan2_config_libs )
set( _assuan2_library_dirs )
set( _assuan2_library_names )
string( REGEX REPLACE " +" ";" _assuan2_config_libs "${_assuan2_config_libs}" )
foreach( _flag ${_assuan2_config_libs} )
if ( "${_flag}" MATCHES "^-L" )
string( REGEX REPLACE "^-L" "" _dir "${_flag}" )
file( TO_CMAKE_PATH "${_dir}" _dir )
set( _assuan2_library_dirs ${_assuan2_library_dirs} "${_dir}" )
elseif( "${_flag}" MATCHES "^-l" )
string( REGEX REPLACE "^-l" "" _name "${_flag}" )
set( _assuan2_library_names ${_assuan2_library_names} "${_name}" )
endif()
endforeach()
set( ASSUAN2_FOUND true )
foreach( _name ${_assuan2_library_names} )
set( _assuan2_${_name}_lib )
# if -L options were given, look only there
if ( _assuan2_library_dirs )
find_library( _assuan2_${_name}_lib NAMES ${_name} PATHS ${_assuan2_library_dirs} NO_DEFAULT_PATH )
endif()
# if not found there, look in system directories
if ( NOT _assuan2_${_name}_lib )
find_library( _assuan2_${_name}_lib NAMES ${_name} )
endif()
# if still not found, then the whole flavour isn't found
if ( NOT _assuan2_${_name}_lib )
if ( ASSUAN2_FOUND )
set( ASSUAN2_FOUND false )
- set( _not_found_reason "dependant library ${_name} wasn't found" )
+ set( _not_found_reason "dependent library ${_name} wasn't found" )
endif()
endif()
set( ASSUAN2_LIBRARIES ${ASSUAN2_LIBRARIES} "${_assuan2_${_name}_lib}" )
endforeach()
#check_c_library_exists_explicit( assuan assuan_check_version "${_ASSUAN2_CFLAGS}" "${ASSUAN2_LIBRARIES}" ASSUAN2_FOUND )
if ( ASSUAN2_FOUND )
message( STATUS " Checking whether assuan is usable...yes" )
else()
message( STATUS " Checking whether assuan is usable...no" )
message( STATUS " (${_not_found_reason})" )
endif()
endif()
# ensure that they are cached
set( ASSUAN2_INCLUDES ${ASSUAN2_INCLUDES} )
set( ASSUAN2_LIBRARIES ${ASSUAN2_LIBRARIES} )
endif()
endif()
endif()
endif()
if (ASSUAN2_FOUND)
set (HAVE_ASSUAN2 1)
else()
set (HAVE_ASSUAN2 0)
endif()
endif() # WIN32 | Unix
if ( NOT Assuan2_FIND_QUIETLY )
if ( ASSUAN2_FOUND )
message( STATUS "Usable assuan found." )
message( STATUS " Includes: ${ASSUAN2_INCLUDES}" )
message( STATUS " Libraries: ${ASSUAN2_LIBRARIES}" )
else()
message( STATUS "No usable assuan found." )
endif()
if( Assuan2_FIND_REQUIRED )
set( _ASSUAN2_TYPE "REQUIRED" )
else()
set( _ASSUAN2_TYPE "OPTIONAL" )
endif()
if ( WIN32 )
set( _assuan2_homepage "https://www.gpg4win.org" )
else()
set( _assuan2_homepage "https://www.gnupg.org/related_software/libassuan" )
endif()
set_package_properties(ASSUAN2 PROPERTIES DESCRIPTION "Assuan v2 IPC library"
URL ${_assuan2_homepage}
TYPE ${_ASSUAN2_TYPE}
PURPOSE "Needed for Kleopatra to act as the GnuPG UI Server"
)
else()
if ( Assuan2_FIND_REQUIRED AND NOT ASSUAN2_FOUND )
message( FATAL_ERROR "Assuan2 is required but was not found." )
endif()
endif()
diff --git a/src/conf/smimevalidationconfigurationwidget.ui b/src/conf/smimevalidationconfigurationwidget.ui
index 19daf8df1..39d76b4a2 100644
--- a/src/conf/smimevalidationconfigurationwidget.ui
+++ b/src/conf/smimevalidationconfigurationwidget.ui
@@ -1,477 +1,477 @@
Kleo::Config::SMimeValidationConfigurationWidget
0
0
502
603
-
-
- This option enables interval checking of certificate validity. You can also choose the checking interval (in hours). Note that validation is perfomed implicitly whenever significant files in ~/.gnupg change. This option therefore only affects external factors of certificate validity.
+ This option enables interval checking of certificate validity. You can also choose the checking interval (in hours). Note that validation is performed implicitly whenever significant files in ~/.gnupg change. This option therefore only affects external factors of certificate validity.
Check certificate validity every
-
false
- This option enables interval checking of certificate validity. You can also choose the checking interval (in hours). Note that validation is perfomed implicitly whenever significant files in ~/.gnupg change. This option therefore only affects external factors of certificate validity.
+ This option enables interval checking of certificate validity. You can also choose the checking interval (in hours). Note that validation is performed implicitly whenever significant files in ~/.gnupg change. This option therefore only affects external factors of certificate validity.
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
hour
hours
1
24
-
Qt::Horizontal
40
20
-
If this option is selected, S/MIME certificates are validated using Certificate Revocation Lists (CRLs).
Validate certificates using CRLs
true
-
If this option is selected, S/MIME certificates are validated online using the Online Certificates Status Protocol (OCSP). Fill in the URL of the OCSP responder below.
Validate certificates online (OCSP)
-
false
Online Certificate Validation
-
OCSP responder URL:
false
-
Enter here the address of the server for online validation of certificates (OCSP responder). The URL is usually starting with http://.
-
OCSP responder signature:
false
-
Ignore service URL of certificates
-
Choose here the certificate with which the OCSP server signs its replies.
-
By default, GnuPG uses the file ~/.gnupg/policies.txt to check if a certificate policy is allowed. If this option is selected, policies are not checked.
Do not check certificate policies
-
If this option is checked, Certificate Revocation Lists are never used to validate S/MIME certificates.
Never consult a CRL
-
If this option is checked while a root CA certificate is being imported, you will be asked to confirm its fingerprint and to state whether or not you consider this root certificate to be trusted. A root certificate needs to be trusted before the certificates it certified become trusted, but lightly allowing trusted root certificates into your certificate store will undermine the security of the system.
Allow to mark root certificates as trusted
-
If this option is checked, missing issuer certificates are fetched when necessary (this applies to both validation methods, CRLs and OCSP).
Fetch missing issuer certificates
-
&HTTP Requests
-
Entirely disables the use of HTTP for S/MIME.
Do not perform any HTTP requests
-
When looking for the location of a CRL, the to-be-tested certificate usually contains what are known as "CRL Distribution Point" (DP) entries, which are URLs describing the way to access the CRL. The first-found DP entry is used. With this option, all entries using the HTTP scheme are ignored when looking for a suitable DP.
Ignore HTTP CRL distribution point of certificates
-
If this option is selected, the value of the HTTP proxy shown on the right (which comes from the environment variable http_proxy) will be used for any HTTP request.
Use system HTTP proxy:
-
no proxy
false
-
Use this proxy for HTTP requests:
-
<p>If no system proxy is set, or you need to use a different proxy for GpgSM, you can enter its location here.</p><p>It will be used for all HTTP requests relating to S/MIME.</p><p>The syntax is host:port, for instance myproxy.nowhere.com:3128.</p>
-
Qt::Vertical
320
16
&LDAP Requests
-
Entirely disables the use of LDAP for S/MIME.
Do not perform any LDAP requests
-
When looking for the location of a CRL, the to-be-tested certificate usually contains what are known as "CRL Distribution Point" (DP) entries, which are URLs describing the way to access the CRL. The first found DP entry is used. With this option, all entries using the LDAP scheme are ignored when looking for a suitable DP.
Ignore LDAP CRL distribution point of certificates
-
Primary host for LDAP requests:
false
-
Entering an LDAP server here will make all LDAP requests go to that server first. More precisely, this setting overrides any specified host and port part in a LDAP URL and will also be used if host and port have been omitted from the URL. Other LDAP servers will be used only if the connection to the "proxy" failed.
The syntax is "HOST" or "HOST:PORT". If PORT is omitted, port 389 (standard LDAP port) is used.
-
Qt::Vertical
320
16
KleopatraClientCopy::Gui::CertificateRequester
QWidget
libkleopatraclient/gui/certificaterequester.h
1
libkleo/keyrequester.h
CRLRB
toggled(bool)
OCSPGroupBox
setDisabled(bool)
20
20
29
99
useCustomHTTPProxyRB
toggled(bool)
customHTTPProxy
setEnabled(bool)
44
542
481
542
disableLDAPCB
toggled(bool)
ignoreLDAPDPCB
setDisabled(bool)
190
440
188
471
disableLDAPCB
toggled(bool)
customLDAPLabel
setDisabled(bool)
136
440
146
508
disableLDAPCB
toggled(bool)
customLDAPProxy
setDisabled(bool)
328
440
481
508
disableHTTPCB
toggled(bool)
ignoreHTTPDPCB
setDisabled(bool)
338
440
338
471
disableHTTPCB
toggled(bool)
honorHTTPProxyRB
setDisabled(bool)
116
440
126
507
disableHTTPCB
toggled(bool)
useCustomHTTPProxyRB
setDisabled(bool)
92
440
98
542
intervalRefreshCB
toggled(bool)
intervalRefreshSB
setEnabled(bool)
282
243
334
245
diff --git a/src/crypto/autodecryptverifyfilescontroller.cpp b/src/crypto/autodecryptverifyfilescontroller.cpp
index adf9b4459..2f996002a 100644
--- a/src/crypto/autodecryptverifyfilescontroller.cpp
+++ b/src/crypto/autodecryptverifyfilescontroller.cpp
@@ -1,550 +1,550 @@
/* -*- mode: c++; c-basic-offset:4 -*-
autodecryptverifyfilescontroller.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2008 Klarälvdalens Datakonsult AB
2016 by Bundesamt für Sicherheit in der Informationstechnik
Software engineering by Intevation GmbH
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include
#include "autodecryptverifyfilescontroller.h"
#include "fileoperationspreferences.h"
#include
#include
#include
#include
#include "commands/decryptverifyfilescommand.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "kleopatra_debug.h"
#include
#include
#include
#include
#include
#include
#include
#include
using namespace GpgME;
using namespace Kleo;
using namespace Kleo::Crypto;
using namespace Kleo::Crypto::Gui;
class AutoDecryptVerifyFilesController::Private
{
AutoDecryptVerifyFilesController *const q;
public:
explicit Private(AutoDecryptVerifyFilesController *qq);
~Private() {
qCDebug(KLEOPATRA_LOG);
delete m_workDir;
}
void slotDialogCanceled();
void schedule();
void exec();
std::vector > buildTasks(const QStringList &, QStringList &);
struct CryptoFile {
QString baseName;
QString fileName;
GpgME::Protocol protocol = GpgME::UnknownProtocol;
int classification = 0;
std::shared_ptr output;
};
QVector classifyAndSortFiles(const QStringList &files);
void reportError(int err, const QString &details)
{
q->setLastError(err, details);
q->emitDoneOrError();
}
void cancelAllTasks();
QStringList m_passedFiles, m_filesAfterPreparation;
std::vector > m_results;
std::vector > m_runnableTasks, m_completedTasks;
std::shared_ptr m_runningTask;
bool m_errorDetected;
DecryptVerifyOperation m_operation;
DecryptVerifyFilesDialog *m_dialog;
QTemporaryDir *m_workDir;
};
AutoDecryptVerifyFilesController::Private::Private(AutoDecryptVerifyFilesController *qq) : q(qq),
m_errorDetected(false),
m_operation(DecryptVerify),
m_dialog(nullptr),
m_workDir(nullptr)
{
qRegisterMetaType();
}
void AutoDecryptVerifyFilesController::Private::slotDialogCanceled()
{
qCDebug(KLEOPATRA_LOG);
}
void AutoDecryptVerifyFilesController::Private::schedule()
{
if (!m_runningTask && !m_runnableTasks.empty()) {
const std::shared_ptr t = m_runnableTasks.back();
m_runnableTasks.pop_back();
t->start();
m_runningTask = t;
}
if (!m_runningTask) {
kleo_assert(m_runnableTasks.empty());
for (const std::shared_ptr &i : qAsConst(m_results)) {
Q_EMIT q->verificationResult(i->verificationResult());
}
}
}
void AutoDecryptVerifyFilesController::Private::exec()
{
Q_ASSERT(!m_dialog);
QStringList undetected;
std::vector > tasks = buildTasks(m_passedFiles, undetected);
if (!undetected.isEmpty()) {
// Since GpgME 1.7.0 Classification is supposed to be reliable
// so we really can't do anything with this data.
reportError(makeGnuPGError(GPG_ERR_GENERAL),
xi18n("Failed to find encrypted or signed data in one or more files. "
"You can manually select what to do with the files now. "
"If they contain signed or encrypted data please report a bug (see Help->Report Bug)."));
auto cmd = new Commands::DecryptVerifyFilesCommand(undetected, nullptr, true);
cmd->start();
}
if (tasks.empty()) {
q->emitDoneOrError();
return;
}
Q_ASSERT(m_runnableTasks.empty());
m_runnableTasks.swap(tasks);
std::shared_ptr coll(new TaskCollection);
Q_FOREACH (const std::shared_ptr &i, m_runnableTasks) {
q->connectTask(i);
}
coll->setTasks(m_runnableTasks);
m_dialog = new DecryptVerifyFilesDialog(coll);
m_dialog->setOutputLocation(heuristicBaseDirectory(m_passedFiles));
QTimer::singleShot(0, q, SLOT(schedule()));
if (m_dialog->exec() == QDialog::Accepted && m_workDir) {
// Without workdir there is nothing to move.
const QDir workdir(m_workDir->path());
const QDir outDir(m_dialog->outputLocation());
bool overWriteAll = false;
qCDebug(KLEOPATRA_LOG) << workdir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
for (const QFileInfo &fi: workdir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot)) {
const auto inpath = fi.absoluteFilePath();
if (fi.isDir()) {
// A directory. Assume that the input was an archive
// and avoid directory merges by trying to find a non
// existing directory.
auto candidate = fi.baseName();
if (candidate.startsWith(QLatin1Char('-'))) {
// Bug in GpgTar Extracts stdout passed archives to a dir named -
candidate = QFileInfo(m_passedFiles.first()).baseName();
}
QString suffix;
QFileInfo ofi;
int i = 0;
do {
ofi = QFileInfo(outDir.absoluteFilePath(candidate + suffix));
if (!ofi.exists()) {
break;
}
suffix = QStringLiteral("_%1").arg(++i);
} while (i < 1000);
if (!moveDir(inpath, ofi.absoluteFilePath())) {
reportError(makeGnuPGError(GPG_ERR_GENERAL),
xi18n("Failed to move %1 to %2 .",
inpath, ofi.absoluteFilePath()));
}
continue;
}
const auto outpath = outDir.absoluteFilePath(fi.fileName());
qCDebug(KLEOPATRA_LOG) << "Moving " << inpath << " to " << outpath;
const QFileInfo ofi(outpath);
if (ofi.exists()) {
int sel = KMessageBox::No;
if (!overWriteAll) {
sel = KMessageBox::questionYesNoCancel(m_dialog, i18n("The file %1 already exists.\n"
"Overwrite?", outpath),
i18n("Overwrite Existing File?"),
KStandardGuiItem::overwrite(),
KGuiItem(i18n("Overwrite All")),
KStandardGuiItem::cancel());
}
if (sel == KMessageBox::Cancel) {
qCDebug(KLEOPATRA_LOG) << "Overwriting canceled for: " << outpath;
continue;
}
if (sel == KMessageBox::No) { //Overwrite All
overWriteAll = true;
}
if (!QFile::remove(outpath)) {
reportError(makeGnuPGError(GPG_ERR_GENERAL),
xi18n("Failed to delete %1 .",
outpath));
continue;
}
}
if (!QFile::rename(inpath, outpath)) {
reportError(makeGnuPGError(GPG_ERR_GENERAL),
xi18n("Failed to move %1 to %2 .",
inpath, outpath));
}
}
}
q->emitDoneOrError();
delete m_dialog;
m_dialog = nullptr;
}
QVector AutoDecryptVerifyFilesController::Private::classifyAndSortFiles(const QStringList &files)
{
const auto isSignature = [](int classification) -> bool {
return mayBeDetachedSignature(classification)
|| mayBeOpaqueSignature(classification)
|| (classification & Class::TypeMask) == Class::ClearsignedMessage;
};
QVector out;
for (const auto &file : files) {
CryptoFile cFile;
cFile.fileName = file;
cFile.baseName = file.left(file.length() - 4);
cFile.classification = classify(file);
cFile.protocol = findProtocol(cFile.classification);
auto it = std::find_if(out.begin(), out.end(),
[&cFile](const CryptoFile &other) {
return other.protocol == cFile.protocol
&& other.baseName == cFile.baseName;
});
if (it != out.end()) {
// If we found a file with the same basename, make sure that encrypted
// file is before the signature file, so that we first decrypt and then
// verify
if (isSignature(cFile.classification) && isCipherText(it->classification)) {
out.insert(it + 1, cFile);
} else if (isCipherText(cFile.classification) && isSignature(it->classification)) {
out.insert(it, cFile);
} else {
// both are signatures or both are encrypted files, in which
// case order does not matter
out.insert(it, cFile);
}
} else {
out.push_back(cFile);
}
}
return out;
}
std::vector< std::shared_ptr > AutoDecryptVerifyFilesController::Private::buildTasks(const QStringList &fileNames, QStringList &undetected)
{
// sort files so that we make sure we first decrypt and then verify
QVector cryptoFiles = classifyAndSortFiles(fileNames);
std::vector > tasks;
for (auto it = cryptoFiles.begin(), end = cryptoFiles.end(); it != end; ++it) {
auto &cFile = (*it);
QFileInfo fi(cFile.fileName);
qCDebug(KLEOPATRA_LOG) << "classified" << cFile.fileName << "as" << printableClassification(cFile.classification);
if (!fi.isReadable()) {
reportError(makeGnuPGError(GPG_ERR_ASS_NO_INPUT),
xi18n("Cannot open %1 for reading.", cFile.fileName));
continue;
}
if (mayBeAnyCertStoreType(cFile.classification)) {
// Trying to verify a certificate. Possible because extensions are often similar
// for PGP Keys.
reportError(makeGnuPGError(GPG_ERR_ASS_NO_INPUT),
xi18n("The file %1 contains certificates and can't be decrypted or verified.", cFile.fileName));
qCDebug(KLEOPATRA_LOG) << "reported error";
continue;
}
// We can't reliably detect CMS detached signatures, so we will try to do
// our best to use the current file as a detached signature and fallback to
// opaque signature otherwise.
if (cFile.protocol == GpgME::CMS && mayBeDetachedSignature(cFile.classification)) {
// First, see if previous task was a decryption task for the same file
// and "pipe" it's output into our input
std::shared_ptr input;
bool prepend = false;
if (it != cryptoFiles.begin()) {
const auto prev = it - 1;
if (prev->protocol == cFile.protocol && prev->baseName == cFile.baseName) {
input = Input::createFromOutput(prev->output);
prepend = true;
}
}
if (!input) {
if (QFile::exists(cFile.baseName)) {
input = Input::createFromFile(cFile.baseName);
}
}
if (input) {
qCDebug(KLEOPATRA_LOG) << "Detached CMS verify: " << cFile.fileName;
std::shared_ptr t(new VerifyDetachedTask);
t->setInput(Input::createFromFile(cFile.fileName));
t->setSignedData(input);
t->setProtocol(cFile.protocol);
if (prepend) {
// Put the verify task BEFORE the decrypt task in the tasks queue,
// because the tasks are executed in reverse order!
tasks.insert(tasks.end() - 1, t);
} else {
tasks.push_back(t);
}
continue;
} else {
// No signed data, maybe not a detached signature
}
}
if (isDetachedSignature(cFile.classification)) {
// Detached signature, try to find data or ask the user.
QString signedDataFileName = cFile.baseName;
if (signedDataFileName.isEmpty()) {
signedDataFileName = QFileDialog::getOpenFileName(nullptr, xi18n("Select the file to verify with \"%1\"", fi.fileName()),
fi.dir().dirName());
}
if (signedDataFileName.isEmpty()) {
- qCDebug(KLEOPATRA_LOG) << "No signed data selected. Verify abortet.";
+ qCDebug(KLEOPATRA_LOG) << "No signed data selected. Verify aborted.";
} else {
qCDebug(KLEOPATRA_LOG) << "Detached verify: " << cFile.fileName << " Data: " << signedDataFileName;
std::shared_ptr t(new VerifyDetachedTask);
t->setInput(Input::createFromFile(cFile.fileName));
t->setSignedData(Input::createFromFile(signedDataFileName));
t->setProtocol(cFile.protocol);
tasks.push_back(t);
}
continue;
}
if (!mayBeAnyMessageType(cFile.classification)) {
// Not a Message? Maybe there is a signature for this file?
const auto signatures = findSignatures(cFile.fileName);
bool foundSig = false;
if (!signatures.empty()) {
for (const QString &sig : signatures) {
const auto classification = classify(sig);
qCDebug(KLEOPATRA_LOG) << "Guessing: " << sig << " is a signature for: " << cFile.fileName
<< "Classification: " << classification;
const auto proto = findProtocol(classification);
if (proto == GpgME::UnknownProtocol) {
qCDebug(KLEOPATRA_LOG) << "Could not determine protocol. Skipping guess.";
continue;
}
foundSig = true;
std::shared_ptr t(new VerifyDetachedTask);
t->setInput(Input::createFromFile(sig));
t->setSignedData(Input::createFromFile(cFile.fileName));
t->setProtocol(proto);
tasks.push_back(t);
}
}
if (!foundSig) {
undetected << cFile.fileName;
qCDebug(KLEOPATRA_LOG) << "Failed detection for: " << cFile.fileName << " adding to undetected.";
}
} else {
// Any Message type so we have input and output.
const auto input = Input::createFromFile(cFile.fileName);
const auto archiveDefinitions = ArchiveDefinition::getArchiveDefinitions();
const auto ad = q->pick_archive_definition(cFile.protocol, archiveDefinitions, cFile.fileName);
if (FileOperationsPreferences().dontUseTmpDir()) {
if (!m_workDir) {
m_workDir = new QTemporaryDir(heuristicBaseDirectory(fileNames) + QStringLiteral("/kleopatra-XXXXXX"));
}
if (!m_workDir->isValid()) {
qCDebug(KLEOPATRA_LOG) << m_workDir->path() << "not a valid temporary directory.";
delete m_workDir;
m_workDir = new QTemporaryDir();
}
} else if (!m_workDir) {
m_workDir = new QTemporaryDir();
}
qCDebug(KLEOPATRA_LOG) << "Using:" << m_workDir->path() << "as temporary directory.";
const auto wd = QDir(m_workDir->path());
const auto output =
ad ? ad->createOutputFromUnpackCommand(cFile.protocol, cFile.fileName, wd) :
/*else*/ Output::createFromFile(wd.absoluteFilePath(outputFileName(fi.fileName())), false);
// If this might be opaque CMS signature, then try that. We already handled
// detached CMS signature above
const auto isCMSOpaqueSignature = cFile.protocol == GpgME::CMS && mayBeOpaqueSignature(cFile.classification);
if (isOpaqueSignature(cFile.classification) || isCMSOpaqueSignature) {
qCDebug(KLEOPATRA_LOG) << "creating a VerifyOpaqueTask";
std::shared_ptr t(new VerifyOpaqueTask);
t->setInput(input);
t->setOutput(output);
t->setProtocol(cFile.protocol);
tasks.push_back(t);
} else {
// Any message. That is not an opaque signature needs to be
// decrypted. Verify we always do because we can't know if
// an encrypted message is also signed.
qCDebug(KLEOPATRA_LOG) << "creating a DecryptVerifyTask";
std::shared_ptr t(new DecryptVerifyTask);
t->setInput(input);
t->setOutput(output);
t->setProtocol(cFile.protocol);
cFile.output = output;
tasks.push_back(t);
}
}
}
return tasks;
}
void AutoDecryptVerifyFilesController::setFiles(const QStringList &files)
{
d->m_passedFiles = files;
}
AutoDecryptVerifyFilesController::AutoDecryptVerifyFilesController(QObject *parent) :
DecryptVerifyFilesController(parent), d(new Private(this))
{
}
AutoDecryptVerifyFilesController::AutoDecryptVerifyFilesController(const std::shared_ptr &ctx, QObject *parent) :
DecryptVerifyFilesController(ctx, parent), d(new Private(this))
{
}
AutoDecryptVerifyFilesController::~AutoDecryptVerifyFilesController()
{
qCDebug(KLEOPATRA_LOG);
}
void AutoDecryptVerifyFilesController::start()
{
d->exec();
}
void AutoDecryptVerifyFilesController::setOperation(DecryptVerifyOperation op)
{
d->m_operation = op;
}
DecryptVerifyOperation AutoDecryptVerifyFilesController::operation() const
{
return d->m_operation;
}
void AutoDecryptVerifyFilesController::Private::cancelAllTasks()
{
// we just kill all runnable tasks - this will not result in
// signal emissions.
m_runnableTasks.clear();
// a cancel() will result in a call to
if (m_runningTask) {
m_runningTask->cancel();
}
}
void AutoDecryptVerifyFilesController::cancel()
{
qCDebug(KLEOPATRA_LOG);
try {
d->m_errorDetected = true;
if (d->m_dialog) {
d->m_dialog->close();
}
d->cancelAllTasks();
} catch (const std::exception &e) {
qCDebug(KLEOPATRA_LOG) << "Caught exception: " << e.what();
}
}
void AutoDecryptVerifyFilesController::doTaskDone(const Task *task, const std::shared_ptr &result)
{
Q_ASSERT(task);
Q_UNUSED(task);
// We could just delete the tasks here, but we can't use
// Qt::QueuedConnection here (we need sender()) and other slots
// might not yet have executed. Therefore, we push completed tasks
// into a burial container
d->m_completedTasks.push_back(d->m_runningTask);
d->m_runningTask.reset();
if (const std::shared_ptr &dvr = std::dynamic_pointer_cast(result)) {
d->m_results.push_back(dvr);
}
QTimer::singleShot(0, this, SLOT(schedule()));
}
#include "moc_autodecryptverifyfilescontroller.cpp"
diff --git a/src/crypto/newsignencryptemailcontroller.cpp b/src/crypto/newsignencryptemailcontroller.cpp
index f8d06fd52..20b9410b5 100644
--- a/src/crypto/newsignencryptemailcontroller.cpp
+++ b/src/crypto/newsignencryptemailcontroller.cpp
@@ -1,655 +1,655 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/newsignencryptemailcontroller.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2009,2010 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include
#include "newsignencryptemailcontroller.h"
#include "kleopatra_debug.h"
#include "encryptemailtask.h"
#include "signemailtask.h"
#include "taskcollection.h"
#include "sender.h"
#include "recipient.h"
#include "emailoperationspreferences.h"
#include
#include "utils/input.h"
#include "utils/output.h"
#include "utils/gnupg-helper.h"
#include "utils/kleo_assert.h"
#include
#include
#include
#include
#include
#include
#include
#include
using namespace Kleo;
using namespace Kleo::Crypto;
using namespace Kleo::Crypto::Gui;
using namespace GpgME;
using namespace KMime::Types;
//
// BEGIN Conflict Detection
//
/*
- This code implements the following conflict detection algortihm:
+ This code implements the following conflict detection algorithm:
1. There is no conflict if and only if we have a Perfect Match.
2. A Perfect Match is defined as:
a. either a Perfect OpenPGP-Match and not even a Partial S/MIME Match
b. or a Perfect S/MIME-Match and not even a Partial OpenPGP-Match
c. or a Perfect OpenPGP-Match and preselected protocol=OpenPGP
d. or a Perfect S/MIME-Match and preselected protocol=S/MIME
3. For Protocol \in {OpenPGP,S/MIME}, a Perfect Protocol-Match is defined as:
a. If signing, \foreach Sender, there is exactly one
Matching Protocol-Certificate with
i. can-sign=true
ii. has-secret=true
b. and, if encrypting, \foreach Recipient, there is exactly one
Matching Protocol-Certificate with
i. can-encrypt=true
ii. (validity is not considered, cf. msg 24059)
4. For Protocol \in {OpenPGP,S/MIME}, a Partial Protocol-Match is defined as:
a. If signing, \foreach Sender, there is at least one
Matching Protocol-Certificate with
i. can-sign=true
ii. has-secret=true
b. and, if encrypting, \foreach Recipient, there is at least
one Matching Protocol-Certificate with
i. can-encrypt=true
ii. (validity is not considered, cf. msg 24059)
5. For Protocol \in {OpenPGP,S/MIME}, a Matching Protocol-Certificate is
defined as matching by email-address. A revoked, disabled, or expired
certificate is not considered a match.
6. Sender is defined as those mailboxes that have been set with the SENDER
command.
7. Recipient is defined as those mailboxes that have been set with either the
SENDER or the RECIPIENT commands.
*/
namespace
{
static size_t count_signing_certificates(Protocol proto, const Sender &sender)
{
const size_t result = sender.signingCertificateCandidates(proto).size();
qDebug("count_signing_certificates( %9s %20s ) == %2lu",
proto == OpenPGP ? "OpenPGP," : proto == CMS ? "CMS," : ",",
qPrintable(sender.mailbox().prettyAddress()), result);
return result;
}
static size_t count_encrypt_certificates(Protocol proto, const Sender &sender)
{
const size_t result = sender.encryptToSelfCertificateCandidates(proto).size();
qDebug("count_encrypt_certificates( %9s %20s ) == %2lu",
proto == OpenPGP ? "OpenPGP," : proto == CMS ? "CMS," : ",",
qPrintable(sender.mailbox().prettyAddress()), result);
return result;
}
static size_t count_encrypt_certificates(Protocol proto, const Recipient &recipient)
{ const size_t result = recipient.encryptionCertificateCandidates(proto).size();
qDebug("count_encrypt_certificates( %9s %20s ) == %2lu",
proto == OpenPGP ? "OpenPGP," : proto == CMS ? "CMS," : ",",
qPrintable(recipient.mailbox().prettyAddress()), result);
return result;
}
}
static bool has_perfect_match(bool sign, bool encrypt, Protocol proto, const std::vector &senders, const std::vector &recipients)
{
if (sign)
if (!std::all_of(senders.cbegin(), senders.cend(),
[proto](const Sender &sender) { return count_signing_certificates(proto, sender) == 1; })) {
return false;
}
if (encrypt)
if (!std::all_of(senders.cbegin(), senders.cend(),
[proto](const Sender &sender) { return count_encrypt_certificates(proto, sender) == 1; })
|| !std::all_of(recipients.cbegin(), recipients.cend(),
[proto](const Recipient &rec) { return count_encrypt_certificates(proto, rec) == 1; })) {
return false;
}
return true;
}
static bool has_partial_match(bool sign, bool encrypt, Protocol proto, const std::vector &senders, const std::vector &recipients)
{
if (sign)
if (std::all_of(senders.cbegin(), senders.cend(),
[proto](const Sender &sender) { return count_signing_certificates(proto, sender) >= 1; })) {
return false;
}
if (encrypt)
if (!std::all_of(senders.cbegin(), senders.cend(),
[proto](const Sender &sender) { return count_encrypt_certificates(proto, sender) >= 1; })
|| !std::all_of(recipients.cbegin(), recipients.cend(),
[proto](const Recipient &rec) { return count_encrypt_certificates(proto, rec) >= 1; })) {
return false;
}
return true;
}
static bool has_perfect_overall_match(bool sign, bool encrypt, const std::vector &senders, const std::vector &recipients, Protocol presetProtocol)
{
return (presetProtocol == OpenPGP && has_perfect_match(sign, encrypt, OpenPGP, senders, recipients))
|| (presetProtocol == CMS && has_perfect_match(sign, encrypt, CMS, senders, recipients))
|| (has_perfect_match(sign, encrypt, OpenPGP, senders, recipients) && !has_partial_match(sign, encrypt, CMS, senders, recipients))
|| (has_perfect_match(sign, encrypt, CMS, senders, recipients) && !has_partial_match(sign, encrypt, OpenPGP, senders, recipients));
}
static bool has_conflict(bool sign, bool encrypt, const std::vector &senders, const std::vector &recipients, Protocol presetProtocol)
{
return !has_perfect_overall_match(sign, encrypt, senders, recipients, presetProtocol);
}
static bool is_de_vs_compliant(bool sign, bool encrypt, const std::vector &senders, const std::vector &recipients, Protocol presetProtocol)
{
if (presetProtocol == Protocol::UnknownProtocol) {
return false;
}
if (sign) {
for (const auto &sender: senders) {
const auto &key = sender.resolvedSigningKey(presetProtocol);
if (!IS_DE_VS(key) || keyValidity(key) < GpgME::UserID::Validity::Full) {
return false;
}
}
}
if (encrypt) {
for (const auto &sender: senders) {
const auto &key = sender.resolvedSigningKey(presetProtocol);
if (!IS_DE_VS(key) || keyValidity(key) < GpgME::UserID::Validity::Full) {
return false;
}
}
for (const auto &recipient: recipients) {
const auto &key = recipient.resolvedEncryptionKey(presetProtocol);
if (!IS_DE_VS(key) || keyValidity(key) < GpgME::UserID::Validity::Full) {
return false;
}
}
}
return true;
}
//
// END Conflict Detection
//
static std::vector mailbox2sender(const std::vector &mbs)
{
std::vector senders;
senders.reserve(mbs.size());
for (const Mailbox &mb : mbs) {
senders.push_back(Sender(mb));
}
return senders;
}
static std::vector mailbox2recipient(const std::vector &mbs)
{
std::vector recipients;
recipients.reserve(mbs.size());
for (const Mailbox &mb : mbs) {
recipients.push_back(Recipient(mb));
}
return recipients;
}
class NewSignEncryptEMailController::Private
{
friend class ::Kleo::Crypto::NewSignEncryptEMailController;
NewSignEncryptEMailController *const q;
public:
explicit Private(NewSignEncryptEMailController *qq);
~Private();
private:
void slotDialogAccepted();
void slotDialogRejected();
private:
void ensureDialogVisible();
void cancelAllTasks();
void startSigning();
void startEncryption();
void schedule();
std::shared_ptr takeRunnable(GpgME::Protocol proto);
private:
bool sign : 1;
bool encrypt : 1;
bool resolvingInProgress : 1;
bool certificatesResolved : 1;
bool detached : 1;
Protocol presetProtocol;
std::vector signers, recipients;
std::vector< std::shared_ptr > runnable, completed;
std::shared_ptr cms, openpgp;
QPointer dialog;
};
NewSignEncryptEMailController::Private::Private(NewSignEncryptEMailController *qq)
: q(qq),
sign(false),
encrypt(false),
resolvingInProgress(false),
certificatesResolved(false),
detached(false),
presetProtocol(UnknownProtocol),
signers(),
recipients(),
runnable(),
cms(),
openpgp(),
dialog(new SignEncryptEMailConflictDialog)
{
connect(dialog, SIGNAL(accepted()), q, SLOT(slotDialogAccepted()));
connect(dialog, SIGNAL(rejected()), q, SLOT(slotDialogRejected()));
}
NewSignEncryptEMailController::Private::~Private()
{
delete dialog;
}
NewSignEncryptEMailController::NewSignEncryptEMailController(const std::shared_ptr &xc, QObject *p)
: Controller(xc, p), d(new Private(this))
{
}
NewSignEncryptEMailController::NewSignEncryptEMailController(QObject *p)
: Controller(p), d(new Private(this))
{
}
NewSignEncryptEMailController::~NewSignEncryptEMailController()
{
qCDebug(KLEOPATRA_LOG);
}
void NewSignEncryptEMailController::setSubject(const QString &subject)
{
d->dialog->setSubject(subject);
}
void NewSignEncryptEMailController::setProtocol(Protocol proto)
{
d->presetProtocol = proto;
d->dialog->setPresetProtocol(proto);
}
Protocol NewSignEncryptEMailController::protocol() const
{
return d->dialog->selectedProtocol();
}
const char *NewSignEncryptEMailController::protocolAsString() const
{
switch (protocol()) {
case OpenPGP: return "OpenPGP";
case CMS: return "CMS";
default:
throw Kleo::Exception(gpg_error(GPG_ERR_INTERNAL),
i18n("Call to NewSignEncryptEMailController::protocolAsString() is ambiguous."));
}
}
void NewSignEncryptEMailController::setSigning(bool sign)
{
d->sign = sign;
d->dialog->setSign(sign);
}
bool NewSignEncryptEMailController::isSigning() const
{
return d->sign;
}
void NewSignEncryptEMailController::setEncrypting(bool encrypt)
{
d->encrypt = encrypt;
d->dialog->setEncrypt(encrypt);
}
bool NewSignEncryptEMailController::isEncrypting() const
{
return d->encrypt;
}
void NewSignEncryptEMailController::setDetachedSignature(bool detached)
{
d->detached = detached;
}
bool NewSignEncryptEMailController::isResolvingInProgress() const
{
return d->resolvingInProgress;
}
bool NewSignEncryptEMailController::areCertificatesResolved() const
{
return d->certificatesResolved;
}
static bool is_dialog_quick_mode(bool sign, bool encrypt)
{
const EMailOperationsPreferences prefs;
return (!sign || prefs.quickSignEMail())
&& (!encrypt || prefs.quickEncryptEMail())
;
}
static void save_dialog_quick_mode(bool on)
{
EMailOperationsPreferences prefs;
prefs.setQuickSignEMail(on);
prefs.setQuickEncryptEMail(on);
prefs.save();
}
void NewSignEncryptEMailController::startResolveCertificates(const std::vector &r, const std::vector &s)
{
d->certificatesResolved = false;
d->resolvingInProgress = true;
const std::vector senders = mailbox2sender(s);
const std::vector recipients = mailbox2recipient(r);
const bool quickMode = is_dialog_quick_mode(d->sign, d->encrypt);
const bool conflict = quickMode && has_conflict(d->sign, d->encrypt, senders, recipients, d->presetProtocol);
d->dialog->setQuickMode(quickMode);
d->dialog->setSenders(senders);
d->dialog->setRecipients(recipients);
d->dialog->pickProtocol();
d->dialog->setConflict(conflict);
const bool compliant = !Kleo::gpgComplianceP("de-vs") || is_de_vs_compliant(d->sign,
d->encrypt,
senders,
recipients,
d->presetProtocol);
if (quickMode && !conflict && compliant) {
QMetaObject::invokeMethod(this, "slotDialogAccepted", Qt::QueuedConnection);
} else {
d->ensureDialogVisible();
}
}
void NewSignEncryptEMailController::Private::slotDialogAccepted()
{
if (dialog->isQuickMode() != is_dialog_quick_mode(sign, encrypt)) {
save_dialog_quick_mode(dialog->isQuickMode());
}
resolvingInProgress = false;
certificatesResolved = true;
signers = dialog->resolvedSigningKeys();
recipients = dialog->resolvedEncryptionKeys();
QMetaObject::invokeMethod(q, "certificatesResolved", Qt::QueuedConnection);
}
void NewSignEncryptEMailController::Private::slotDialogRejected()
{
resolvingInProgress = false;
certificatesResolved = false;
QMetaObject::invokeMethod(q, "error", Qt::QueuedConnection,
Q_ARG(int, gpg_error(GPG_ERR_CANCELED)),
Q_ARG(QString, i18n("User cancel")));
}
void NewSignEncryptEMailController::startEncryption(const std::vector< std::shared_ptr > &inputs, const std::vector< std::shared_ptr > &outputs)
{
kleo_assert(d->encrypt);
kleo_assert(!d->resolvingInProgress);
kleo_assert(!inputs.empty());
kleo_assert(outputs.size() == inputs.size());
std::vector< std::shared_ptr > tasks;
tasks.reserve(inputs.size());
kleo_assert(!d->recipients.empty());
for (unsigned int i = 0, end = inputs.size(); i < end; ++i) {
const std::shared_ptr task(new EncryptEMailTask);
task->setInput(inputs[i]);
task->setOutput(outputs[i]);
task->setRecipients(d->recipients);
tasks.push_back(task);
}
// append to runnable stack
d->runnable.insert(d->runnable.end(), tasks.begin(), tasks.end());
d->startEncryption();
}
void NewSignEncryptEMailController::Private::startEncryption()
{
std::shared_ptr coll(new TaskCollection);
std::vector > tmp;
tmp.reserve(runnable.size());
std::copy(runnable.cbegin(), runnable.cend(), std::back_inserter(tmp));
coll->setTasks(tmp);
#if 0
#warning use a new result dialog
// ### use a new result dialog
dialog->setTaskCollection(coll);
#endif
Q_FOREACH (const std::shared_ptr &t, tmp) {
q->connectTask(t);
}
schedule();
}
void NewSignEncryptEMailController::startSigning(const std::vector< std::shared_ptr > &inputs, const std::vector< std::shared_ptr > &outputs)
{
kleo_assert(d->sign);
kleo_assert(!d->resolvingInProgress);
kleo_assert(!inputs.empty());
kleo_assert(!outputs.empty());
std::vector< std::shared_ptr > tasks;
tasks.reserve(inputs.size());
kleo_assert(!d->signers.empty());
kleo_assert(std::none_of(d->signers.cbegin(), d->signers.cend(), std::mem_fn(&Key::isNull)));
for (unsigned int i = 0, end = inputs.size(); i < end; ++i) {
const std::shared_ptr task(new SignEMailTask);
task->setInput(inputs[i]);
task->setOutput(outputs[i]);
task->setSigners(d->signers);
task->setDetachedSignature(d->detached);
tasks.push_back(task);
}
// append to runnable stack
d->runnable.insert(d->runnable.end(), tasks.begin(), tasks.end());
d->startSigning();
}
void NewSignEncryptEMailController::Private::startSigning()
{
std::shared_ptr coll(new TaskCollection);
std::vector > tmp;
tmp.reserve(runnable.size());
std::copy(runnable.cbegin(), runnable.cend(), std::back_inserter(tmp));
coll->setTasks(tmp);
#if 0
#warning use a new result dialog
// ### use a new result dialog
dialog->setTaskCollection(coll);
#endif
Q_FOREACH (const std::shared_ptr &t, tmp) {
q->connectTask(t);
}
schedule();
}
void NewSignEncryptEMailController::Private::schedule()
{
if (!cms)
if (const std::shared_ptr t = takeRunnable(CMS)) {
t->start();
cms = t;
}
if (!openpgp)
if (const std::shared_ptr t = takeRunnable(OpenPGP)) {
t->start();
openpgp = t;
}
if (cms || openpgp) {
return;
}
kleo_assert(runnable.empty());
q->emitDoneOrError();
}
std::shared_ptr NewSignEncryptEMailController::Private::takeRunnable(GpgME::Protocol proto)
{
const auto it = std::find_if(runnable.begin(), runnable.end(),
[proto](const std::shared_ptr &task) { return task->protocol() == proto; });
if (it == runnable.end()) {
return std::shared_ptr();
}
const std::shared_ptr result = *it;
runnable.erase(it);
return result;
}
void NewSignEncryptEMailController::doTaskDone(const Task *task, const std::shared_ptr &result)
{
Q_ASSERT(task);
if (result && result->hasError()) {
QPointer that = this;
if (result->details().isEmpty())
KMessageBox:: sorry(nullptr,
result->overview(),
i18nc("@title:window", "Error"));
else
KMessageBox::detailedSorry(nullptr,
result->overview(),
result->details(),
i18nc("@title:window", "Error"));
if (!that) {
return;
}
}
// 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 NewSignEncryptEMailController::cancel()
{
try {
d->dialog->close();
d->cancelAllTasks();
} catch (const std::exception &e) {
qCDebug(KLEOPATRA_LOG) << "Caught exception: " << e.what();
}
}
void NewSignEncryptEMailController::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 NewSignEncryptEMailController::Private::ensureDialogVisible()
{
q->bringToForeground(dialog, true);
}
#include "moc_newsignencryptemailcontroller.cpp"
diff --git a/src/dialogs/ownertrustdialog.ui b/src/dialogs/ownertrustdialog.ui
index 1f60fa9eb..286ad1619 100644
--- a/src/dialogs/ownertrustdialog.ui
+++ b/src/dialogs/ownertrustdialog.ui
@@ -1,496 +1,496 @@
OwnerTrustDialog
0
0
700
380
QLayout::SetMinimumSize
-
true
-
-
I do not know
true
-
true
<i>(unknown trust)</i>
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
Qt::Horizontal
QSizePolicy::Fixed
20
20
-
true
<font size="-1">Choose this if you have no opinion about the trustworthyness of the certificate's owner.<br>Certifications at this trust level are ignored when checking the validity of OpenPGP certificates.</font>
true
-
-
I do NOT trust them
-
false
<i>(never trust)</i>
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
Qt::Horizontal
QSizePolicy::Fixed
20
20
-
false
<font size="-1">Choose this if you explicitly do <em>not</em> trust the certificate owner, e.g. because you have knowledge of him certifying without checking or without the certificate owner's consent.<br>Certifications at this trust level are ignored when checking the validity of OpenPGP certificates.</font>
true
-
-
I believe checks are casual
-
false
<i>(marginal trust)</i>
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
Qt::Horizontal
QSizePolicy::Fixed
20
20
-
false
- <font size="-1">Choose this if you trust certifications are not done blindly, but not very accuratly, either.<br>Certificates will only become valid with multiple certifications (typically three) at this trust level. This is usually a good choice.</font>
+ <font size="-1">Choose this if you trust certifications are not done blindly, but not very accurately, either.<br>Certificates will only become valid with multiple certifications (typically three) at this trust level. This is usually a good choice.</font>
true
-
-
I believe checks are very accurate
-
false
<i>(full trust)</i>
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
Qt::Horizontal
QSizePolicy::Fixed
20
20
-
false
<font size="-1">Choose this if you trust certifications are done very accurately.<br>Certificates will become valid with just a single certification at this trust level, so assign this much trust with care.</font>
true
-
-
false
This is my certificate
-
false
<i>(ultimate trust)</i>
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
Qt::Horizontal
QSizePolicy::Fixed
20
20
-
false
<font size="-1">Choose this if and only if this is your certificate. This is the default if the secret key is available, but if you imported this certificate, you might need to adjust the trust level yourself.<br>Certificates will become valid with just a single certification at this trust level.</font>
true
-
Qt::Vertical
501
40
unknownRB
toggled(bool)
label_2
setEnabled(bool)
258
50
282
82
neverRB
toggled(bool)
label_3
setEnabled(bool)
227
111
279
155
marginalRB
toggled(bool)
label_4
setEnabled(bool)
267
184
321
216
fullRB
toggled(bool)
label_5
setEnabled(bool)
321
245
381
277
ultimateRB
toggled(bool)
label_6
setEnabled(bool)
227
306
283
350
unknownRB
toggled(bool)
label_7
setEnabled(bool)
317
46
689
50
neverRB
toggled(bool)
label_8
setEnabled(bool)
329
111
689
111
marginalRB
toggled(bool)
label_9
setEnabled(bool)
331
184
689
184
fullRB
toggled(bool)
label_10
setEnabled(bool)
333
245
689
245
ultimateRB
toggled(bool)
label_11
setEnabled(bool)
335
306
689
306
slotTrustLevelChanged()
diff --git a/src/kcfg/smimevalidationpreferences.kcfg b/src/kcfg/smimevalidationpreferences.kcfg
index f905255a7..c6cae61ba 100644
--- a/src/kcfg/smimevalidationpreferences.kcfg
+++ b/src/kcfg/smimevalidationpreferences.kcfg
@@ -1,12 +1,12 @@
Certificate refresh interval (in hours). Zero (0) disables.
- This option enables interval checking of certificate validity. You can also choose the checking interval (in hours). Note that validation is perfomed implicitly whenever significant files in ~/.gnupg change. This option therefore only affects external factors of certificate validity.
+ This option enables interval checking of certificate validity. You can also choose the checking interval (in hours). Note that validation is performed implicitly whenever significant files in ~/.gnupg change. This option therefore only affects external factors of certificate validity.
1
24
diff --git a/src/main.cpp b/src/main.cpp
index 6d5bbdcf6..64ee20d53 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,264 +1,264 @@
/*
main.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2001,2002,2004,2008 Klarävdalens 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
#include "aboutdata.h"
#include "kleopatraapplication.h"
#include "mainwindow.h"
#include
#include
#include
#include
#include
#include "utils/kuniqueservice.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "kleopatra_debug.h"
#include "kleopatra_options.h"
#include
#include
#include
#include
#include // for Qt::escape
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static bool selfCheck()
{
Kleo::Commands::SelfTestCommand cmd(nullptr);
cmd.setAutoDelete(false);
cmd.setAutomaticMode(true);
QEventLoop loop;
QObject::connect(&cmd, &Kleo::Commands::SelfTestCommand::finished, &loop, &QEventLoop::quit);
QTimer::singleShot(0, &cmd, &Kleo::Command::start); // start() may Q_EMIT finished()...
loop.exec();
if (cmd.isCanceled()) {
return false;
} else {
return true;
}
}
static void fillKeyCache(Kleo::UiServer *server)
{
Kleo::ReloadKeysCommand *cmd = new Kleo::ReloadKeysCommand(nullptr);
QObject::connect(cmd, SIGNAL(finished()), server, SLOT(enableCryptoCommands()));
cmd->start();
}
int main(int argc, char **argv)
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true);
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true);
KleopatraApplication app(argc, argv);
KCrash::initialize();
QTime timer;
timer.start();
KLocalizedString::setApplicationDomain("kleopatra");
KUniqueService service;
QObject::connect(&service, &KUniqueService::activateRequested,
&app, &KleopatraApplication::slotActivateRequested);
QObject::connect(&app, &KleopatraApplication::setExitValue,
&service, [&service](int i) {
service.setExitValue(i);
});
// Delay init after KUniqueservice call as this might already
// have terminated us and so we can avoid overhead (e.g. keycache
// setup / systray icon).
qCDebug(KLEOPATRA_LOG) << "Startup timing:" << timer.elapsed() << "ms elapsed: Service created";
app.init();
qCDebug(KLEOPATRA_LOG) << "Startup timing:" << timer.elapsed() << "ms elapsed: Application initialized";
AboutData aboutData;
KAboutData::setApplicationData(aboutData);
QCommandLineParser parser;
aboutData.setupCommandLine(&parser);
kleopatra_options(&parser);
parser.process(QApplication::arguments());
aboutData.processCommandLine(&parser);
Kdelibs4ConfigMigrator migrate(QStringLiteral("kleopatra"));
migrate.setConfigFiles(QStringList() << QStringLiteral("kleopatrarc")
<< QStringLiteral("libkleopatrarc"));
migrate.setUiFiles(QStringList() << QStringLiteral("kleopatra.rc"));
migrate.migrate();
qCDebug(KLEOPATRA_LOG) << "Startup timing:" << timer.elapsed() << "ms elapsed: Application created";
// Initialize GpgME
const GpgME::Error gpgmeInitError = GpgME::initializeLibrary(0);
{
const unsigned int threads = QThreadPool::globalInstance()->maxThreadCount();
QThreadPool::globalInstance()->setMaxThreadCount(qMax(2U, threads));
}
if (gpgmeInitError) {
KMessageBox::sorry(nullptr, xi18nc("@info",
"The version of the GpgME library you are running against "
"is older than the one that the GpgME++ library was built against. "
"Kleopatra will not function in this setting. "
"Please ask your administrator for help in resolving this issue. "),
i18nc("@title", "GpgME Too Old"));
return EXIT_FAILURE;
}
- qCDebug(KLEOPATRA_LOG) << "Startup timing:" << timer.elapsed() << "ms elapsed: GPGME Initalized";
+ qCDebug(KLEOPATRA_LOG) << "Startup timing:" << timer.elapsed() << "ms elapsed: GPGME Initialized";
Kleo::ChecksumDefinition::setInstallPath(Kleo::gpg4winInstallPath());
Kleo::ArchiveDefinition::setInstallPath(Kleo::gnupgInstallPath());
int rc;
Kleo::UiServer server(parser.value(QStringLiteral("uiserver-socket")));
try {
qCDebug(KLEOPATRA_LOG) << "Startup timing:" << timer.elapsed() << "ms elapsed: UiServer created";
QObject::connect(&server, &Kleo::UiServer::startKeyManagerRequested, &app, &KleopatraApplication::openOrRaiseMainWindow);
QObject::connect(&server, &Kleo::UiServer::startConfigDialogRequested, &app, &KleopatraApplication::openOrRaiseConfigDialog);
#define REGISTER( Command ) server.registerCommandFactory( std::shared_ptr( new Kleo::GenericAssuanCommandFactory ) )
REGISTER(CreateChecksumsCommand);
REGISTER(DecryptCommand);
REGISTER(DecryptFilesCommand);
REGISTER(DecryptVerifyFilesCommand);
REGISTER(EchoCommand);
REGISTER(EncryptCommand);
REGISTER(EncryptFilesCommand);
REGISTER(EncryptSignFilesCommand);
REGISTER(ImportFilesCommand);
REGISTER(PrepEncryptCommand);
REGISTER(PrepSignCommand);
REGISTER(SelectCertificateCommand);
REGISTER(SignCommand);
REGISTER(SignEncryptFilesCommand);
REGISTER(SignFilesCommand);
REGISTER(VerifyChecksumsCommand);
REGISTER(VerifyCommand);
REGISTER(VerifyFilesCommand);
#undef REGISTER
server.start();
qCDebug(KLEOPATRA_LOG) << "Startup timing:" << timer.elapsed() << "ms elapsed: UiServer started";
} catch (const std::exception &e) {
qCDebug(KLEOPATRA_LOG) << "Failed to start UI Server: " << e.what();
#ifdef Q_OS_WIN
// Once there actually is a plugin for other systems then Windows this
// error should probably be shown, too. But currently only Windows users need
// to care.
QMessageBox::information(nullptr, i18n("GPG UI Server Error"),
i18n("The Kleopatra GPG UI Server Module could not be initialized. "
"The error given was: %1 "
"You can use Kleopatra as a certificate manager, but cryptographic plugins that "
"rely on a GPG UI Server being present might not work correctly, or at all. ",
QString::fromUtf8(e.what()).toHtmlEscaped()));
#endif
}
const bool daemon = parser.isSet(QStringLiteral("daemon"));
if (!daemon && app.isSessionRestored()) {
app.restoreMainWindow();
}
if (!selfCheck()) {
return EXIT_FAILURE;
}
qCDebug(KLEOPATRA_LOG) << "Startup timing:" << timer.elapsed() << "ms elapsed: SelfCheck completed";
fillKeyCache(&server);
#ifndef QT_NO_SYSTEMTRAYICON
app.startMonitoringSmartCard();
#endif
app.setIgnoreNewInstance(false);
if (!daemon) {
const QString err = app.newInstance(parser);
if (!err.isEmpty()) {
std::cerr << i18n("Invalid arguments: %1", err).toLocal8Bit().constData() << "\n";
return EXIT_FAILURE;
}
qCDebug(KLEOPATRA_LOG) << "Startup timing:" << timer.elapsed() << "ms elapsed: new instance created";
}
rc = app.exec();
app.setIgnoreNewInstance(true);
QObject::disconnect(&server, &Kleo::UiServer::startKeyManagerRequested, &app, &KleopatraApplication::openOrRaiseMainWindow);
QObject::disconnect(&server, &Kleo::UiServer::startConfigDialogRequested, &app, &KleopatraApplication::openOrRaiseConfigDialog);
server.stop();
server.waitForStopped();
return rc;
}
diff --git a/src/selftest/enginecheck.cpp b/src/selftest/enginecheck.cpp
index c429fc49e..9bb2349c1 100644
--- a/src/selftest/enginecheck.cpp
+++ b/src/selftest/enginecheck.cpp
@@ -1,216 +1,216 @@
/* -*- mode: c++; c-basic-offset:4 -*-
selftest/enginecheck.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2008 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include
#include "enginecheck.h"
#include "utils/gnupg-helper.h"
#include "implementation_p.h"
#include
#include
#include
#include
#include
#include "kleopatra_debug.h"
#include
#include
#include
#include
using namespace Kleo;
using namespace Kleo::_detail;
using namespace GpgME;
static QString engine_name(GpgME::Engine eng)
{
static const char *engines[] = {
"gpg", "gpgsm", "gpgconf"
};
return QString::fromLatin1(engines[eng]);
}
static QString test_name(GpgME::Engine eng)
{
static const char *names[] = {
I18NC_NOOP("@title", "GPG (OpenPGP Backend) installation"),
I18NC_NOOP("@title", "GpgSM (S/MIME Backend) installation"),
I18NC_NOOP("@title", "GpgConf (Configuration) installation"),
};
return i18nc("@title", names[eng]);
}
namespace
{
class EngineCheck : public SelfTestImplementation
{
public:
explicit EngineCheck(GpgME::Engine eng)
: SelfTestImplementation(test_name(eng))
{
runTest(eng);
}
void runTest(GpgME::Engine eng)
{
// First use the crypto config which is much faster because it is only
// created once and then kept in memory. Only if the crypoconfig is
// bad we check into the engine info.
const auto conf = QGpgME::cryptoConfig();
if (conf && eng == GpgME::GpgEngine) {
m_passed = true;
return;
} else if (conf) {
const auto comp = conf->component(engine_name(eng));
if (comp) {
m_passed = true;
return;
}
}
// Problem with the config. Try to get more details:
const Error err = GpgME::checkEngine(eng);
Q_ASSERT(!err.code() || err.code() == GPG_ERR_INV_ENGINE);
m_passed = !err;
if (m_passed) {
return;
}
- m_explaination = xi18nc("@info",
+ m_explanation = xi18nc("@info",
"A problem was detected with the %1 backend. ",
engine_name(eng));
const EngineInfo ei = engineInfo(eng);
if (ei.isNull()) {
m_error = i18n("not supported");
- m_explaination += xi18nc("@info",
+ m_explanation += xi18nc("@info",
"It seems that the gpgme library was compiled without "
"support for this backend. ");
m_proposedFix += xi18nc("@info",
"Replace the gpgme library with a version compiled "
"with %1 support. ",
engine_name(eng));
} else if (ei.fileName() && (!ei.version() || !strcmp(ei.version(), "1.0.0"))) {
// GPGSM only got the ei.version() working with 1.0.0 so 1.0.0 is returned as
// a fallback if the version could not be checked. We assume that it's not properly
// installed in that case.
m_error = i18n("not properly installed");
- m_explaination += xi18nc("@info",
+ m_explanation += xi18nc("@info",
"Backend %1 is not installed properly. ", QFile::decodeName(ei.fileName()));
m_proposedFix += xi18nc("@info",
"Please check the output of %1 --version manually. ",
QFile::decodeName(ei.fileName()));
} else if (ei.fileName() && ei.version() && ei.requiredVersion()) {
m_error = i18n("too old");
- m_explaination += xi18nc("@info",
+ m_explanation += xi18nc("@info",
"Backend %1 is installed in version %2, "
"but at least version %3 is required. ",
QFile::decodeName(ei.fileName()),
QString::fromUtf8(ei.version()),
QString::fromUtf8(ei.requiredVersion()));
m_proposedFix += xi18nc("@info",
"Install %1 version %2 or higher. ",
engine_name(eng), QString::fromUtf8(ei.requiredVersion()));
} else {
- m_error = m_explaination = i18n("unknown problem");
+ m_error = m_explanation = i18n("unknown problem");
m_proposedFix += xi18nc("@info",
"Make sure %1 is installed and "
"in PATH . ",
engine_name(eng));
}
}
};
}
std::shared_ptr Kleo::makeGpgEngineCheckSelfTest()
{
return std::shared_ptr(new EngineCheck(GpgME::GpgEngine));
}
std::shared_ptr Kleo::makeGpgSmEngineCheckSelfTest()
{
return std::shared_ptr(new EngineCheck(GpgME::GpgSMEngine));
}
std::shared_ptr Kleo::makeGpgConfEngineCheckSelfTest()
{
return std::shared_ptr(new EngineCheck(GpgME::GpgConfEngine));
}
//
// SelfTestImplementation (parts)
//
bool SelfTestImplementation::ensureEngineVersion(GpgME::Engine engine, int major, int minor, int patch)
{
const Error err = GpgME::checkEngine(engine);
Q_ASSERT(!err || err.code() == GPG_ERR_INV_ENGINE);
m_skipped = err || !engineIsVersion(major, minor, patch, engine);
if (!m_skipped) {
return true;
}
const char *version = GpgME::engineInfo(engine).version();
if (!err && version) {
// properly installed, but too old
- m_explaination = xi18nc("@info",
+ m_explanation = xi18nc("@info",
"%1 v%2.%3.%4 is required for this test, but only %5 is installed. ",
engine_name(engine), major, minor, patch, QString::fromUtf8(version));
m_proposedFix += xi18nc("@info",
"Install %1 version %2 or higher. ",
engine_name(engine), QStringLiteral("%1.%2.%3").arg(major).arg(minor).arg(patch));
} else {
// not properly installed
- m_explaination = xi18nc("@info",
+ m_explanation = xi18nc("@info",
"%1 is required for this test, but does not seem available. "
"See tests further up for more information. ",
engine_name(engine));
m_proposedFix = xi18nc("@info %1: test name",
"See \"%1\" above. ", test_name(engine));
}
return false;
}
diff --git a/src/selftest/gpgagentcheck.cpp b/src/selftest/gpgagentcheck.cpp
index f25acae2f..aeb72fc47 100644
--- a/src/selftest/gpgagentcheck.cpp
+++ b/src/selftest/gpgagentcheck.cpp
@@ -1,123 +1,123 @@
/* -*- mode: c++; c-basic-offset:4 -*-
selftest/gpgagentcheck.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2009 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include
#include "gpgagentcheck.h"
#include "implementation_p.h"
#include
#include
#include // for Qt::escape
#include
using namespace Kleo;
using namespace Kleo::_detail;
using namespace GpgME;
namespace
{
class GpgAgentCheck : public SelfTestImplementation
{
public:
explicit GpgAgentCheck()
: SelfTestImplementation(i18nc("@title", "Gpg-Agent Connectivity"))
{
runTest();
}
void runTest()
{
m_skipped = true;
if (!hasFeature(AssuanEngineFeature, 0)) {
m_error = i18n("GpgME library too old");
- m_explaination = i18nc("@info",
+ m_explanation = i18nc("@info",
"Either the GpgME library itself is too old, "
"or the GpgME++ library was compiled against "
"an older GpgME that did not support connecting to gpg-agent.");
m_proposedFix = xi18nc("@info",
"Upgrade to gpgme 1.2.0 or higher, "
"and ensure that gpgme++ was compiled against it.");
} else if (ensureEngineVersion(GpgME::GpgConfEngine, 2, 1, 0)) {
// 2.1 starts the agent on demand and requires it. So for 2.1.0 we can assume
// autostart works and we don't need to care about the agent.
m_skipped = false;
m_passed = true;
return;
} else {
Error error;
const std::unique_ptr ctx = Context::createForEngine(AssuanEngine, &error);
if (!ctx.get()) {
m_error = i18n("GpgME does not support gpg-agent");
- m_explaination = xi18nc("@info",
+ m_explanation = xi18nc("@info",
"The GpgME library is new "
"enough to support gpg-agent , "
"but does not seem to do so in this installation. "
"The error returned was: %1 . ",
QString::fromLocal8Bit(error.asString()).toHtmlEscaped());
// PENDING(marc) proposed fix?
} else {
m_skipped = false;
const Error error = ctx->assuanTransact("GETINFO version");
if (error) {
m_passed = false;
m_error = i18n("unexpected error");
- m_explaination = xi18nc("@info",
+ m_explanation = xi18nc("@info",
"Unexpected error while asking gpg-agent "
"for its version. "
"The error returned was: %1 . ",
QString::fromLocal8Bit(error.asString()).toHtmlEscaped());
// PENDING(marc) proposed fix?
} else {
m_passed = true;
}
}
}
}
};
}
std::shared_ptr Kleo::makeGpgAgentConnectivitySelfTest()
{
return std::shared_ptr(new GpgAgentCheck);
}
diff --git a/src/selftest/gpgconfcheck.cpp b/src/selftest/gpgconfcheck.cpp
index 1e26552ce..5a60f7be3 100644
--- a/src/selftest/gpgconfcheck.cpp
+++ b/src/selftest/gpgconfcheck.cpp
@@ -1,112 +1,112 @@
/* -*- mode: c++; c-basic-offset:4 -*-
selftest/gpgconfcheck.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2008 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include
#include "gpgconfcheck.h"
#include "implementation_p.h"
#include
#include
#include "kleopatra_debug.h"
#include
#include
#include
using namespace Kleo;
using namespace Kleo::_detail;
namespace
{
class GpgConfCheck : public SelfTestImplementation
{
QString m_component;
public:
explicit GpgConfCheck(const char *component)
: SelfTestImplementation(i18nc("@title", "%1 Configuration Check", component && * component ? QLatin1String(component) : QLatin1String("gpgconf"))),
m_component(QLatin1String(component))
{
runTest();
}
void runTest()
{
const auto conf = QGpgME::cryptoConfig();
QString message;
m_passed = true;
if (!conf) {
message = QStringLiteral ("Could not be started.");
m_passed = false;
} else if (m_component.isEmpty() && conf->componentList().empty()) {
message = QStringLiteral ("Could not list components.");
m_passed = false;
} else if (!m_component.isEmpty()) {
const auto comp = conf->component (m_component);
if (!comp) {
message = QStringLiteral ("Binary could not be found.");
m_passed = false;
} else if (comp->groupList().empty()) {
// If we don't have any group it means that list-options
// for this component failed.
message = QStringLiteral ("The configuration file is invalid.");
m_passed = false;
}
}
if (!m_passed) {
m_error = i18nc("self-test did not pass", "Failed");
- m_explaination =
+ m_explanation =
i18n("There was an error executing the GnuPG configuration self-check for %2:\n"
" %1\n"
"You might want to execute \"gpgconf %3\" on the command line.\n",
message, m_component.isEmpty() ? QStringLiteral("GnuPG") : m_component,
QStringLiteral("--check-options ") + (m_component.isEmpty() ? QStringLiteral("") : m_component));
// To avoid modifying the l10n
- m_explaination.replace(QLatin1Char('\n'), QStringLiteral(" "));
+ m_explanation.replace(QLatin1Char('\n'), QStringLiteral(" "));
}
}
};
}
std::shared_ptr Kleo::makeGpgConfCheckConfigurationSelfTest(const char *component)
{
return std::shared_ptr(new GpgConfCheck(component));
}
diff --git a/src/selftest/implementation_p.h b/src/selftest/implementation_p.h
index 21832dd8b..1e85b3146 100644
--- a/src/selftest/implementation_p.h
+++ b/src/selftest/implementation_p.h
@@ -1,94 +1,94 @@
/* -*- mode: c++; c-basic-offset:4 -*-
selftest/implementation_p.h
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2008 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#ifndef __KLEOPATRA_SELFTEST_IMPLEMENTATION_P_H__
#define __KLEOPATRA_SELFTEST_IMPLEMENTATION_P_H__
#include
#include
#include
namespace Kleo
{
namespace _detail
{
class SelfTestImplementation : public SelfTest
{
public:
explicit SelfTestImplementation(const QString &name);
~SelfTestImplementation() override;
QString name() const override
{
return m_name;
}
QString shortError() const override
{
return m_error;
}
QString longError() const override
{
- return m_explaination;
+ return m_explanation;
}
QString proposedFix() const override
{
return m_proposedFix;
}
bool skipped() const override
{
return m_skipped;
}
bool passed() const override
{
return m_passed;
}
protected:
bool ensureEngineVersion(GpgME::Engine, int major, int minor, int patch);
protected:
const QString m_name;
QString m_error;
- QString m_explaination;
+ QString m_explanation;
QString m_proposedFix;
bool m_skipped : 1;
bool m_passed : 1;
};
}
}
#endif /* __KLEOPATRA_SELFTEST_IMPLEMENTATION_P_H__ */
diff --git a/src/selftest/libkleopatrarccheck.cpp b/src/selftest/libkleopatrarccheck.cpp
index 0bac09bcb..7a58a9a17 100644
--- a/src/selftest/libkleopatrarccheck.cpp
+++ b/src/selftest/libkleopatrarccheck.cpp
@@ -1,92 +1,92 @@
/* -*- mode: c++; c-basic-offset:4 -*-
selftest/libkleopatrarccheck.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2010 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include
#include "libkleopatrarccheck.h"
#include "implementation_p.h"
#include
#include
#include
using namespace Kleo;
using namespace Kleo::_detail;
namespace
{
class LibKleopatraRcCheck : public SelfTestImplementation
{
public:
explicit LibKleopatraRcCheck()
: SelfTestImplementation(i18nc("@title", "Config File 'libkleopatrarc'"))
{
runTest();
}
void runTest()
{
QStringList errors;
ArchiveDefinition::getArchiveDefinitions(errors);
ChecksumDefinition::getChecksumDefinitions(errors);
m_passed = errors.empty();
if (m_passed) {
return;
}
m_error = i18n("Errors found");
// The building of the following string is a bit of a hack to avoid
// that xi18nc does not escape the html tags while not breaking
// the historic string.
- m_explaination
+ m_explanation
= xi18nc("@info",
"Kleopatra detected the following errors in the libkleopatrarc configuration: "
"%1", QStringLiteral("%1")).arg(QStringLiteral("") +
errors.join(QLatin1String(" ")) +
QStringLiteral(" "));
}
///* reimp */ bool canFixAutomatically() const { return false; }
};
}
std::shared_ptr Kleo::makeLibKleopatraRcSelfTest()
{
return std::shared_ptr(new LibKleopatraRcCheck);
}
diff --git a/src/selftest/registrycheck.cpp b/src/selftest/registrycheck.cpp
index db0e1a1a1..76c83a962 100644
--- a/src/selftest/registrycheck.cpp
+++ b/src/selftest/registrycheck.cpp
@@ -1,126 +1,126 @@
/* -*- mode: c++; c-basic-offset:4 -*-
selftest/registrycheck.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2008 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include
#include "registrycheck.h"
#include "implementation_p.h"
#include
#include
#include
using namespace Kleo;
using namespace Kleo::_detail;
static QString gnupg_path = QStringLiteral("HKEY_LOCAL_MACHINE\\Software\\GNU\\GnuPG");
static QString gnupg_key = QStringLiteral("gpgProgram");
namespace
{
class RegistryCheck : public SelfTestImplementation
{
public:
explicit RegistryCheck()
: SelfTestImplementation(i18nc("@title", "Windows Registry"))
{
runTest();
}
void runTest()
{
m_passed = !QSettings(gnupg_path, QSettings::NativeFormat).contains(gnupg_key);
if (m_passed) {
return;
}
m_error = i18n("Obsolete registry entries found");
- m_explaination
+ m_explanation
= xi18nc("@info",
"Kleopatra detected an obsolete registry key (%1\\%2 ), "
"added by either a previous Gpg4win version or "
"applications such as WinPT or EnigMail . "
"Keeping the entry might lead to an old GnuPG backend being used. ",
gnupg_path, gnupg_key);
m_proposedFix = xi18nc("@info",
"Delete registry key %1\\%2 . ",
gnupg_path, gnupg_key);
}
/* reimp */ bool canFixAutomatically() const
{
return true;
}
/* reimp */ bool fix()
{
QSettings settings(gnupg_path, QSettings::NativeFormat);
if (!settings.contains(gnupg_key)) {
return true;
}
settings.remove(gnupg_key);
settings.sync();
if (settings.status() != QSettings::NoError) {
KMessageBox::error(
0,
xi18nc("@info",
"Could not delete the registry key %1\\%2 ",
gnupg_path, gnupg_key),
i18nc("@title", "Error Deleting Registry Key"));
return false;
}
m_passed = true;
m_error.clear();
- m_explaination.clear();
+ m_explanation.clear();
m_proposedFix.clear();
return true;
}
};
}
std::shared_ptr Kleo::makeGpgProgramRegistryCheckSelfTest()
{
return std::shared_ptr(new RegistryCheck);
}
diff --git a/src/selftest/selftest.cpp b/src/selftest/selftest.cpp
index 37e2bd897..700d68978 100644
--- a/src/selftest/selftest.cpp
+++ b/src/selftest/selftest.cpp
@@ -1,67 +1,67 @@
/* -*- mode: c++; c-basic-offset:4 -*-
selftest/selftest.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2008 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include
#include "selftest.h"
#include "implementation_p.h"
using namespace Kleo;
using namespace Kleo::_detail;
SelfTest::~SelfTest() {}
bool SelfTest::canFixAutomatically() const
{
return false;
}
bool SelfTest::fix()
{
return false;
}
SelfTestImplementation::SelfTestImplementation(const QString &title)
: SelfTest(),
m_name(title),
m_error(),
- m_explaination(),
+ m_explanation(),
m_proposedFix(),
m_skipped(false),
m_passed(false)
{
}
SelfTestImplementation::~SelfTestImplementation() {}
// bool SelfTestImplementation::ensureEngineVersion( GpgME::Engine engine, int major, int minor, int patch )
// in enginecheck.cpp, since it reuses the instrumentation there
diff --git a/src/selftest/uiservercheck.cpp b/src/selftest/uiservercheck.cpp
index 9617fe459..8095db526 100644
--- a/src/selftest/uiservercheck.cpp
+++ b/src/selftest/uiservercheck.cpp
@@ -1,104 +1,104 @@
/* -*- mode: c++; c-basic-offset:4 -*-
selftest/uiservercheck.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2008 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include
#include "uiservercheck.h"
#include "implementation_p.h"
#include
#include // for Qt::escape
#include
#include
#include
using namespace Kleo;
using namespace Kleo::_detail;
namespace
{
class UiServerCheck : public SelfTestImplementation
{
public:
explicit UiServerCheck()
: SelfTestImplementation(i18nc("@title", "UiServer Connectivity"))
{
runTest();
}
void runTest()
{
KleopatraClientCopy::Command command;
{
QEventLoop loop;
loop.connect(&command, SIGNAL(finished()), SLOT(quit()));
QMetaObject::invokeMethod(&command, "start", Qt::QueuedConnection);
loop.exec();
}
if (command.error()) {
m_passed = false;
m_error = i18n("not reachable");
- m_explaination = xi18nc("@info",
+ m_explanation = xi18nc("@info",
"Could not connect to UiServer: %1 ",
command.errorString().toHtmlEscaped());
m_proposedFix = xi18nc("@info",
"Check that your firewall is not set to block local connections "
"(allow connections to localhost or 127.0.0.1 ). ");
} else if (command.serverPid() != QCoreApplication::applicationPid()) {
m_passed = false;
m_error = i18n("multiple instances");
- m_explaination = xi18nc("@info",
+ m_explanation = xi18nc("@info",
"It seems another Kleopatra is running (with process-id %1)",
command.serverPid());
m_proposedFix = xi18nc("@info",
"Quit any other running instances of Kleopatra .");
} else {
m_passed = true;
}
}
};
}
std::shared_ptr Kleo::makeUiServerConnectivitySelfTest()
{
return std::shared_ptr(new UiServerCheck);
}
diff --git a/src/uiserver/assuancommand.h b/src/uiserver/assuancommand.h
index 99408794b..d5f1da55f 100644
--- a/src/uiserver/assuancommand.h
+++ b/src/uiserver/assuancommand.h
@@ -1,410 +1,410 @@
/* -*- mode: c++; c-basic-offset:4 -*-
uiserver/assuancommand.h
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2007 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#ifndef __KLEOPATRA_UISERVER_ASSUANCOMMAND_H__
#define __KLEOPATRA_UISERVER_ASSUANCOMMAND_H__
#include
#include
#include
#include
#ifdef HAVE_ASSUAN2
#include
#endif
#include
#include // for WId
#include
#include
#include
#include
class QVariant;
class QObject;
class QStringList;
struct assuan_context_s;
namespace Kleo
{
class Input;
class Output;
class AssuanCommandFactory;
/*!
\brief Base class for GnuPG UI Server commands
\note large parts of this are outdated by now!
Implementing a new AssuanCommand
You do not directly inherit AssuanCommand, unless you want to
- deal with implementing low-level, repetetive things like name()
+ deal with implementing low-level, repetitive things like name()
in terms of staticName(). Assuming you don't, then you inherit
your command class from AssuanCommandMixin, passing your class
as the template argument to AssuanCommandMixin, like this:
\code
class MyFooCommand : public AssuanCommandMixin {
\endcode
(http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)
You then choose a command name, and return that from the static
method staticName(), which is by convention queried by both
AssuanCommandMixin<> and GenericAssuanCommandFactory<>:
\code
static const char * staticName() { return "MYFOO"; }
\endcode
The string should be all-uppercase by convention, but the
UiServer implementation doesn't enforce this.
The next step is to implement start(), the starting point of
command execution:
Executing the command
\code
int start( const std::string & line ) {
\endcode
This should set everything up and check the parameters in \a
line and any options this command understands. If there's an
error, choose one of the gpg-error codes and create a
gpg_error_t from it using the protected makeError() function:
\code
return makeError( GPG_ERR_NOT_IMPLEMENTED );
\endcode
But usually, you will want to create a dialog, or call some
GpgME function from here. In case of errors from GpgME, you
shouldn't pipe them through makeError(), but return them
as-is. This will preserve the error source. Error created using
makeError() will have Kleopatra as their error source, so watch
out what you're doing :)
In addition to options and the command line, your command might
require bulk data input or output. That's what the bulk
input and output channels are for. You can check whether the
client handed you an input channel by checking that
bulkInputDevice() isn't NULL, likewise for bulkOutputDevice().
If everything is ok, you return 0. This indicates to the client
that the command has been accepted and is now in progress.
In this mode (start() returned 0), there are a bunch of options
for your command to do. Some commands may require additional
information from the client. The options passed to start() are
designed to be persistent across commands, and rather limited in
length (there's a strict line length limit in the assuan
protocol with no line continuation mechanism). The same is true
for command line arguments, which, in addition, you have to
parse yourself. Those usually apply only to this command, and
not to following ones.
If you need data that might be larger than the line length
limit, you can either expect it on the bulkInputDevice(), or, if
you have the need for more than one such data channel, or the
data is optional or conditional on some condition that can only
be determined during command execution, you can \em inquire the
missing information from the client.
As an example, a VERIFY command would expect the signed data on
the bulkInputDevice(). But if the input stream doesn't contain
an embedded (opaque) signature, indicating a \em detached
signature, it would go and inquire that data from the
client. Here's how it works:
\code
const int err = inquire( "DETACHED_SIGNATURE",
this, SLOT(slotDetachedSignature(int,QByteArray,QByteArray)) );
if ( err )
done( err );
\endcode
This should be self-explanatory: You give a slot to call when
the data has arrived. The slot's first argument is an error
code. The second the data (if any), and the third is just
repeating what you gave as inquire()'s first argument. As usual,
you can leave argument off of the end, if you are not interested
in them.
You can do as many inquiries as you want, but only one at a
time.
You should periodically send status updates to the client. You do
that by calling sendStatus().
Once your command has finished executing, call done(). If it's
with an error code, call done(err) like above. Do not
forget to call done() when done! . It will close
bulkInputDevice(), bulkOutputDevice(), and send an OK or ERR
message back to the client.
At that point, your command has finished executing, and a new
one can be accepted, or the connection closed.
Apropos connection closed. The only way for the client to cancel
an operation is to shut down the connection. In this case, the
canceled() function will be called. At that point, the
connection to the client will have been broken already, and all
you can do is pack your things and go down gracefully.
If _you_ detect that the user has canceled (your dialog contains
a cancel button, doesn't it?), then you should instead call
done( GPG_ERR_CANCELED ), like for normal operation.
Registering the command with UiServer
To register a command, you implement a AssuanCommandFactory for
your AssuanCommand subclass, and register it with the
UiServer. This can be made considerably easier using
GenericAssuanCommandFactory:
\code
UiServer server;
server.registerCommandFactory( shared_ptr( new GenericAssuanCommandFactory ) );
// more registerCommandFactory calls...
server.start();
\endcode
*/
class AssuanCommand : public ExecutionContext, public std::enable_shared_from_this
{
// defined in assuanserverconnection.cpp!
public:
AssuanCommand();
virtual ~AssuanCommand();
int start();
void canceled();
virtual const char *name() const = 0;
class Memento
{
public:
virtual ~Memento() {}
};
template
class TypedMemento : public Memento
{
T m_t;
public:
explicit TypedMemento(const T &t) : m_t(t) {}
const T &get() const
{
return m_t;
}
T &get()
{
return m_t;
}
};
template
static std::shared_ptr< TypedMemento > make_typed_memento(const T &t)
{
return std::shared_ptr< TypedMemento >(new TypedMemento(t));
}
static int makeError(int code);
// convenience methods:
enum Mode { NoMode, EMail, FileManager };
Mode checkMode() const;
enum CheckProtocolOption {
AllowProtocolMissing = 0x01
};
GpgME::Protocol checkProtocol(Mode mode, int options = 0) const;
void applyWindowID(QWidget *w) const override
{
doApplyWindowID(w);
}
WId parentWId() const;
void setNohup(bool on);
bool isNohup() const;
bool isDone() const;
QString sessionTitle() const;
unsigned int sessionId() const;
bool informativeRecipients() const;
bool informativeSenders() const;
const std::vector &recipients() const;
const std::vector &senders() const;
bool hasMemento(const QByteArray &tag) const;
std::shared_ptr memento(const QByteArray &tag) const;
template
std::shared_ptr mementoAs(const QByteArray &tag) const
{
return std::dynamic_pointer_cast(this->memento(tag));
}
QByteArray registerMemento(const std::shared_ptr &mem);
QByteArray registerMemento(const QByteArray &tag, const std::shared_ptr &mem);
void removeMemento(const QByteArray &tag);
template
T mementoContent(const QByteArray &tag) const
{
if (std::shared_ptr< TypedMemento > m = mementoAs< TypedMemento >(tag)) {
return m->get();
} else {
return T();
}
}
bool hasOption(const char *opt) const;
QVariant option(const char *opt) const;
const std::map &options() const;
const std::vector< std::shared_ptr > &inputs() const;
const std::vector< std::shared_ptr > &messages() const;
const std::vector< std::shared_ptr > &outputs() const;
QStringList fileNames() const;
unsigned int numFiles() const;
void sendStatus(const char *keyword, const QString &text);
void sendStatusEncoded(const char *keyword, const std::string &text);
void sendData(const QByteArray &data, bool moreToCome = false);
int inquire(const char *keyword, QObject *receiver, const char *slot, unsigned int maxSize = 0);
void done(const GpgME::Error &err = GpgME::Error());
void done(const GpgME::Error &err, const QString &details);
void done(int err)
{
done(GpgME::Error(err));
}
void done(int err, const QString &details)
{
done(GpgME::Error(err), details);
}
private:
virtual void doCanceled() = 0;
virtual int doStart() = 0;
private:
void doApplyWindowID(QWidget *w) const;
private:
const std::map< QByteArray, std::shared_ptr > &mementos() const;
private:
friend class ::Kleo::AssuanCommandFactory;
class Private;
kdtools::pimpl_ptr d;
};
class AssuanCommandFactory
{
public:
virtual ~AssuanCommandFactory() {}
virtual std::shared_ptr create() const = 0;
virtual const char *name() const = 0;
#ifndef HAVE_ASSUAN2
typedef int(*_Handler)(assuan_context_s *, char *);
#else
typedef gpg_error_t(*_Handler)(assuan_context_s *, char *);
#endif
virtual _Handler _handler() const = 0;
#ifndef HAVE_ASSUAN2
static int _handle(assuan_context_s *, char *, const char *);
#else
static gpg_error_t _handle(assuan_context_s *, char *, const char *);
#endif
};
template
class GenericAssuanCommandFactory : public AssuanCommandFactory
{
AssuanCommandFactory::_Handler _handler() const override
{
return &GenericAssuanCommandFactory::_handle;
}
#ifndef HAVE_ASSUAN2
static int _handle(assuan_context_s *_ctx, char *_line)
{
#else
static gpg_error_t _handle(assuan_context_s *_ctx, char *_line)
{
#endif
return AssuanCommandFactory::_handle(_ctx, _line, Command::staticName());
}
std::shared_ptr create() const override
{
return make();
}
const char *name() const override
{
return Command::staticName();
}
public:
static std::shared_ptr make()
{
return std::shared_ptr(new Command);
}
};
template
class AssuanCommandMixin : public Base
{
protected:
/* reimp */ const char *name() const override
{
return Derived::staticName();
}
};
}
#endif /* __KLEOPATRA_UISERVER_ASSUANCOMMAND_H__ */