File indexing completed on 2024-06-23 05:18:32
0001 /* 0002 SPDX-FileCopyrightText: 2009 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.net 0003 SPDX-FileCopyrightText: 2009 Leo Franchi <lfranchi@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include <config-messagelib.h> 0009 0010 #include "job/encryptjob.h" 0011 0012 #include "contentjobbase_p.h" 0013 #include "job/protectedheadersjob.h" 0014 #include "utils/util_p.h" 0015 0016 #include <QGpgME/EncryptJob> 0017 #include <QGpgME/Protocol> 0018 0019 #include "messagecomposer_debug.h" 0020 0021 #include <gpgme++/encryptionresult.h> 0022 #include <gpgme++/global.h> 0023 #include <gpgme++/signingresult.h> 0024 #include <sstream> 0025 0026 using namespace MessageComposer; 0027 0028 class MessageComposer::EncryptJobPrivate : public ContentJobBasePrivate 0029 { 0030 public: 0031 EncryptJobPrivate(EncryptJob *qq) 0032 : ContentJobBasePrivate(qq) 0033 { 0034 } 0035 0036 QString gnupgHome; 0037 QStringList recipients; 0038 std::vector<GpgME::Key> keys; 0039 Kleo::CryptoMessageFormat format; 0040 KMime::Content *content = nullptr; 0041 KMime::Message *skeletonMessage = nullptr; 0042 0043 bool protectedHeaders = true; 0044 bool protectedHeadersObvoscate = false; 0045 0046 // copied from messagecomposer.cpp 0047 bool binaryHint(Kleo::CryptoMessageFormat f) 0048 { 0049 switch (f) { 0050 case Kleo::SMIMEFormat: 0051 case Kleo::SMIMEOpaqueFormat: 0052 return true; 0053 default: 0054 case Kleo::OpenPGPMIMEFormat: 0055 case Kleo::InlineOpenPGPFormat: 0056 return false; 0057 } 0058 } 0059 0060 GpgME::SignatureMode signingMode(Kleo::CryptoMessageFormat f) 0061 { 0062 switch (f) { 0063 case Kleo::SMIMEOpaqueFormat: 0064 return GpgME::NormalSignatureMode; 0065 case Kleo::InlineOpenPGPFormat: 0066 return GpgME::Clearsigned; 0067 default: 0068 case Kleo::SMIMEFormat: 0069 case Kleo::OpenPGPMIMEFormat: 0070 return GpgME::Detached; 0071 } 0072 } 0073 0074 Q_DECLARE_PUBLIC(EncryptJob) 0075 }; 0076 0077 EncryptJob::EncryptJob(QObject *parent) 0078 : ContentJobBase(*new EncryptJobPrivate(this), parent) 0079 { 0080 } 0081 0082 EncryptJob::~EncryptJob() = default; 0083 0084 void EncryptJob::setContent(KMime::Content *content) 0085 { 0086 Q_D(EncryptJob); 0087 0088 d->content = content; 0089 d->content->assemble(); 0090 } 0091 0092 void EncryptJob::setCryptoMessageFormat(Kleo::CryptoMessageFormat format) 0093 { 0094 Q_D(EncryptJob); 0095 0096 d->format = format; 0097 } 0098 0099 void EncryptJob::setEncryptionKeys(const std::vector<GpgME::Key> &keys) 0100 { 0101 Q_D(EncryptJob); 0102 0103 d->keys = keys; 0104 } 0105 0106 void EncryptJob::setRecipients(const QStringList &recipients) 0107 { 0108 Q_D(EncryptJob); 0109 0110 d->recipients = recipients; 0111 } 0112 0113 void EncryptJob::setSkeletonMessage(KMime::Message *skeletonMessage) 0114 { 0115 Q_D(EncryptJob); 0116 0117 d->skeletonMessage = skeletonMessage; 0118 } 0119 0120 void EncryptJob::setProtectedHeaders(bool protectedHeaders) 0121 { 0122 Q_D(EncryptJob); 0123 0124 d->protectedHeaders = protectedHeaders; 0125 } 0126 0127 void EncryptJob::setProtectedHeadersObvoscate(bool protectedHeadersObvoscate) 0128 { 0129 Q_D(EncryptJob); 0130 0131 d->protectedHeadersObvoscate = protectedHeadersObvoscate; 0132 } 0133 0134 void EncryptJob::setGnupgHome(const QString &path) 0135 { 0136 Q_D(EncryptJob); 0137 0138 d->gnupgHome = path; 0139 } 0140 0141 QStringList EncryptJob::recipients() const 0142 { 0143 Q_D(const EncryptJob); 0144 0145 return d->recipients; 0146 } 0147 0148 std::vector<GpgME::Key> EncryptJob::encryptionKeys() const 0149 { 0150 Q_D(const EncryptJob); 0151 0152 return d->keys; 0153 } 0154 0155 void EncryptJob::doStart() 0156 { 0157 Q_D(EncryptJob); 0158 Q_ASSERT(d->resultContent == nullptr); // Not processed before. 0159 0160 if (d->keys.size() == 0) { // should not happen---resolver should have dealt with it earlier 0161 qCDebug(MESSAGECOMPOSER_LOG) << "HELP! Encrypt job but have no keys to encrypt with."; 0162 return; 0163 } 0164 0165 // if setContent hasn't been called, we assume that a subjob was added 0166 // and we want to use that 0167 if (!d->content || !d->content->hasContent()) { 0168 if (d->subjobContents.size() == 1) { 0169 d->content = d->subjobContents.constFirst(); 0170 } 0171 } 0172 0173 if (d->protectedHeaders && d->skeletonMessage && d->format & Kleo::OpenPGPMIMEFormat) { 0174 auto pJob = new ProtectedHeadersJob; 0175 pJob->setContent(d->content); 0176 pJob->setSkeletonMessage(d->skeletonMessage); 0177 pJob->setObvoscate(d->protectedHeadersObvoscate); 0178 QObject::connect(pJob, &ProtectedHeadersJob::finished, this, [d, pJob](KJob *job) { 0179 if (job->error()) { 0180 return; 0181 } 0182 d->content = pJob->content(); 0183 }); 0184 appendSubjob(pJob); 0185 } 0186 0187 ContentJobBase::doStart(); 0188 } 0189 0190 void EncryptJob::slotResult(KJob *job) 0191 { 0192 // Q_D(EncryptJob); 0193 if (error() || job->error()) { 0194 ContentJobBase::slotResult(job); 0195 return; 0196 } 0197 if (subjobs().size() == 2) { 0198 auto pjob = static_cast<ProtectedHeadersJob *>(subjobs().last()); 0199 if (pjob) { 0200 auto cjob = qobject_cast<ContentJobBase *>(job); 0201 Q_ASSERT(cjob); 0202 pjob->setContent(cjob->content()); 0203 } 0204 } 0205 0206 ContentJobBase::slotResult(job); 0207 } 0208 0209 void EncryptJob::process() 0210 { 0211 Q_D(EncryptJob); 0212 0213 // if setContent hasn't been called, we assume that a subjob was added 0214 // and we want to use that 0215 if (!d->content || !d->content->hasContent()) { 0216 Q_ASSERT(d->subjobContents.size() == 1); 0217 d->content = d->subjobContents.constFirst(); 0218 } 0219 0220 const QGpgME::Protocol *proto = nullptr; 0221 if (d->format & Kleo::AnyOpenPGP) { 0222 proto = QGpgME::openpgp(); 0223 } else if (d->format & Kleo::AnySMIME) { 0224 proto = QGpgME::smime(); 0225 } else { 0226 qCDebug(MESSAGECOMPOSER_LOG) << "HELP! Encrypt job but have protocol to encrypt with."; 0227 return; 0228 } 0229 0230 Q_ASSERT(proto); 0231 0232 // for now just do the main recipients 0233 QByteArray content; 0234 d->content->assemble(); 0235 if (d->format & Kleo::InlineOpenPGPFormat) { 0236 content = d->content->body(); 0237 } else { 0238 content = d->content->encodedContent(); 0239 } 0240 0241 qCDebug(MESSAGECOMPOSER_LOG) << "got backend, starting job"; 0242 QGpgME::EncryptJob *eJob = proto->encryptJob(!d->binaryHint(d->format), d->format == Kleo::InlineOpenPGPFormat); 0243 #if QGPGME_SUPPORTS_ENCRYPTION_JOB_SET_INPUT_ENCODING 0244 if (!(d->format & Kleo::InlineOpenPGPFormat)) { 0245 eJob->setInputEncoding(GpgME::Data::MimeEncoding); 0246 } 0247 #endif 0248 0249 if (!d->gnupgHome.isEmpty()) { 0250 QGpgME::Job::context(eJob)->setEngineHomeDirectory(d->gnupgHome.toUtf8().constData()); 0251 } 0252 0253 QObject::connect( 0254 eJob, 0255 &QGpgME::EncryptJob::result, 0256 this, 0257 [this, d](const GpgME::EncryptionResult &result, const QByteArray &cipherText, const QString &auditLogAsHtml, const GpgME::Error &auditLogError) { 0258 Q_UNUSED(auditLogAsHtml) 0259 Q_UNUSED(auditLogError) 0260 if (result.error()) { 0261 setError(result.error().code()); 0262 setErrorText(QString::fromLocal8Bit(result.error().asString())); 0263 emitResult(); 0264 return; 0265 } 0266 d->resultContent = MessageComposer::Util::composeHeadersAndBody(d->content, cipherText, d->format, false); 0267 0268 emitResult(); 0269 }); 0270 0271 const auto error = eJob->start(d->keys, content, true); 0272 if (error.code()) { 0273 eJob->deleteLater(); 0274 setError(error.code()); 0275 setErrorText(QString::fromLocal8Bit(error.asString())); 0276 emitResult(); 0277 } 0278 } 0279 0280 #include "moc_encryptjob.cpp"