File indexing completed on 2024-06-23 05:14:13
0001 /* -*- mode: c++; c-basic-offset:4 -*- 0002 uiserver/echocommand.cpp 0003 0004 This file is part of Kleopatra, the KDE keymanager 0005 SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include <config-kleopatra.h> 0011 0012 #include "echocommand.h" 0013 0014 #include <utils/input.h> 0015 #include <utils/output.h> 0016 0017 #include <Libkleo/KleoException> 0018 0019 #include <gpg-error.h> 0020 0021 #include <KLocalizedString> 0022 0023 #include <QByteArray> 0024 #include <QIODevice> 0025 0026 #include <algorithm> 0027 #include <string> 0028 0029 using namespace Kleo; 0030 0031 static const char option_prefix[] = "prefix"; 0032 0033 class EchoCommand::Private 0034 { 0035 public: 0036 int operationsInFlight = 0; 0037 QByteArray buffer; 0038 }; 0039 0040 EchoCommand::EchoCommand() 0041 : QObject() 0042 , AssuanCommandMixin<EchoCommand>() 0043 , d(new Private) 0044 { 0045 } 0046 0047 EchoCommand::~EchoCommand() 0048 { 0049 } 0050 0051 int EchoCommand::doStart() 0052 { 0053 const std::vector<std::shared_ptr<Input>> in = inputs(), msg = messages(); 0054 const std::vector<std::shared_ptr<Output>> out = outputs(); 0055 0056 if (!in.empty() && out.empty()) { 0057 return makeError(GPG_ERR_NOT_SUPPORTED); 0058 } 0059 0060 if (!msg.empty()) { 0061 return makeError(GPG_ERR_NOT_SUPPORTED); 0062 } 0063 0064 if (hasOption(option_prefix) && !option(option_prefix).toByteArray().isEmpty()) { 0065 return makeError(GPG_ERR_NOT_IMPLEMENTED); 0066 } 0067 0068 std::string keyword; 0069 if (hasOption("inquire")) { 0070 keyword = option("inquire").toString().toStdString(); 0071 if (keyword.empty()) { 0072 return makeError(GPG_ERR_INV_ARG); 0073 } 0074 } 0075 0076 const std::string output = option("text").toString().toStdString(); 0077 0078 // aaand ACTION: 0079 0080 // 1. echo the command line though the status channel 0081 sendStatus("ECHO", output.empty() ? QString() : QLatin1StringView(output.c_str())); 0082 0083 // 2. if --inquire was given, inquire more data from the client: 0084 if (!keyword.empty()) { 0085 if (const int err = inquire(keyword.c_str(), this, SLOT(slotInquireData(int, QByteArray)))) { 0086 return err; 0087 } else { 0088 ++d->operationsInFlight; 0089 } 0090 } 0091 0092 // 3. if INPUT was given, start the data pump for input->output 0093 if (const std::shared_ptr<QIODevice> i = in.at(0)->ioDevice()) { 0094 const std::shared_ptr<QIODevice> o = out.at(0)->ioDevice(); 0095 0096 ++d->operationsInFlight; 0097 0098 connect(i.get(), &QIODevice::readyRead, this, &EchoCommand::slotInputReadyRead); 0099 connect(o.get(), &QIODevice::bytesWritten, this, &EchoCommand::slotOutputBytesWritten); 0100 0101 if (i->bytesAvailable()) { 0102 slotInputReadyRead(); 0103 } 0104 } 0105 0106 if (!d->operationsInFlight) { 0107 done(); 0108 } 0109 return 0; 0110 } 0111 0112 void EchoCommand::doCanceled() 0113 { 0114 } 0115 0116 void EchoCommand::slotInquireData(int rc, const QByteArray &data) 0117 { 0118 --d->operationsInFlight; 0119 0120 if (rc) { 0121 done(rc); 0122 return; 0123 } 0124 0125 try { 0126 sendStatus("ECHOINQ", QLatin1StringView(data)); 0127 if (!d->operationsInFlight) { 0128 done(); 0129 } 0130 } catch (const Exception &e) { 0131 done(e.error(), e.message()); 0132 } catch (const std::exception &e) { 0133 done(makeError(GPG_ERR_UNEXPECTED), 0134 i18n("Caught unexpected exception in SignCommand::Private::slotMicAlgDetermined: %1", QString::fromLocal8Bit(e.what()))); 0135 } catch (...) { 0136 done(makeError(GPG_ERR_UNEXPECTED), i18n("Caught unknown exception in SignCommand::Private::slotMicAlgDetermined")); 0137 } 0138 } 0139 0140 void EchoCommand::slotInputReadyRead() 0141 { 0142 const std::shared_ptr<QIODevice> in = inputs().at(0)->ioDevice(); 0143 Q_ASSERT(in); 0144 0145 QByteArray buffer; 0146 buffer.resize(in->bytesAvailable()); 0147 const qint64 read = in->read(buffer.data(), buffer.size()); 0148 if (read == -1) { 0149 done(makeError(GPG_ERR_EIO)); 0150 return; 0151 } 0152 if (read == 0 || (!in->isSequential() && read == in->size())) { 0153 in->close(); 0154 } 0155 0156 buffer.resize(read); 0157 d->buffer += buffer; 0158 0159 slotOutputBytesWritten(); 0160 } 0161 0162 void EchoCommand::slotOutputBytesWritten() 0163 { 0164 const std::shared_ptr<QIODevice> out = outputs().at(0)->ioDevice(); 0165 Q_ASSERT(out); 0166 0167 if (!d->buffer.isEmpty()) { 0168 if (out->bytesToWrite()) { 0169 return; 0170 } 0171 0172 const qint64 written = out->write(d->buffer); 0173 if (written == -1) { 0174 done(makeError(GPG_ERR_EIO)); 0175 return; 0176 } 0177 d->buffer.remove(0, written); 0178 } 0179 0180 if (out->isOpen() && d->buffer.isEmpty() && !inputs().at(0)->ioDevice()->isOpen()) { 0181 out->close(); 0182 if (!--d->operationsInFlight) { 0183 done(); 0184 } 0185 } 0186 } 0187 0188 #include "moc_echocommand.cpp"