diff --git a/src/utils/assuan.cpp b/src/utils/assuan.cpp index 1cd56c918..528085a2b 100644 --- a/src/utils/assuan.cpp +++ b/src/utils/assuan.cpp @@ -1,120 +1,140 @@ /* utils/assuan.cpp This file is part of libkleopatra - SPDX-FileCopyrightText: 2021 g10 Code GmbH + SPDX-FileCopyrightText: 2021, 2022 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "assuan.h" #include #if __has_include() # include #endif #include #include #include #include "libkleo_debug.h" using namespace GpgME; using namespace Kleo; using namespace Kleo::Assuan; namespace { static QDebug operator<<(QDebug s, const std::string &string) { return s << QString::fromStdString(string); } static QDebug operator<<(QDebug s, const std::vector< std::pair > &v) { using pair = std::pair; s << '('; for (const pair &p : v) { s << "status(" << QString::fromStdString(p.first) << ") =" << QString::fromStdString(p.second) << '\n'; } return s << ')'; } } +bool Kleo::Assuan::agentIsRunning() +{ + Error err; + const std::unique_ptr ctx = Context::createForEngine(AssuanEngine, &err); + if (err) { + qCWarning(LIBKLEO_LOG) << __func__ << ": Creating context for Assuan engine failed:" << err; + return false; + } + static const char *command = "GETINFO version"; + err = ctx->assuanTransact(command); + if (!err) { + // all good + } else if (err.code() == GPG_ERR_ASS_CONNECT_FAILED) { + qCDebug(LIBKLEO_LOG) << __func__ << ": Connecting to the agent failed."; + } else { + qCWarning(LIBKLEO_LOG) << __func__ << ": Starting Assuan transaction for" << command << "failed:" << err; + } + return !err; +} + std::unique_ptr Kleo::Assuan::sendCommand(std::shared_ptr &context, const std::string &command, std::unique_ptr transaction, GpgME::Error &err) { qCDebug(LIBKLEO_LOG) << __func__ << command; err = context->assuanTransact(command.c_str(), std::move(transaction)); static int cnt = 0; while (err.code() == GPG_ERR_ASS_CONNECT_FAILED && cnt < 5) { // Esp. on Windows the agent processes may take their time so we try // in increasing waits for them to start up qCDebug(LIBKLEO_LOG) << "Waiting for the daemons to start up"; cnt++; QThread::msleep(250 * cnt); err = context->assuanTransact(command.c_str(), context->takeLastAssuanTransaction()); } if (err.code()) { qCDebug(LIBKLEO_LOG) << __func__ << command << "failed:" << err; if (err.code() >= GPG_ERR_ASS_GENERAL && err.code() <= GPG_ERR_ASS_UNKNOWN_INQUIRE) { qCDebug(LIBKLEO_LOG) << "Assuan problem, killing context"; context.reset(); } return {}; } return context->takeLastAssuanTransaction(); } std::unique_ptr Kleo::Assuan::sendCommand(std::shared_ptr &context, const std::string &command, Error &err) { std::unique_ptr t = sendCommand(context, command, std::make_unique(), err); return std::unique_ptr(dynamic_cast(t.release())); } std::string Kleo::Assuan::sendDataCommand(std::shared_ptr context, const std::string &command, Error &err) { std::string data; const std::unique_ptr t = sendCommand(context, command, err); if (t.get()) { data = t->data(); qCDebug(LIBKLEO_LOG) << __func__ << command << ": got" << QString::fromStdString(data); } else { qCDebug(LIBKLEO_LOG) << __func__ << command << ": t == NULL"; } return data; } std::vector> Kleo::Assuan::sendStatusLinesCommand(std::shared_ptr context, const std::string &command, Error &err) { std::vector> statusLines; const std::unique_ptr t = sendCommand(context, command, err); if (t.get()) { statusLines = t->statusLines(); qCDebug(LIBKLEO_LOG) << __func__ << command << ": got" << statusLines; } else { qCDebug(LIBKLEO_LOG) << __func__ << command << ": t == NULL"; } return statusLines; } std::string Kleo::Assuan::sendStatusCommand(const std::shared_ptr &context, const std::string &command, Error &err) { const auto lines = sendStatusLinesCommand(context, command, err); // The status is only the last attribute // e.g. for SCD SERIALNO it would only be "SERIALNO" and for SCD GETATTR FOO // it would only be FOO const auto lastSpace = command.rfind(' '); const auto needle = lastSpace == std::string::npos ? command : command.substr(lastSpace + 1); for (const auto &pair: lines) { if (pair.first == needle) { return pair.second; } } return {}; } diff --git a/src/utils/assuan.h b/src/utils/assuan.h index 7280f8d4d..a1b943ba4 100644 --- a/src/utils/assuan.h +++ b/src/utils/assuan.h @@ -1,64 +1,67 @@ /* utils/assuan.h This file is part of libkleopatra - SPDX-FileCopyrightText: 2021 g10 Code GmbH + SPDX-FileCopyrightText: 2021, 2022 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include #include "kleo_export.h" namespace GpgME { class AssuanTransaction; class Context; class DefaultAssuanTransaction; class Error; } namespace Kleo { /** The Assuan namespace collects functions for communicating with the GnuPG * agent via the Assuan protocol. */ namespace Assuan { +/** Checks if the GnuPG agent is running and accepts connections. */ +KLEO_EXPORT bool agentIsRunning(); + /** Sends the Assuan @p command using the @p transaction and the @p assuanContext * to the GnuPG agent and waits for the result. The returned transaction can be used * to retrieve the result. * If an error occurred, then @p err provides details. */ KLEO_EXPORT std::unique_ptr sendCommand(std::shared_ptr &assuanContext, const std::string &command, std::unique_ptr transaction, GpgME::Error &err); /** Sends the Assuan @p command using a default Assuan transaction and the @p assuanContext * to the GnuPG agent and waits for the result. The returned transaction can be used * to retrieve the result. * If an error occurred, then @p err provides details. */ KLEO_EXPORT std::unique_ptr sendCommand(std::shared_ptr &assuanContext, const std::string &command, GpgME::Error &err); /** Sends the Assuan @p command using a default Assuan transaction and the @p assuanContext * to the GnuPG agent and waits for the result. Returns the data that was sent by * GnuPG agent in response to the @p command. * If an error occurred, then @p err provides details. */ KLEO_EXPORT std::string sendDataCommand(std::shared_ptr assuanContext, const std::string &command, GpgME::Error &err); /** Sends the Assuan @p command using a default Assuan transaction and the @p assuanContext * to the GnuPG agent and waits for the result. Returns the status lines that were sent by * GnuPG agent in response to the @p command. * If an error occurred, then @p err provides details. */ KLEO_EXPORT std::vector> sendStatusLinesCommand(std::shared_ptr assuanContext, const std::string &command, GpgME::Error &err); /** Sends the Assuan @p command using a default Assuan transaction and the @p assuanContext * to the GnuPG agent and waits for the result. Returns the status that was sent by * GnuPG agent in response to the @p command. * If an error occurred, then @p err provides details. */ KLEO_EXPORT std::string sendStatusCommand(const std::shared_ptr &assuanContext, const std::string &command, GpgME::Error &err); } }