File indexing completed on 2024-06-23 05:13:57
0001 /* -*- mode: c++; c-basic-offset:4 -*- 0002 crypto/encryptemailcontroller.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 "encryptemailcontroller.h" 0013 #include "encryptemailtask.h" 0014 #include "kleopatra_debug.h" 0015 #include "taskcollection.h" 0016 0017 #include <crypto/gui/encryptemailwizard.h> 0018 0019 #include <utils/input.h> 0020 #include <utils/kleo_assert.h> 0021 #include <utils/output.h> 0022 0023 #include <Libkleo/KleoException> 0024 #include <Libkleo/Stl_Util> 0025 0026 #include <gpgme++/key.h> 0027 0028 #include <KLocalizedString> 0029 0030 #include <QPointer> 0031 0032 using namespace Kleo; 0033 using namespace Kleo::Crypto; 0034 using namespace Kleo::Crypto::Gui; 0035 using namespace GpgME; 0036 using namespace KMime::Types; 0037 0038 class EncryptEMailController::Private 0039 { 0040 friend class ::Kleo::Crypto::EncryptEMailController; 0041 EncryptEMailController *const q; 0042 0043 public: 0044 explicit Private(Mode mode, EncryptEMailController *qq); 0045 0046 private: 0047 void slotWizardCanceled(); 0048 0049 private: 0050 void ensureWizardCreated(); 0051 void ensureWizardVisible(); 0052 void cancelAllTasks(); 0053 0054 void schedule(); 0055 std::shared_ptr<EncryptEMailTask> takeRunnable(GpgME::Protocol proto); 0056 0057 private: 0058 const Mode mode; 0059 std::vector<std::shared_ptr<EncryptEMailTask>> runnable, completed; 0060 std::shared_ptr<EncryptEMailTask> cms, openpgp; 0061 QPointer<EncryptEMailWizard> wizard; 0062 }; 0063 0064 EncryptEMailController::Private::Private(Mode m, EncryptEMailController *qq) 0065 : q(qq) 0066 , mode(m) 0067 , runnable() 0068 , cms() 0069 , openpgp() 0070 , wizard() 0071 { 0072 } 0073 0074 EncryptEMailController::EncryptEMailController(const std::shared_ptr<ExecutionContext> &xc, Mode mode, QObject *p) 0075 : Controller(xc, p) 0076 , d(new Private(mode, this)) 0077 { 0078 } 0079 0080 EncryptEMailController::EncryptEMailController(Mode mode, QObject *p) 0081 : Controller(p) 0082 , d(new Private(mode, this)) 0083 { 0084 } 0085 0086 EncryptEMailController::~EncryptEMailController() 0087 { 0088 if (d->wizard && !d->wizard->isVisible()) { 0089 delete d->wizard; 0090 } 0091 } 0092 0093 EncryptEMailController::Mode EncryptEMailController::mode() const 0094 { 0095 return d->mode; 0096 } 0097 0098 void EncryptEMailController::setProtocol(Protocol proto) 0099 { 0100 d->ensureWizardCreated(); 0101 const Protocol protocol = d->wizard->presetProtocol(); 0102 kleo_assert(protocol == UnknownProtocol || protocol == proto); 0103 0104 d->wizard->setPresetProtocol(proto); 0105 } 0106 0107 Protocol EncryptEMailController::protocol() 0108 { 0109 d->ensureWizardCreated(); 0110 return d->wizard->selectedProtocol(); 0111 } 0112 0113 const char *EncryptEMailController::protocolAsString() 0114 { 0115 switch (protocol()) { 0116 case OpenPGP: 0117 return "OpenPGP"; 0118 case CMS: 0119 return "CMS"; 0120 default: 0121 throw Kleo::Exception(gpg_error(GPG_ERR_INTERNAL), i18n("Call to EncryptEMailController::protocolAsString() is ambiguous.")); 0122 } 0123 } 0124 0125 void EncryptEMailController::startResolveRecipients() 0126 { 0127 d->ensureWizardCreated(); 0128 d->ensureWizardVisible(); 0129 } 0130 0131 void EncryptEMailController::Private::slotWizardCanceled() 0132 { 0133 q->setLastError(gpg_error(GPG_ERR_CANCELED), i18n("User cancel")); 0134 q->emitDoneOrError(); 0135 } 0136 0137 void EncryptEMailController::setInputAndOutput(const std::shared_ptr<Input> &input, const std::shared_ptr<Output> &output) 0138 { 0139 setInputsAndOutputs(std::vector<std::shared_ptr<Input>>(1, input), std::vector<std::shared_ptr<Output>>(1, output)); 0140 } 0141 0142 void EncryptEMailController::setInputsAndOutputs(const std::vector<std::shared_ptr<Input>> &inputs, const std::vector<std::shared_ptr<Output>> &outputs) 0143 { 0144 kleo_assert(!inputs.empty()); 0145 kleo_assert(outputs.size() == inputs.size()); 0146 0147 std::vector<std::shared_ptr<EncryptEMailTask>> tasks; 0148 tasks.reserve(inputs.size()); 0149 0150 d->ensureWizardCreated(); 0151 0152 const std::vector<Key> keys = d->wizard->resolvedCertificates(); 0153 kleo_assert(!keys.empty()); 0154 0155 for (unsigned int i = 0, end = inputs.size(); i < end; ++i) { 0156 const std::shared_ptr<EncryptEMailTask> task(new EncryptEMailTask); 0157 task->setInput(inputs[i]); 0158 task->setOutput(outputs[i]); 0159 if (d->mode == ClipboardMode) { 0160 task->setAsciiArmor(true); 0161 } 0162 task->setRecipients(keys); 0163 0164 tasks.push_back(task); 0165 } 0166 0167 d->runnable.swap(tasks); 0168 } 0169 0170 void EncryptEMailController::start() 0171 { 0172 std::shared_ptr<TaskCollection> coll(new TaskCollection); 0173 std::vector<std::shared_ptr<Task>> tmp; 0174 std::copy(d->runnable.begin(), d->runnable.end(), std::back_inserter(tmp)); 0175 coll->setTasks(tmp); 0176 d->ensureWizardCreated(); 0177 d->wizard->setTaskCollection(coll); 0178 for (const std::shared_ptr<Task> &t : std::as_const(tmp)) { 0179 connectTask(t); 0180 } 0181 d->schedule(); 0182 } 0183 0184 void EncryptEMailController::Private::schedule() 0185 { 0186 if (!cms) 0187 if (const std::shared_ptr<EncryptEMailTask> t = takeRunnable(CMS)) { 0188 t->start(); 0189 cms = t; 0190 } 0191 0192 if (!openpgp) 0193 if (const std::shared_ptr<EncryptEMailTask> t = takeRunnable(OpenPGP)) { 0194 t->start(); 0195 openpgp = t; 0196 } 0197 0198 if (cms || openpgp) { 0199 return; 0200 } 0201 kleo_assert(runnable.empty()); 0202 q->emitDoneOrError(); 0203 } 0204 0205 std::shared_ptr<EncryptEMailTask> EncryptEMailController::Private::takeRunnable(GpgME::Protocol proto) 0206 { 0207 const auto it = std::find_if(runnable.begin(), runnable.end(), [proto](const std::shared_ptr<Kleo::Crypto::EncryptEMailTask> &task) { 0208 return task->protocol() == proto; 0209 }); 0210 if (it == runnable.end()) { 0211 return std::shared_ptr<EncryptEMailTask>(); 0212 } 0213 0214 const std::shared_ptr<EncryptEMailTask> result = *it; 0215 runnable.erase(it); 0216 return result; 0217 } 0218 0219 void EncryptEMailController::doTaskDone(const Task *task, const std::shared_ptr<const Task::Result> &result) 0220 { 0221 Q_UNUSED(result) 0222 Q_ASSERT(task); 0223 0224 // We could just delete the tasks here, but we can't use 0225 // Qt::QueuedConnection here (we need sender()) and other slots 0226 // might not yet have executed. Therefore, we push completed tasks 0227 // into a burial container 0228 0229 if (task == d->cms.get()) { 0230 d->completed.push_back(d->cms); 0231 d->cms.reset(); 0232 } else if (task == d->openpgp.get()) { 0233 d->completed.push_back(d->openpgp); 0234 d->openpgp.reset(); 0235 } 0236 0237 QMetaObject::invokeMethod( 0238 this, 0239 [this]() { 0240 d->schedule(); 0241 }, 0242 Qt::QueuedConnection); 0243 } 0244 0245 void EncryptEMailController::cancel() 0246 { 0247 try { 0248 if (d->wizard) { 0249 d->wizard->close(); 0250 } 0251 d->cancelAllTasks(); 0252 } catch (const std::exception &e) { 0253 qCDebug(KLEOPATRA_LOG) << "Caught exception: " << e.what(); 0254 } 0255 } 0256 0257 void EncryptEMailController::Private::cancelAllTasks() 0258 { 0259 // we just kill all runnable tasks - this will not result in 0260 // signal emissions. 0261 runnable.clear(); 0262 0263 // a cancel() will result in a call to 0264 if (cms) { 0265 cms->cancel(); 0266 } 0267 if (openpgp) { 0268 openpgp->cancel(); 0269 } 0270 } 0271 0272 void EncryptEMailController::Private::ensureWizardCreated() 0273 { 0274 if (wizard) { 0275 return; 0276 } 0277 0278 std::unique_ptr<EncryptEMailWizard> w(new EncryptEMailWizard); 0279 w->setAttribute(Qt::WA_DeleteOnClose); 0280 connect(w.get(), &EncryptEMailWizard::recipientsResolved, q, &EncryptEMailController::recipientsResolved, Qt::QueuedConnection); 0281 connect( 0282 w.get(), 0283 &EncryptEMailWizard::canceled, 0284 q, 0285 [this]() { 0286 slotWizardCanceled(); 0287 }, 0288 Qt::QueuedConnection); 0289 0290 wizard = w.release(); 0291 } 0292 0293 void EncryptEMailController::Private::ensureWizardVisible() 0294 { 0295 ensureWizardCreated(); 0296 q->bringToForeground(wizard); 0297 } 0298 0299 #include "moc_encryptemailcontroller.cpp"