File indexing completed on 2024-06-23 05:14:13
0001 /* -*- mode: c++; c-basic-offset:4 -*- 0002 uiserver/prepsigncommand.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 "prepsigncommand.h" 0013 0014 #include <crypto/newsignencryptemailcontroller.h> 0015 0016 #include <utils/kleo_assert.h> 0017 0018 #include <Libkleo/KleoException> 0019 0020 #include <KLocalizedString> 0021 0022 #include <QPointer> 0023 #include <QTimer> 0024 0025 using namespace Kleo; 0026 using namespace Kleo::Crypto; 0027 0028 class PrepSignCommand::Private : public QObject 0029 { 0030 Q_OBJECT 0031 private: 0032 friend class ::Kleo::PrepSignCommand; 0033 PrepSignCommand *const q; 0034 0035 public: 0036 explicit Private(PrepSignCommand *qq) 0037 : q(qq) 0038 , controller() 0039 { 0040 } 0041 0042 private: 0043 void checkForErrors() const; 0044 void connectController(); 0045 0046 public Q_SLOTS: 0047 void slotSignersResolved(); 0048 void slotError(int, const QString &); 0049 0050 private: 0051 std::shared_ptr<NewSignEncryptEMailController> controller; 0052 }; 0053 0054 PrepSignCommand::PrepSignCommand() 0055 : AssuanCommandMixin<PrepSignCommand>() 0056 , d(new Private(this)) 0057 { 0058 } 0059 0060 PrepSignCommand::~PrepSignCommand() 0061 { 0062 } 0063 0064 void PrepSignCommand::Private::checkForErrors() const 0065 { 0066 if (!q->inputs().empty() || !q->outputs().empty() || !q->messages().empty()) 0067 throw Exception(makeError(GPG_ERR_CONFLICT), i18n("INPUT/OUTPUT/MESSAGE may only be given after PREP_SIGN")); 0068 0069 if (q->numFiles()) 0070 throw Exception(makeError(GPG_ERR_CONFLICT), i18n("PREP_SIGN is an email mode command, connection seems to be in filemanager mode")); 0071 0072 if (q->senders().empty()) 0073 throw Exception(makeError(GPG_ERR_CONFLICT), i18n("No SENDER given")); 0074 0075 const auto m = q->mementoContent<std::shared_ptr<NewSignEncryptEMailController>>(NewSignEncryptEMailController::mementoName()); 0076 0077 if (m && m->isSigning()) { 0078 if (q->hasOption("protocol")) 0079 if (m->protocol() != q->checkProtocol(EMail)) 0080 throw Exception(makeError(GPG_ERR_CONFLICT), i18n("Protocol given conflicts with protocol determined by PREP_ENCRYPT in this session")); 0081 0082 // ### check that any SENDER here is the same as the one for PREP_ENCRYPT 0083 0084 // ### ditto RECIPIENT 0085 } 0086 } 0087 0088 void PrepSignCommand::Private::connectController() 0089 { 0090 auto ptr = controller.get(); 0091 connect(ptr, &NewSignEncryptEMailController::certificatesResolved, this, &PrepSignCommand::Private::slotSignersResolved); 0092 connect(ptr, &Controller::error, this, &PrepSignCommand::Private::slotError); 0093 } 0094 0095 int PrepSignCommand::doStart() 0096 { 0097 d->checkForErrors(); 0098 0099 const auto seec = mementoContent<std::shared_ptr<NewSignEncryptEMailController>>(NewSignEncryptEMailController::mementoName()); 0100 0101 if (seec && seec->isSigning()) { 0102 // reuse the controller from a previous PREP_ENCRYPT --expect-sign, if available: 0103 d->controller = seec; 0104 d->connectController(); 0105 seec->setExecutionContext(shared_from_this()); 0106 if (seec->areCertificatesResolved()) { 0107 QTimer::singleShot(0, d.get(), &Private::slotSignersResolved); 0108 } else { 0109 kleo_assert(seec->isResolvingInProgress()); 0110 } 0111 } else { 0112 // use a new controller 0113 d->controller.reset(new NewSignEncryptEMailController(shared_from_this())); 0114 0115 const QString session = sessionTitle(); 0116 if (!session.isEmpty()) { 0117 d->controller->setSubject(session); 0118 } 0119 0120 if (hasOption("protocol")) 0121 // --protocol is optional for PREP_SIGN 0122 { 0123 d->controller->setProtocol(checkProtocol(EMail)); 0124 } 0125 0126 d->controller->setEncrypting(false); 0127 d->controller->setSigning(true); 0128 d->connectController(); 0129 d->controller->startResolveCertificates(recipients(), senders()); 0130 } 0131 0132 return 0; 0133 } 0134 0135 void PrepSignCommand::Private::slotSignersResolved() 0136 { 0137 // hold local std::shared_ptr to member as q->done() deletes *this 0138 const std::shared_ptr<NewSignEncryptEMailController> cont = controller; 0139 QPointer<Private> that(this); 0140 0141 try { 0142 q->sendStatus("PROTOCOL", QLatin1StringView(controller->protocolAsString())); 0143 q->registerMemento(NewSignEncryptEMailController::mementoName(), make_typed_memento(controller)); 0144 q->done(); 0145 return; 0146 0147 } catch (const Exception &e) { 0148 q->done(e.error(), e.message()); 0149 } catch (const std::exception &e) { 0150 q->done(makeError(GPG_ERR_UNEXPECTED), 0151 i18n("Caught unexpected exception in PrepSignCommand::Private::slotRecipientsResolved: %1", QString::fromLocal8Bit(e.what()))); 0152 } catch (...) { 0153 q->done(makeError(GPG_ERR_UNEXPECTED), i18n("Caught unknown exception in PrepSignCommand::Private::slotRecipientsResolved")); 0154 } 0155 if (that) { // isn't this always deleted here and thus unnecessary? 0156 q->removeMemento(NewSignEncryptEMailController::mementoName()); 0157 } 0158 cont->cancel(); 0159 } 0160 0161 void PrepSignCommand::Private::slotError(int err, const QString &details) 0162 { 0163 q->done(err, details); 0164 } 0165 0166 void PrepSignCommand::doCanceled() 0167 { 0168 if (d->controller) { 0169 d->controller->cancel(); 0170 } 0171 } 0172 0173 #include "prepsigncommand.moc"