Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F41057497
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
5 KB
Subscribers
None
View Options
diff --git a/src/smartcard/deviceinfowatcher.cpp b/src/smartcard/deviceinfowatcher.cpp
index 6439d4489..19d744211 100644
--- a/src/smartcard/deviceinfowatcher.cpp
+++ b/src/smartcard/deviceinfowatcher.cpp
@@ -1,146 +1,151 @@
/* smartcard/deviceinfowatcher.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2020 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "deviceinfowatcher.h"
#include "deviceinfowatcher_p.h"
#include <QGpgME/Debug>
#include <gpgme++/context.h>
#include <gpgme++/engineinfo.h>
#include <gpgme++/statusconsumerassuantransaction.h>
#include "kleopatra_debug.h"
using namespace Kleo;
using namespace GpgME;
using namespace std::chrono_literals;
static const auto initialRetryDelay = 125ms;
static const auto maxRetryDelay = 1000ms;
static const auto maxConnectionAttempts = 10;
DeviceInfoWatcher::Worker::Worker()
: mRetryDelay{initialRetryDelay}
{
}
DeviceInfoWatcher::Worker::~Worker()
{
if (mContext) {
mContext->cancelPendingOperationImmediately();
}
}
void DeviceInfoWatcher::Worker::start()
{
if (!mContext) {
Error err;
mContext = Context::createForEngine(AssuanEngine, &err);
if (err) {
qCWarning(KLEOPATRA_LOG) << "DeviceInfoWatcher::Worker::start: Creating context failed:" << err;
return;
}
}
static const char *command = "SCD DEVINFO --watch";
std::unique_ptr<AssuanTransaction> t(new StatusConsumerAssuanTransaction(this));
const Error err = mContext->startAssuanTransaction(command, std::move(t));
if (!err) {
qCDebug(KLEOPATRA_LOG) << "DeviceInfoWatcher::Worker::start: Assuan transaction for" << command << "started";
mRetryDelay = initialRetryDelay;
mFailedConnectionAttempts = 0;
QMetaObject::invokeMethod(this, "poll", Qt::QueuedConnection);
return;
} else if (err.code() == GPG_ERR_ASS_CONNECT_FAILED) {
mFailedConnectionAttempts++;
if (mFailedConnectionAttempts == 1) {
Q_EMIT startOfGpgAgentRequested();
}
if (mFailedConnectionAttempts < maxConnectionAttempts) {
qCInfo(KLEOPATRA_LOG) << "DeviceInfoWatcher::Worker::start: Connecting to the agent failed. Retrying in" << mRetryDelay.count() << "ms";
QThread::msleep(mRetryDelay.count());
mRetryDelay = std::min(mRetryDelay * 2, maxRetryDelay);
QMetaObject::invokeMethod(this, "start", Qt::QueuedConnection);
return;
}
qCWarning(KLEOPATRA_LOG) << "DeviceInfoWatcher::Worker::start: Connecting to the agent failed too often. Giving up.";
} else if (err.code() == GPG_ERR_EPIPE) {
qCDebug(KLEOPATRA_LOG)
<< "DeviceInfoWatcher::Worker::start: Assuan transaction failed with broken pipe. The agent seems to have died. Resetting context.";
mContext.reset();
QMetaObject::invokeMethod(this, "start", Qt::QueuedConnection);
} else {
qCWarning(KLEOPATRA_LOG) << "DeviceInfoWatcher::Worker::start: Starting Assuan transaction for" << command << "failed:" << err;
}
}
void DeviceInfoWatcher::Worker::poll()
{
const bool finished = mContext->poll();
if (finished) {
qCDebug(KLEOPATRA_LOG) << "DeviceInfoWatcher::Worker::poll: context finished with" << mContext->lastError();
QThread::msleep(1000);
QMetaObject::invokeMethod(this, "start", Qt::QueuedConnection);
} else {
QMetaObject::invokeMethod(this, "poll", Qt::QueuedConnection);
}
}
void DeviceInfoWatcher::Worker::status(const char *status, const char *details)
{
qCDebug(KLEOPATRA_LOG) << "DeviceInfoWatcher::Worker::status:" << status << details;
if (status && std::strcmp(status, "DEVINFO_STATUS") == 0) {
Q_EMIT statusChanged(QByteArray(details));
}
}
DeviceInfoWatcher::Private::Private(DeviceInfoWatcher *qq)
: q(qq)
{
}
DeviceInfoWatcher::Private::~Private()
{
workerThread.quit();
workerThread.wait();
}
void DeviceInfoWatcher::Private::start()
{
auto worker = new DeviceInfoWatcher::Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::started, worker, &DeviceInfoWatcher::Worker::start);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(worker, &DeviceInfoWatcher::Worker::statusChanged, q, &DeviceInfoWatcher::statusChanged);
connect(worker, &DeviceInfoWatcher::Worker::startOfGpgAgentRequested, q, &DeviceInfoWatcher::startOfGpgAgentRequested);
workerThread.start();
}
DeviceInfoWatcher::DeviceInfoWatcher(QObject *parent)
: QObject(parent)
, d(new Private(this))
{
}
DeviceInfoWatcher::~DeviceInfoWatcher()
{
delete d;
}
// static
bool DeviceInfoWatcher::isSupported()
{
- return engineInfo(GpgEngine).engineVersion() >= "2.4.0";
+#ifdef Q_OS_WIN
+ // "SCD DEVINFO --watch" does not seem to work on Windows; see https://dev.gnupg.org/T5359
+ return false;
+#else
+ return engineInfo(GpgEngine).engineVersion() >= "2.3.0";
+#endif
}
void DeviceInfoWatcher::start()
{
d->start();
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Tue, May 5, 6:14 AM (1 d, 23 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
dc/f5/6803b2ffb53558601af25c60f6a8
Attached To
rKLEOPATRA Kleopatra
Event Timeline
Log In to Comment