7#include "messagepart.h"
8#include "cryptohelper.h"
9#include "job/qgpgmejobexecutor.h"
10#include "memento/compositememento.h"
11#include "memento/cryptobodypartmemento.h"
12#include "memento/decryptverifybodypartmemento.h"
13#include "memento/keycachememento.h"
14#include "memento/verifydetachedbodypartmemento.h"
15#include "memento/verifyopaquebodypartmemento.h"
16#include "mimetreeparser_debug.h"
17#include "objecttreeparser.h"
19#include "bodyformatter/utils.h"
21#include <KMime/Content>
23#include <Libkleo/Compliance>
24#include <Libkleo/KeyCache>
27#include <QGpgME/ImportJob>
28#include <QGpgME/Protocol>
29#include <QGpgME/VerifyDetachedJob>
30#include <QGpgME/VerifyOpaqueJob>
32#include <gpgme++/key.h>
33#include <gpgme++/keylistresult.h>
36#include <KLocalizedString>
40using namespace MimeTreeParser;
43namespace MimeTreeParser
45class MessagePartPrivate
53 PartMetaData mMetaData;
55 bool mIsImage =
false;
56 bool mNeverDisplayInline =
false;
62 , d(new MessagePartPrivate)
67MessagePart::~MessagePart() =
default;
71 return d->mParentPart;
74void MessagePart::setParentPart(
MessagePart *parentPart)
76 d->mParentPart = parentPart;
79QString MessagePart::htmlContent()
const
84QString MessagePart::plaintextContent()
const
89PartMetaData *MessagePart::partMetaData()
const
96 return nodeHelper()->bodyPartMemento(
content(),
"__plugin__");
101 nodeHelper()->setBodyPartMemento(
content(),
"__plugin__", memento);
116 return d->mAttachmentNode;
121 d->mAttachmentNode = node;
124bool MessagePart::isAttachment()
const
126 return d->mAttachmentNode;
136 return mOtp->nodeHelper()->asHREF(
content(), QStringLiteral(
"body"));
142 static int serial = 0;
146 return QStringLiteral(
"x-kmail:/bodypart/%1/%2/%3")
151void MessagePart::setIsRoot(
bool root)
156bool MessagePart::isRoot()
const
161QString MessagePart::text()
const
166void MessagePart::setText(
const QString &text)
171bool MessagePart::isHtml()
const
179 return mOtp->mSource;
185 return mOtp->nodeHelper();
188void MessagePart::parseInternal(
KMime::Content *node,
bool onlyOneMimePart)
190 auto subMessagePart = mOtp->parseObjectTreeInternal(node, onlyOneMimePart);
191 d->mRoot = subMessagePart->isRoot();
193 for (
const auto &part : subParts) {
198QString MessagePart::renderInternalText()
const
201 const auto subPartsLst = subParts();
202 for (
const auto &mp : subPartsLst) {
208void MessagePart::fix()
const
210 const auto subPartsLst = subParts();
211 for (
const auto &mp : subPartsLst) {
221 messagePart->setParentPart(
this);
222 d->mBlocks.append(messagePart);
230bool MessagePart::hasSubParts()
const
232 return !d->mBlocks.isEmpty();
235void MessagePart::clearSubParts()
240bool MessagePart::neverDisplayInline()
const
242 return d->mNeverDisplayInline;
245void MessagePart::setNeverDisplayInline(
bool displayInline)
247 d->mNeverDisplayInline = displayInline;
250bool MessagePart::isImage()
const
255void MessagePart::setIsImage(
bool image)
260bool MessagePart::hasHeader(
const char *headerType)
const
284MessagePartList::~MessagePartList() =
default;
286QString MessagePartList::text()
const
288 return renderInternalText();
291QString MessagePartList::plaintextContent()
const
296QString MessagePartList::htmlContent()
const
305 , mDecryptMessage(decryptMessage)
308 qCWarning(MIMETREEPARSER_LOG) <<
"not a valid node";
317TextMessagePart::~TextMessagePart() =
default;
319bool TextMessagePart::decryptMessage()
const
321 return mDecryptMessage;
324void TextMessagePart::parseContent()
326 const auto codecName = mOtp->codecNameFor(
content());
328 const QString &fromAddress = mOtp->nodeHelper()->fromAsString(
content());
329 mSignatureState = KMMsgNotSigned;
330 mEncryptionState = KMMsgNotEncrypted;
331 const auto blocks = prepareMessageForDecryption(
content()->decodedContent());
333 const auto cryptProto = QGpgME::openpgp();
335 if (!blocks.isEmpty()) {
343 bool fullySignedOrEncrypted =
true;
344 bool fullySignedOrEncryptedTmp =
true;
347 for (
const auto &block : blocks) {
349 if (!fullySignedOrEncryptedTmp) {
350 fullySignedOrEncrypted =
false;
353 if (block.type() == NoPgpBlock && !block.text().trimmed().isEmpty()) {
354 fullySignedOrEncryptedTmp =
false;
357 }
else if (block.type() == PgpMessageBlock) {
359 mp->setDecryptMessage(decryptMessage());
360 mp->setIsEncrypted(
true);
361 mp->setMementoName(mp->mementoName() +
"-" + nodeHelper()->asHREF(
content(),
QString::number(blockIndex)).toLocal8Bit());
363 if (!decryptMessage()) {
366 mp->startDecryption(block.text(), codecName);
367 if (mp->partMetaData()->inProgress) {
370 }
else if (block.type() == ClearsignedBlock) {
372 mp->setMementoName(mp->mementoName() +
"-" + nodeHelper()->asHREF(
content(),
QString::number(blockIndex)).toLocal8Bit());
374 mp->startVerification(block.text(), codecName);
380 const PartMetaData *messagePart(mp->partMetaData());
382 if (!messagePart->isEncrypted && !messagePart->isSigned && !block.text().trimmed().isEmpty()) {
384 mp->setText(aCodec.decode(block.text()));
387 if (messagePart->isEncrypted) {
388 mEncryptionState = KMMsgPartiallyEncrypted;
391 if (messagePart->isSigned) {
392 mSignatureState = KMMsgPartiallySigned;
397 if (fullySignedOrEncrypted) {
398 if (mSignatureState == KMMsgPartiallySigned) {
399 mSignatureState = KMMsgFullySigned;
401 if (mEncryptionState == KMMsgPartiallyEncrypted) {
402 mEncryptionState = KMMsgFullyEncrypted;
408KMMsgEncryptionState TextMessagePart::encryptionState()
const
410 return mEncryptionState;
413KMMsgSignatureState TextMessagePart::signatureState()
const
415 return mSignatureState;
418bool TextMessagePart::showLink()
const
423bool TextMessagePart::isFirstTextPart()
const
428bool TextMessagePart::hasLabel()
const
438 label =
i18nc(
"display name for an unnamed attachment",
"Unnamed");
446 if (comment == label()) {
464AttachmentMessagePart::~AttachmentMessagePart() =
default;
473 qCWarning(MIMETREEPARSER_LOG) <<
"not a valid node";
483HtmlMessagePart::~HtmlMessagePart() =
default;
485void HtmlMessagePart::fix()
const
487 mOtp->mHtmlContent += mBodyHTML;
490QString HtmlMessagePart::text()
const
495QString MimeTreeParser::HtmlMessagePart::plaintextContent()
const
500bool HtmlMessagePart::isHtml()
const
505QString HtmlMessagePart::bodyHtml()
const
514 , mOnlyOneMimePart(onlyOneMimePart)
517 qCWarning(MIMETREEPARSER_LOG) <<
"not a valid node";
522 parseInternal(node, mOnlyOneMimePart);
525MimeMessagePart::~MimeMessagePart() =
default;
527QString MimeMessagePart::text()
const
529 return renderInternalText();
532QString MimeMessagePart::plaintextContent()
const
537QString MimeMessagePart::htmlContent()
const
546 , mPreferredMode(preferredMode)
549 KMime::Content *dataIcal = findTypeInDirectChilds(node,
"text/calendar");
550 KMime::Content *dataHtml = findTypeInDirectChilds(node,
"text/html");
551 KMime::Content *dataText = findTypeInDirectChilds(node,
"text/plain");
558 dataHtml = findTypeInDirectChilds(node,
"multipart/related");
566 dataHtml = findTypeInDirectChilds(node,
"multipart/mixed");
582 if (mChildNodes.isEmpty()) {
583 qCWarning(MIMETREEPARSER_LOG) <<
"no valid nodes";
588 while (i.hasNext()) {
594AlternativeMessagePart::~AlternativeMessagePart() =
default;
598 return mPreferredMode;
601void AlternativeMessagePart::setPreferredMode(
Util::HtmlMode preferredMode)
603 mPreferredMode = preferredMode;
608 return mChildParts.keys();
611QString AlternativeMessagePart::text()
const
619void AlternativeMessagePart::fix()
const
625 const auto mode = preferredMode();
627 mChildParts[mode]->fix();
636bool AlternativeMessagePart::isHtml()
const
641QString AlternativeMessagePart::plaintextContent()
const
646QString AlternativeMessagePart::htmlContent()
const
651 return plaintextContent();
659 , mAutoImport(autoImport)
660 , mCryptoProto(cryptoProto)
663 qCWarning(MIMETREEPARSER_LOG) <<
"not a valid node";
674 QGpgME::ImportJob *
import = mCryptoProto->importJob();
676 mImportResult = executor.exec(
import, certData);
679CertMessagePart::~CertMessagePart() =
default;
681QString CertMessagePart::text()
const
686const GpgME::ImportResult &CertMessagePart::importResult()
const
688 return mImportResult;
694 const QGpgME::Protocol *cryptoProto,
698 , mCryptoProto(cryptoProto)
699 , mFromAddress(fromAddress)
700 , mMementoName(
"verification")
703 partMetaData()->technicalProblem = (mCryptoProto ==
nullptr);
704 partMetaData()->isSigned =
true;
705 partMetaData()->isGoodSignature =
false;
706 partMetaData()->keyTrust = GpgME::Signature::Unknown;
707 partMetaData()->status =
i18n(
"Wrong Crypto Plug-In.");
708 partMetaData()->status_code = GPGME_SIG_STAT_NONE;
711SignedMessagePart::~SignedMessagePart() =
default;
713void SignedMessagePart::setIsSigned(
bool isSigned)
715 partMetaData()->isSigned = isSigned;
718bool SignedMessagePart::isSigned()
const
720 return partMetaData()->isSigned;
723QByteArray SignedMessagePart::mementoName()
const
728void SignedMessagePart::setMementoName(
const QByteArray &name)
733static GpgME::Protocol toGpgMeProtocol(
const QGpgME::Protocol *protocol)
735 if (protocol == QGpgME::openpgp()) {
736 return GpgME::OpenPGP;
739 if (protocol == QGpgME::smime()) {
743 return GpgME::UnknownProtocol;
750 partMetaData()->isSigned =
false;
751 partMetaData()->technicalProblem = (mCryptoProto ==
nullptr);
752 partMetaData()->keyTrust = GpgME::Signature::Unknown;
753 partMetaData()->status =
i18n(
"Wrong Crypto Plug-In.");
754 partMetaData()->status_code = GPGME_SIG_STAT_NONE;
756 const QByteArray _mementoName = mementoName();
758 auto m =
dynamic_cast<CompositeMemento *
>(nodeHelper->bodyPartMemento(
content(), _mementoName));
759 Q_ASSERT(!m || mCryptoProto);
761 if (!m && mCryptoProto) {
762 CryptoBodyPartMemento *newM =
nullptr;
764 QGpgME::VerifyDetachedJob *job = mCryptoProto->verifyDetachedJob();
766 newM =
new VerifyDetachedBodyPartMemento(job, mCryptoProto->keyListJob(), signature, data);
769 QGpgME::VerifyOpaqueJob *job = mCryptoProto->verifyOpaqueJob();
771 newM =
new VerifyOpaqueBodyPartMemento(job, mCryptoProto->keyListJob(), data);
776 m =
new CompositeMemento();
778 m->addMemento(
new KeyCacheMemento(Kleo::KeyCache::mutableInstance(), toGpgMeProtocol(mCryptoProto)));
782 if (mOtp->allowAsync()) {
783 QObject::connect(m, &CryptoBodyPartMemento::update, nodeHelper, &NodeHelper::update);
785 partMetaData()->inProgress =
true;
786 mOtp->mHasPendingAsyncJobs =
true;
791 nodeHelper->setBodyPartMemento(
content(), _mementoName, m);
793 }
else if (m && m->isRunning()) {
794 partMetaData()->inProgress =
true;
795 mOtp->mHasPendingAsyncJobs =
true;
797 partMetaData()->inProgress =
false;
798 mOtp->mHasPendingAsyncJobs =
false;
801 if (m && !partMetaData()->inProgress) {
803 mVerifiedText = data;
805 setVerificationResult(m, textNode);
808 if (!m && !partMetaData()->inProgress) {
813 cryptPlugLibName = mCryptoProto->name();
814 cryptPlugDisplayName = mCryptoProto->displayName();
818 if (cryptPlugDisplayName.
isEmpty()) {
819 errorMsg =
i18n(
"No appropriate crypto plug-in was found.");
821 errorMsg =
i18nc(
"%1 is either 'OpenPGP' or 'S/MIME'",
"No %1 plug-in was found.", cryptPlugDisplayName);
824 errorMsg =
i18n(
"Crypto plug-in \"%1\" cannot verify signatures.", cryptPlugLibName);
826 partMetaData()->errorText =
i18n(
827 "The message is signed, but the "
828 "validity of the signature cannot be "
834 return partMetaData()->isSigned;
837static int signatureToStatus(
const GpgME::Signature &sig)
839 switch (sig.status().code()) {
840 case GPG_ERR_NO_ERROR:
841 return GPGME_SIG_STAT_GOOD;
842 case GPG_ERR_BAD_SIGNATURE:
843 return GPGME_SIG_STAT_BAD;
844 case GPG_ERR_NO_PUBKEY:
845 return GPGME_SIG_STAT_NOKEY;
846 case GPG_ERR_NO_DATA:
847 return GPGME_SIG_STAT_NOSIG;
848 case GPG_ERR_SIG_EXPIRED:
849 return GPGME_SIG_STAT_GOOD_EXP;
850 case GPG_ERR_KEY_EXPIRED:
851 return GPGME_SIG_STAT_GOOD_EXPKEY;
853 return GPGME_SIG_STAT_ERROR;
857QString prettifyDN(
const char *uid)
859 return QGpgME::DN(uid).prettyDN();
862void SignedMessagePart::sigStatusToMetaData()
865 if (partMetaData()->isSigned) {
866 GpgME::Signature signature = mSignatures.front();
867 partMetaData()->status_code = signatureToStatus(signature);
868 partMetaData()->isGoodSignature = partMetaData()->status_code == GPGME_SIG_STAT_GOOD;
870 partMetaData()->sigSummary = signature.summary();
872 if (partMetaData()->isGoodSignature && !key.keyID()) {
875 key = mKeyCache->findByFingerprint(signature.fingerprint());
876 if (key.isNull() && signature.fingerprint()) {
879 const auto fpr = std::string_view{signature.fingerprint()};
880 const auto keyID = std::string{fpr, fpr.size() - 16, 16};
881 const auto subkeys = mKeyCache->findSubkeysByKeyID({keyID});
882 if (subkeys.size() > 0) {
883 key = subkeys[0].parent();
887 qCDebug(MIMETREEPARSER_LOG) <<
"Found no key or subkey for fingerprint" << signature.fingerprint();
892 partMetaData()->keyId = key.keyID();
894 if (partMetaData()->keyId.isEmpty()) {
895 partMetaData()->keyId = signature.fingerprint();
897 partMetaData()->keyTrust = signature.validity();
898 if (key.numUserIDs() > 0 && key.userID(0).id()) {
899 partMetaData()->signer = prettifyDN(key.userID(0).id());
901 for (
const auto &uid : key.userIDs()) {
908 partMetaData()->signerMailAddresses.
append(mbox.addrSpec().asString());
913 if (signature.creationTime()) {
916 partMetaData()->creationTime =
QDateTime();
918 if (partMetaData()->signer.isEmpty()) {
919 if (key.numUserIDs() > 0 && key.userID(0).name()) {
920 partMetaData()->signer = prettifyDN(key.userID(0).name());
922 if (!partMetaData()->signerMailAddresses.empty()) {
923 if (partMetaData()->signer.isEmpty()) {
924 partMetaData()->signer = partMetaData()->signerMailAddresses.
front();
930 if (Kleo::DeVSCompliance::isCompliant()) {
931 partMetaData()->isCompliant = signature.isDeVs();
932 partMetaData()->compliance = Kleo::DeVSCompliance::name(signature.isDeVs());
934 partMetaData()->isCompliant =
true;
941 startVerificationDetached(text,
nullptr,
QByteArray());
943 if (!
content() && partMetaData()->isSigned) {
945 setText(codec.decode(mVerifiedText));
951 partMetaData()->isEncrypted =
false;
952 partMetaData()->isDecryptable =
false;
955 parseInternal(textNode,
false);
958 if (!okVerify(text, signature, textNode)) {
959 partMetaData()->creationTime =
QDateTime();
963void SignedMessagePart::setVerificationResult(
const CompositeMemento *m,
KMime::Content *textNode)
966 const auto kc = m->memento<KeyCacheMemento>();
968 mKeyCache = kc->keyCache();
972 const auto vm = m->memento<VerifyDetachedBodyPartMemento>();
974 mSignatures = vm->verifyResult().signatures();
978 const auto vm = m->memento<VerifyOpaqueBodyPartMemento>();
980 mVerifiedText = vm->plainText();
981 mSignatures = vm->verifyResult().signatures();
985 const auto vm = m->memento<DecryptVerifyBodyPartMemento>();
987 mVerifiedText = vm->plainText();
988 mSignatures = vm->verifyResult().signatures();
991 partMetaData()->auditLogError = m->auditLogError();
992 partMetaData()->auditLog = m->auditLogAsHtml();
993 partMetaData()->isSigned = !mSignatures.empty();
995 if (partMetaData()->isSigned) {
996 sigStatusToMetaData();
998 mOtp->nodeHelper()->setSignatureState(
content(), KMMsgFullySigned);
1000 mOtp->nodeHelper()->setPartMetaData(
content(), *partMetaData());
1002 if (!mVerifiedText.
isEmpty()) {
1004 tempNode->setContent(KMime::CRLFtoLF(mVerifiedText.
constData()));
1007 if (!tempNode->head().isEmpty()) {
1008 tempNode->contentDescription()->from7BitString(
"signed data");
1012 parseInternal(tempNode,
false);
1019QString SignedMessagePart::plaintextContent()
const
1022 return MessagePart::text();
1028QString SignedMessagePart::htmlContent()
const
1031 return MessagePart::text();
1037const QGpgME::Protocol *SignedMessagePart::cryptoProto()
const
1039 return mCryptoProto;
1042QString SignedMessagePart::fromAddress()
const
1044 return mFromAddress;
1047bool SignedMessagePart::hasHeader(
const char *headerType)
const
1055const KMime::Headers::Base *MimeTreeParser::SignedMessagePart::header(
const char *headerType)
const
1058 return content()->headerByType(headerType);
1074 const QGpgME::Protocol *cryptoProto,
1078 , mPassphraseError(false)
1080 , mDecryptMessage(false)
1081 , mCryptoProto(cryptoProto)
1082 , mFromAddress(fromAddress)
1083 , mMementoName(
"decryptverify")
1086 partMetaData()->technicalProblem = (mCryptoProto ==
nullptr);
1087 partMetaData()->isSigned =
false;
1088 partMetaData()->isGoodSignature =
false;
1089 partMetaData()->isEncrypted =
false;
1090 partMetaData()->isDecryptable =
false;
1091 partMetaData()->keyTrust = GpgME::Signature::Unknown;
1092 partMetaData()->status =
i18n(
"Wrong Crypto Plug-In.");
1093 partMetaData()->status_code = GPGME_SIG_STAT_NONE;
1096EncryptedMessagePart::~EncryptedMessagePart() =
default;
1098void EncryptedMessagePart::setDecryptMessage(
bool decrypt)
1100 mDecryptMessage = decrypt;
1103bool EncryptedMessagePart::decryptMessage()
const
1105 return mDecryptMessage;
1108void EncryptedMessagePart::setIsEncrypted(
bool encrypted)
1110 partMetaData()->isEncrypted = encrypted;
1113bool EncryptedMessagePart::isEncrypted()
const
1115 return partMetaData()->isEncrypted;
1118bool EncryptedMessagePart::isDecryptable()
const
1120 return partMetaData()->isDecryptable;
1123bool EncryptedMessagePart::isNoSecKey()
const
1128bool EncryptedMessagePart::passphraseError()
const
1130 return mPassphraseError;
1133QByteArray EncryptedMessagePart::mementoName()
const
1135 return mMementoName;
1138void EncryptedMessagePart::setMementoName(
const QByteArray &name)
1140 mMementoName =
name;
1151 if (!partMetaData()->inProgress && partMetaData()->isDecryptable) {
1153 if (hasSubParts()) {
1154 auto _mp = (subParts()[0]).dynamicCast<SignedMessagePart>();
1156 _mp->setText(codec.decode(mDecryptedData));
1158 setText(codec.decode(mDecryptedData));
1161 setText(codec.decode(mDecryptedData));
1169 mPassphraseError =
false;
1170 partMetaData()->inProgress =
false;
1171 partMetaData()->errorText.
clear();
1172 partMetaData()->auditLogError = GpgME::Error();
1173 partMetaData()->auditLog.
clear();
1174 bool bDecryptionOk =
false;
1175 bool cannotDecrypt =
false;
1178 Q_ASSERT(decryptMessage());
1180 const QByteArray _mementoName = mementoName();
1182 const auto *m =
dynamic_cast<CompositeMemento *
>(nodeHelper->bodyPartMemento(&data, _mementoName));
1184 Q_ASSERT(!m || mCryptoProto);
1186 if (!m && mCryptoProto) {
1187 QGpgME::DecryptVerifyJob *job = mCryptoProto->decryptVerifyJob();
1189 cannotDecrypt =
true;
1192 auto newM =
new CompositeMemento();
1193 newM->addMemento(
new KeyCacheMemento(Kleo::KeyCache::mutableInstance(), toGpgMeProtocol(mCryptoProto)));
1194 newM->addMemento(
new DecryptVerifyBodyPartMemento(job, ciphertext));
1195 if (mOtp->allowAsync()) {
1196 QObject::connect(newM, &CryptoBodyPartMemento::update, nodeHelper, &NodeHelper::update);
1197 if (newM->start()) {
1198 partMetaData()->inProgress =
true;
1199 mOtp->mHasPendingAsyncJobs =
true;
1208 nodeHelper->setBodyPartMemento(&data, _mementoName, newM);
1210 }
else if (m && m->isRunning()) {
1211 partMetaData()->inProgress =
true;
1212 mOtp->mHasPendingAsyncJobs =
true;
1218 const auto *kcm = m->memento<KeyCacheMemento>();
1220 mKeyCache = kcm->keyCache();
1223 auto *decryptMemento = m->memento<DecryptVerifyBodyPartMemento>();
1224 const QByteArray &plainText = decryptMemento->plainText();
1225 const GpgME::DecryptionResult &decryptResult = decryptMemento->decryptResult();
1226 const GpgME::VerificationResult &verifyResult = decryptMemento->verifyResult();
1227 partMetaData()->isSigned = verifyResult.signatures().size() > 0;
1229 if (partMetaData()->isSigned) {
1231 subPart->setVerificationResult(m,
nullptr);
1232 appendSubPart(subPart);
1235 mDecryptRecipients.clear();
1236 bDecryptionOk = !decryptResult.error();
1242 for (
const auto &recipient : decryptResult.recipients()) {
1243 if (!recipient.status()) {
1244 bDecryptionOk =
true;
1247 key = mKeyCache->findByKeyIDOrFingerprint(recipient.keyID());
1249 auto ret = mKeyCache->findSubkeysByKeyID({recipient.keyID()});
1250 if (ret.size() == 1) {
1251 key = ret.front().parent();
1254 qCDebug(MIMETREEPARSER_LOG) <<
"Found no Key for KeyID " << recipient.keyID();
1257 mDecryptRecipients.emplace_back(recipient, key);
1260 if (!bDecryptionOk && partMetaData()->isSigned) {
1262 partMetaData()->isEncrypted =
false;
1263 bDecryptionOk =
true;
1264 mDecryptedData = plainText;
1266 mPassphraseError = decryptResult.error().isCanceled() || decryptResult.error().code() == GPG_ERR_NO_SECKEY;
1267 partMetaData()->isEncrypted = bDecryptionOk || decryptResult.error().code() != GPG_ERR_NO_DATA;
1269 if (decryptResult.error().isCanceled()) {
1270 setDecryptMessage(
false);
1274 if (Kleo::DeVSCompliance::isCompliant()) {
1275 partMetaData()->isCompliant = decryptResult.isDeVs();
1276 partMetaData()->compliance = Kleo::DeVSCompliance::name(decryptResult.isDeVs());
1278 partMetaData()->isCompliant =
true;
1280 if (partMetaData()->isEncrypted && decryptResult.numRecipients() > 0) {
1281 partMetaData()->keyId = decryptResult.recipient(0).keyID();
1284 if (bDecryptionOk) {
1285 mDecryptedData = plainText;
1288 const auto decryRecipients = decryptResult.recipients();
1289 for (
const GpgME::DecryptionResult::Recipient &recipient : decryRecipients) {
1290 mNoSecKey &= (recipient.status().code() == GPG_ERR_NO_SECKEY);
1292 if (!mPassphraseError && !mNoSecKey) {
1293 mPassphraseError =
true;
1299 if (!bDecryptionOk) {
1302 cryptPlugLibName = mCryptoProto->name();
1305 if (!mCryptoProto) {
1306 partMetaData()->errorText =
i18n(
"No appropriate crypto plug-in was found.");
1307 }
else if (cannotDecrypt) {
1308 partMetaData()->errorText =
i18n(
"Crypto plug-in \"%1\" cannot decrypt messages.", cryptPlugLibName);
1309 }
else if (!passphraseError()) {
1310 partMetaData()->errorText =
i18n(
"Crypto plug-in \"%1\" could not decrypt the data.", cryptPlugLibName) +
QLatin1StringView(
"<br />")
1311 +
i18n(
"Error: %1", partMetaData()->errorText);
1314 return bDecryptionOk;
1327 partMetaData()->isEncrypted =
true;
1329 bool bOkDecrypt = okDecryptMIME(*data);
1331 if (partMetaData()->inProgress) {
1334 partMetaData()->isDecryptable = bOkDecrypt;
1336 if (!partMetaData()->isDecryptable) {
1340 if (partMetaData()->isEncrypted && !decryptMessage()) {
1341 partMetaData()->isDecryptable =
true;
1344 if (
content() && !partMetaData()->isSigned) {
1345 mOtp->nodeHelper()->setPartMetaData(
content(), *partMetaData());
1347 if (decryptMessage()) {
1349 tempNode->setContent(KMime::CRLFtoLF(mDecryptedData.
constData()));
1352 if (!tempNode->head().isEmpty()) {
1353 tempNode->contentDescription()->from7BitString(
"encrypted data");
1357 parseInternal(tempNode,
false);
1362QString EncryptedMessagePart::plaintextContent()
const
1365 return MessagePart::text();
1371QString EncryptedMessagePart::htmlContent()
const
1374 return MessagePart::text();
1380QString EncryptedMessagePart::text()
const
1382 if (hasSubParts()) {
1383 auto _mp = (subParts()[0]).dynamicCast<SignedMessagePart>();
1387 return MessagePart::text();
1390 return MessagePart::text();
1394const QGpgME::Protocol *EncryptedMessagePart::cryptoProto()
const
1396 return mCryptoProto;
1399QString EncryptedMessagePart::fromAddress()
const
1401 return mFromAddress;
1404const std::vector<std::pair<GpgME::DecryptionResult::Recipient, GpgME::Key>> &EncryptedMessagePart::decryptRecipients()
const
1406 return mDecryptRecipients;
1409bool EncryptedMessagePart::hasHeader(
const char *headerType)
const
1411 const auto extraContent = mOtp->nodeHelper()->decryptedNodeForContent(
content());
1413 return nodeHelper()->hasMailHeader(headerType, extraContent);
1420 const auto extraContent = mOtp->nodeHelper()->decryptedNodeForContent(
content());
1422 return nodeHelper()->mailHeaderAsBase(headerType, extraContent);
1429 const auto extraContent = mOtp->nodeHelper()->decryptedNodeForContent(
content());
1431 return nodeHelper()->headers(headerType, extraContent);
1441 partMetaData()->isEncrypted =
false;
1442 partMetaData()->isSigned =
false;
1443 partMetaData()->isEncapsulatedRfc822Message =
true;
1445 mOtp->nodeHelper()->setNodeDisplayedEmbedded(node,
true);
1446 mOtp->nodeHelper()->setPartMetaData(node, *partMetaData());
1449 qCWarning(MIMETREEPARSER_LOG) <<
"Node is of type message/rfc822 but doesn't have a message!";
1457 parseInternal(message.
data(),
false);
1460EncapsulatedRfc822MessagePart::~EncapsulatedRfc822MessagePart() =
default;
1462QString EncapsulatedRfc822MessagePart::text()
const
1464 return renderInternalText();
1467void EncapsulatedRfc822MessagePart::fix()
const
1476#include "moc_messagepart.cpp"
const Headers::ContentType * contentType() const
ContentIndex index() const
QByteArray decodedContent() const
QList< Headers::Base * > headersByType(const char *type) const
bool hasHeader(const char *type) const
void setBody(const QByteArray &body)
const Headers::ContentDescription * contentDescription() const
void from7BitString(QByteArrayView s)
The EncryptedMessagePart class.
interface of classes that implement status for BodyPartFormatters.
Interface for object tree sources.
The MessagePartList class.
KMime::Content * content() const
The KMime::Content* node that's represented by this part.
QString makeLink(const QString &path) const
Returns a string representation of an URL that can be used to invoke a BodyPartURLHandler for this bo...
KMime::Content * attachmentContent() const
The KMime::Content* node that's the source of this part.
QString attachmentLink() const
The MimeMessagePart class.
static QByteArray charset(const KMime::Content *node)
Returns the charset for the given node.
static QString fileName(const KMime::Content *node)
Returns a usable filename for a node, that can be the filename from the content disposition header,...
void attachExtraContent(KMime::Content *topLevelNode, KMime::Content *content)
Attach an extra node to an existing node.
QString writeNodeToTempFile(KMime::Content *node)
Writes the given message part to a temporary file and returns the name of this file or QString() if w...
Parses messages and generates HTML display code out of them.
Helper class for synchronous execution of Kleo crypto jobs.
The SignedMessagePart class.
The TextMessagePart class.
QString temporaryFilePath() const
Temporary file containing the part content.
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
QString name(GameStandardAction id)
HtmlMode
Describes the type of the displayed message.
@ MultipartPlain
A multipart/alternative message, the plain text part is currently displayed.
@ MultipartIcal
A multipart/alternative message, the ICal part is currently displayed.
@ MultipartHtml
A multipart/alternative message, the HTML part is currently displayed.
const char * constData() const const
bool isEmpty() const const
const_pointer constData() const const
void setSecsSinceEpoch(qint64 secs)
void append(QList< T > &&value)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QString arg(Args &&... args) const const
QString fromLatin1(QByteArrayView str)
QString fromLocal8Bit(QByteArrayView str)
QString fromUtf8(QByteArrayView str)
bool isEmpty() const const
QString number(double n, char format, int precision)
EncodedData< QByteArrayView > decode(QByteArrayView ba)
QByteArray toPercentEncoding(const QString &input, const QByteArray &exclude, const QByteArray &include)