7 #include "messagepart.h"
8 #include "cryptohelper.h"
9 #include "job/qgpgmejobexecutor.h"
10 #include "memento/cryptobodypartmemento.h"
11 #include "memento/decryptverifybodypartmemento.h"
12 #include "memento/verifydetachedbodypartmemento.h"
13 #include "memento/verifyopaquebodypartmemento.h"
14 #include "mimetreeparser_debug.h"
15 #include "objecttreeparser.h"
17 #include "bodyformatter/utils.h"
19 #include <KMime/Content>
22 #include <QGpgME/ImportJob>
23 #include <QGpgME/KeyListJob>
24 #include <QGpgME/Protocol>
25 #include <QGpgME/VerifyDetachedJob>
26 #include <QGpgME/VerifyOpaqueJob>
28 #include <gpgme++/key.h>
29 #include <gpgme++/keylistresult.h>
32 #include <KLocalizedString>
37 using namespace MimeTreeParser;
40 namespace MimeTreeParser
42 class MessagePartPrivate
50 PartMetaData mMetaData;
52 bool mIsImage =
false;
53 bool mNeverDisplayInline =
false;
59 , d(new MessagePartPrivate)
64 MessagePart::~MessagePart() =
default;
68 return d->mParentPart;
71 void MessagePart::setParentPart(
MessagePart *parentPart)
73 d->mParentPart = parentPart;
76 QString MessagePart::htmlContent()
const
81 QString MessagePart::plaintextContent()
const
86 PartMetaData *MessagePart::partMetaData()
const
93 return nodeHelper()->bodyPartMemento(content(),
"__plugin__");
98 nodeHelper()->setBodyPartMemento(content(),
"__plugin__", memento);
113 return d->mAttachmentNode;
118 d->mAttachmentNode = node;
121 bool MessagePart::isAttachment()
const
123 return d->mAttachmentNode;
126 QString MessagePart::attachmentIndex()
const
128 return attachmentContent()->index().toString();
133 return mOtp->nodeHelper()->asHREF(content(), QStringLiteral(
"body"));
139 static int serial = 0;
143 return QStringLiteral(
"x-kmail:/bodypart/%1/%2/%3")
148 void MessagePart::setIsRoot(
bool root)
153 bool MessagePart::isRoot()
const
158 QString MessagePart::text()
const
163 void MessagePart::setText(
const QString &text)
168 bool MessagePart::isHtml()
const
176 return mOtp->mSource;
182 return mOtp->nodeHelper();
185 void MessagePart::parseInternal(
KMime::Content *node,
bool onlyOneMimePart)
187 auto subMessagePart = mOtp->parseObjectTreeInternal(node, onlyOneMimePart);
188 d->mRoot = subMessagePart->isRoot();
190 for (
const auto &part : subParts) {
195 QString MessagePart::renderInternalText()
const
198 const auto subPartsLst = subParts();
199 for (
const auto &mp : subPartsLst) {
205 void MessagePart::fix()
const
207 const auto subPartsLst = subParts();
208 for (
const auto &mp : subPartsLst) {
218 messagePart->setParentPart(
this);
219 d->mBlocks.append(messagePart);
227 bool MessagePart::hasSubParts()
const
232 void MessagePart::clearSubParts()
237 bool MessagePart::neverDisplayInline()
const
239 return d->mNeverDisplayInline;
242 void MessagePart::setNeverDisplayInline(
bool displayInline)
244 d->mNeverDisplayInline = displayInline;
247 bool MessagePart::isImage()
const
252 void MessagePart::setIsImage(
bool image)
257 bool MessagePart::hasHeader(
const char *headerType)
const
281 MessagePartList::~MessagePartList() =
default;
283 QString MessagePartList::text()
const
285 return renderInternalText();
288 QString MessagePartList::plaintextContent()
const
293 QString MessagePartList::htmlContent()
const
302 , mDecryptMessage(decryptMessage)
305 qCWarning(MIMETREEPARSER_LOG) <<
"not a valid node";
314 TextMessagePart::~TextMessagePart() =
default;
316 bool TextMessagePart::decryptMessage()
const
318 return mDecryptMessage;
321 void TextMessagePart::parseContent()
323 const auto aCodec = mOtp->codecFor(
content());
324 const QString &fromAddress = mOtp->nodeHelper()->fromAsString(
content());
325 mSignatureState = KMMsgNotSigned;
326 mEncryptionState = KMMsgNotEncrypted;
327 const auto blocks = prepareMessageForDecryption(
content()->decodedContent());
329 const auto cryptProto = QGpgME::openpgp();
331 if (!blocks.isEmpty()) {
339 bool fullySignedOrEncrypted =
true;
340 bool fullySignedOrEncryptedTmp =
true;
343 for (
const auto &block : blocks) {
345 if (!fullySignedOrEncryptedTmp) {
346 fullySignedOrEncrypted =
false;
349 if (block.type() == NoPgpBlock && !block.text().trimmed().isEmpty()) {
350 fullySignedOrEncryptedTmp =
false;
352 }
else if (block.type() == PgpMessageBlock) {
354 mp->setDecryptMessage(decryptMessage());
355 mp->setIsEncrypted(
true);
356 mp->setMementoName(mp->mementoName() +
"-" + nodeHelper()->asHREF(
content(),
QString::number(blockIndex)).toLocal8Bit());
358 if (!decryptMessage()) {
361 mp->startDecryption(block.text(), aCodec);
362 if (mp->partMetaData()->inProgress) {
365 }
else if (block.type() == ClearsignedBlock) {
367 mp->setMementoName(mp->mementoName() +
"-" + nodeHelper()->asHREF(
content(),
QString::number(blockIndex)).toLocal8Bit());
369 mp->startVerification(block.text(), aCodec);
375 const PartMetaData *messagePart(mp->partMetaData());
377 if (!messagePart->isEncrypted && !messagePart->isSigned && !block.text().trimmed().isEmpty()) {
378 mp->setText(aCodec->toUnicode(block.text()));
381 if (messagePart->isEncrypted) {
382 mEncryptionState = KMMsgPartiallyEncrypted;
385 if (messagePart->isSigned) {
386 mSignatureState = KMMsgPartiallySigned;
391 if (fullySignedOrEncrypted) {
392 if (mSignatureState == KMMsgPartiallySigned) {
393 mSignatureState = KMMsgFullySigned;
395 if (mEncryptionState == KMMsgPartiallyEncrypted) {
396 mEncryptionState = KMMsgFullyEncrypted;
402 KMMsgEncryptionState TextMessagePart::encryptionState()
const
404 return mEncryptionState;
407 KMMsgSignatureState TextMessagePart::signatureState()
const
409 return mSignatureState;
412 bool TextMessagePart::showLink()
const
417 bool TextMessagePart::isFirstTextPart()
const
422 bool TextMessagePart::hasLabel()
const
427 QString TextMessagePart::label()
const
432 label =
i18nc(
"display name for an unnamed attachment",
"Unnamed");
437 QString TextMessagePart::comment()
const
440 if (comment ==
label()) {
458 AttachmentMessagePart::~AttachmentMessagePart() =
default;
467 qCWarning(MIMETREEPARSER_LOG) <<
"not a valid node";
473 mBodyHTML = mOtp->codecFor(node)->
toUnicode(partBody);
477 HtmlMessagePart::~HtmlMessagePart() =
default;
479 void HtmlMessagePart::fix()
const
481 mOtp->mHtmlContent += mBodyHTML;
482 mOtp->mHtmlContentCharset = mCharset;
485 QString HtmlMessagePart::text()
const
490 QString MimeTreeParser::HtmlMessagePart::plaintextContent()
const
495 bool HtmlMessagePart::isHtml()
const
500 QString HtmlMessagePart::bodyHtml()
const
509 , mOnlyOneMimePart(onlyOneMimePart)
512 qCWarning(MIMETREEPARSER_LOG) <<
"not a valid node";
517 parseInternal(node, mOnlyOneMimePart);
520 MimeMessagePart::~MimeMessagePart() =
default;
522 QString MimeMessagePart::text()
const
524 return renderInternalText();
527 QString MimeMessagePart::plaintextContent()
const
532 QString MimeMessagePart::htmlContent()
const
541 , mPreferredMode(preferredMode)
544 KMime::Content *dataIcal = findTypeInDirectChilds(node,
"text/calendar");
545 KMime::Content *dataHtml = findTypeInDirectChilds(node,
"text/html");
546 KMime::Content *dataText = findTypeInDirectChilds(node,
"text/plain");
553 dataHtml = findTypeInDirectChilds(node,
"multipart/related");
561 dataHtml = findTypeInDirectChilds(node,
"multipart/mixed");
577 if (mChildNodes.isEmpty()) {
578 qCWarning(MIMETREEPARSER_LOG) <<
"no valid nodes";
583 while (i.hasNext()) {
589 AlternativeMessagePart::~AlternativeMessagePart() =
default;
593 return mPreferredMode;
596 void AlternativeMessagePart::setPreferredMode(
Util::HtmlMode preferredMode)
598 mPreferredMode = preferredMode;
603 return mChildParts.keys();
606 QString AlternativeMessagePart::text()
const
614 void AlternativeMessagePart::fix()
const
620 const auto mode = preferredMode();
622 mChildParts[mode]->fix();
631 bool AlternativeMessagePart::isHtml()
const
636 QString AlternativeMessagePart::plaintextContent()
const
641 QString AlternativeMessagePart::htmlContent()
const
646 return plaintextContent();
654 , mAutoImport(autoImport)
655 , mCryptoProto(cryptoProto)
658 qCWarning(MIMETREEPARSER_LOG) <<
"not a valid node";
669 QGpgME::ImportJob *
import = mCryptoProto->importJob();
671 mImportResult = executor.exec(
import, certData);
674 CertMessagePart::~CertMessagePart() =
default;
676 QString CertMessagePart::text()
const
681 const GpgME::ImportResult &CertMessagePart::importResult()
const
683 return mImportResult;
689 const QGpgME::Protocol *cryptoProto,
693 , mCryptoProto(cryptoProto)
694 , mFromAddress(fromAddress)
695 , mMementoName(
"verification")
698 partMetaData()->technicalProblem = (mCryptoProto ==
nullptr);
699 partMetaData()->isSigned =
true;
700 partMetaData()->isGoodSignature =
false;
701 partMetaData()->keyTrust = GpgME::Signature::Unknown;
702 partMetaData()->status =
i18n(
"Wrong Crypto Plug-In.");
703 partMetaData()->status_code = GPGME_SIG_STAT_NONE;
706 SignedMessagePart::~SignedMessagePart() =
default;
708 void SignedMessagePart::setIsSigned(
bool isSigned)
710 partMetaData()->isSigned = isSigned;
713 bool SignedMessagePart::isSigned()
const
715 return partMetaData()->isSigned;
718 QByteArray SignedMessagePart::mementoName()
const
723 void SignedMessagePart::setMementoName(
const QByteArray &name)
732 partMetaData()->isSigned =
false;
733 partMetaData()->technicalProblem = (mCryptoProto ==
nullptr);
734 partMetaData()->keyTrust = GpgME::Signature::Unknown;
735 partMetaData()->status =
i18n(
"Wrong Crypto Plug-In.");
736 partMetaData()->status_code = GPGME_SIG_STAT_NONE;
738 const QByteArray _mementoName = mementoName();
740 auto m =
dynamic_cast<CryptoBodyPartMemento *
>(nodeHelper->bodyPartMemento(
content(), _mementoName));
741 Q_ASSERT(!m || mCryptoProto);
743 if (!m && mCryptoProto) {
745 QGpgME::VerifyDetachedJob *job = mCryptoProto->verifyDetachedJob();
747 m =
new VerifyDetachedBodyPartMemento(job, mCryptoProto->keyListJob(), signature, data);
750 QGpgME::VerifyOpaqueJob *job = mCryptoProto->verifyOpaqueJob();
752 m =
new VerifyOpaqueBodyPartMemento(job, mCryptoProto->keyListJob(), data);
756 if (mOtp->allowAsync()) {
757 QObject::connect(m, &CryptoBodyPartMemento::update, nodeHelper, &NodeHelper::update);
759 partMetaData()->inProgress =
true;
760 mOtp->mHasPendingAsyncJobs =
true;
765 nodeHelper->setBodyPartMemento(
content(), _mementoName, m);
767 }
else if (m && m->isRunning()) {
768 partMetaData()->inProgress =
true;
769 mOtp->mHasPendingAsyncJobs =
true;
771 partMetaData()->inProgress =
false;
772 mOtp->mHasPendingAsyncJobs =
false;
775 if (m && !partMetaData()->inProgress) {
777 mVerifiedText = data;
779 setVerificationResult(m, textNode);
782 if (!m && !partMetaData()->inProgress) {
787 cryptPlugLibName = mCryptoProto->name();
788 cryptPlugDisplayName = mCryptoProto->displayName();
792 if (cryptPlugDisplayName.
isEmpty()) {
793 errorMsg =
i18n(
"No appropriate crypto plug-in was found.");
795 errorMsg =
i18nc(
"%1 is either 'OpenPGP' or 'S/MIME'",
"No %1 plug-in was found.", cryptPlugDisplayName);
798 errorMsg =
i18n(
"Crypto plug-in \"%1\" cannot verify signatures.", cryptPlugLibName);
800 partMetaData()->errorText =
i18n(
801 "The message is signed, but the "
802 "validity of the signature cannot be "
808 return partMetaData()->isSigned;
811 static int signatureToStatus(
const GpgME::Signature &sig)
813 switch (sig.status().code()) {
814 case GPG_ERR_NO_ERROR:
815 return GPGME_SIG_STAT_GOOD;
816 case GPG_ERR_BAD_SIGNATURE:
817 return GPGME_SIG_STAT_BAD;
818 case GPG_ERR_NO_PUBKEY:
819 return GPGME_SIG_STAT_NOKEY;
820 case GPG_ERR_NO_DATA:
821 return GPGME_SIG_STAT_NOSIG;
822 case GPG_ERR_SIG_EXPIRED:
823 return GPGME_SIG_STAT_GOOD_EXP;
824 case GPG_ERR_KEY_EXPIRED:
825 return GPGME_SIG_STAT_GOOD_EXPKEY;
827 return GPGME_SIG_STAT_ERROR;
831 QString prettifyDN(
const char *uid)
833 return QGpgME::DN(uid).prettyDN();
836 void SignedMessagePart::sigStatusToMetaData()
839 if (partMetaData()->isSigned) {
840 GpgME::Signature signature = mSignatures.front();
841 partMetaData()->status_code = signatureToStatus(signature);
842 partMetaData()->isGoodSignature = partMetaData()->status_code & GPGME_SIG_STAT_GOOD;
844 partMetaData()->sigSummary = signature.summary();
846 if (partMetaData()->isGoodSignature && !key.keyID()) {
849 QGpgME::KeyListJob *job = mCryptoProto->keyListJob(
false,
false,
false);
851 qCDebug(MIMETREEPARSER_LOG) <<
"The Crypto backend does not support listing keys. ";
853 std::vector<GpgME::Key> found_keys;
857 qCDebug(MIMETREEPARSER_LOG) <<
"Error while searching key for Fingerprint: " << signature.fingerprint();
859 if (found_keys.size() > 1) {
861 qCDebug(MIMETREEPARSER_LOG) <<
"Oops: Found more then one Key for Fingerprint: " << signature.fingerprint();
863 if (found_keys.size() != 1) {
865 qCDebug(MIMETREEPARSER_LOG) <<
"Oops: Found no Key for Fingerprint: " << signature.fingerprint();
874 partMetaData()->keyId = key.keyID();
876 if (partMetaData()->keyId.isEmpty()) {
877 partMetaData()->keyId = signature.fingerprint();
879 partMetaData()->keyTrust = signature.validity();
880 if (key.numUserIDs() > 0 && key.userID(0).id()) {
881 partMetaData()->signer = prettifyDN(key.userID(0).id());
883 for (uint iMail = 0; iMail < key.numUserIDs(); ++iMail) {
886 if (key.userID(iMail).email()) {
891 email = email.
mid(1, email.
length() - 2);
894 partMetaData()->signerMailAddresses.append(email);
899 if (signature.creationTime()) {
900 partMetaData()->creationTime.setSecsSinceEpoch(signature.creationTime());
902 partMetaData()->creationTime =
QDateTime();
904 if (partMetaData()->signer.isEmpty()) {
905 if (key.numUserIDs() > 0 && key.userID(0).name()) {
906 partMetaData()->signer = prettifyDN(key.userID(0).name());
908 if (!partMetaData()->signerMailAddresses.empty()) {
909 if (partMetaData()->signer.isEmpty()) {
910 partMetaData()->signer = partMetaData()->signerMailAddresses.front();
921 startVerificationDetached(text,
nullptr,
QByteArray());
923 if (!
content() && partMetaData()->isSigned) {
924 setText(aCodec->
toUnicode(mVerifiedText));
930 partMetaData()->isEncrypted =
false;
931 partMetaData()->isDecryptable =
false;
934 parseInternal(textNode,
false);
937 if (!okVerify(text, signature, textNode)) {
938 partMetaData()->creationTime =
QDateTime();
942 void SignedMessagePart::setVerificationResult(
const CryptoBodyPartMemento *m,
KMime::Content *textNode)
945 const auto vm =
dynamic_cast<const VerifyDetachedBodyPartMemento *
>(m);
947 mSignatures = vm->verifyResult().signatures();
951 const auto vm =
dynamic_cast<const VerifyOpaqueBodyPartMemento *
>(m);
953 mVerifiedText = vm->plainText();
954 mSignatures = vm->verifyResult().signatures();
958 const auto vm =
dynamic_cast<const DecryptVerifyBodyPartMemento *
>(m);
960 mVerifiedText = vm->plainText();
961 mSignatures = vm->verifyResult().signatures();
964 partMetaData()->auditLogError = m->auditLogError();
965 partMetaData()->auditLog = m->auditLogAsHtml();
966 partMetaData()->isSigned = !mSignatures.empty();
968 if (partMetaData()->isSigned) {
969 sigStatusToMetaData();
971 mOtp->nodeHelper()->setSignatureState(
content(), KMMsgFullySigned);
973 mOtp->nodeHelper()->setPartMetaData(
content(), *partMetaData());
975 if (!mVerifiedText.
isEmpty()) {
977 tempNode->setContent(KMime::CRLFtoLF(mVerifiedText.
constData()));
980 if (!tempNode->head().isEmpty()) {
981 tempNode->contentDescription()->from7BitString(
"signed data");
985 parseInternal(tempNode,
false);
992 QString SignedMessagePart::plaintextContent()
const
995 return MessagePart::text();
1001 QString SignedMessagePart::htmlContent()
const
1004 return MessagePart::text();
1010 const QGpgME::Protocol *SignedMessagePart::cryptoProto()
const
1012 return mCryptoProto;
1015 QString SignedMessagePart::fromAddress()
const
1017 return mFromAddress;
1020 bool SignedMessagePart::hasHeader(
const char *headerType)
const
1028 const KMime::Headers::Base *MimeTreeParser::SignedMessagePart::header(
const char *headerType)
const
1031 return content()->headerByType(headerType);
1047 const QGpgME::Protocol *cryptoProto,
1051 , mPassphraseError(false)
1053 , mDecryptMessage(false)
1054 , mCryptoProto(cryptoProto)
1055 , mFromAddress(fromAddress)
1056 , mMementoName(
"decryptverify")
1059 partMetaData()->technicalProblem = (mCryptoProto ==
nullptr);
1060 partMetaData()->isSigned =
false;
1061 partMetaData()->isGoodSignature =
false;
1062 partMetaData()->isEncrypted =
false;
1063 partMetaData()->isDecryptable =
false;
1064 partMetaData()->keyTrust = GpgME::Signature::Unknown;
1065 partMetaData()->status =
i18n(
"Wrong Crypto Plug-In.");
1066 partMetaData()->status_code = GPGME_SIG_STAT_NONE;
1069 EncryptedMessagePart::~EncryptedMessagePart() =
default;
1071 void EncryptedMessagePart::setDecryptMessage(
bool decrypt)
1073 mDecryptMessage = decrypt;
1076 bool EncryptedMessagePart::decryptMessage()
const
1078 return mDecryptMessage;
1081 void EncryptedMessagePart::setIsEncrypted(
bool encrypted)
1083 partMetaData()->isEncrypted = encrypted;
1086 bool EncryptedMessagePart::isEncrypted()
const
1088 return partMetaData()->isEncrypted;
1091 bool EncryptedMessagePart::isDecryptable()
const
1093 return partMetaData()->isDecryptable;
1096 bool EncryptedMessagePart::isNoSecKey()
const
1101 bool EncryptedMessagePart::passphraseError()
const
1103 return mPassphraseError;
1106 QByteArray EncryptedMessagePart::mementoName()
const
1108 return mMementoName;
1111 void EncryptedMessagePart::setMementoName(
const QByteArray &name)
1113 mMementoName =
name;
1124 if (!partMetaData()->inProgress && partMetaData()->isDecryptable) {
1125 if (hasSubParts()) {
1126 auto _mp = (subParts()[0]).dynamicCast<SignedMessagePart>();
1128 _mp->setText(aCodec->
toUnicode(mDecryptedData));
1130 setText(aCodec->
toUnicode(mDecryptedData));
1133 setText(aCodec->
toUnicode(mDecryptedData));
1141 mPassphraseError =
false;
1142 partMetaData()->inProgress =
false;
1143 partMetaData()->errorText.clear();
1144 partMetaData()->auditLogError = GpgME::Error();
1145 partMetaData()->auditLog.clear();
1146 bool bDecryptionOk =
false;
1147 bool cannotDecrypt =
false;
1150 Q_ASSERT(decryptMessage());
1152 const QByteArray _mementoName = mementoName();
1154 const DecryptVerifyBodyPartMemento *m =
dynamic_cast<DecryptVerifyBodyPartMemento *
>(nodeHelper->bodyPartMemento(&data, _mementoName));
1156 Q_ASSERT(!m || mCryptoProto);
1158 if (!m && mCryptoProto) {
1159 QGpgME::DecryptVerifyJob *job = mCryptoProto->decryptVerifyJob();
1161 cannotDecrypt =
true;
1164 auto newM =
new DecryptVerifyBodyPartMemento(job, ciphertext);
1165 if (mOtp->allowAsync()) {
1166 QObject::connect(newM, &CryptoBodyPartMemento::update, nodeHelper, &NodeHelper::update);
1167 if (newM->start()) {
1168 partMetaData()->inProgress =
true;
1169 mOtp->mHasPendingAsyncJobs =
true;
1177 nodeHelper->setBodyPartMemento(&data, _mementoName, newM);
1179 }
else if (m && m->isRunning()) {
1180 partMetaData()->inProgress =
true;
1181 mOtp->mHasPendingAsyncJobs =
true;
1186 const QByteArray &plainText = m->plainText();
1187 const GpgME::DecryptionResult &decryptResult = m->decryptResult();
1188 const GpgME::VerificationResult &verifyResult = m->verifyResult();
1189 partMetaData()->isSigned = verifyResult.signatures().size() > 0;
1191 if (partMetaData()->isSigned) {
1193 subPart->setVerificationResult(m,
nullptr);
1194 appendSubPart(subPart);
1197 mDecryptRecipients.clear();
1198 bDecryptionOk = !decryptResult.error();
1204 for (
const auto &recipient : decryptResult.recipients()) {
1205 if (!recipient.status()) {
1206 bDecryptionOk =
true;
1209 QGpgME::KeyListJob *job = mCryptoProto->keyListJob(
false,
false,
false);
1211 qCDebug(MIMETREEPARSER_LOG) <<
"The Crypto backend does not support listing keys. ";
1213 std::vector<GpgME::Key> found_keys;
1217 qCDebug(MIMETREEPARSER_LOG) <<
"Error while searching key for Fingerprint: " << recipient.keyID();
1219 if (found_keys.size() > 1) {
1221 qCDebug(MIMETREEPARSER_LOG) <<
"Oops: Found more then one Key for Fingerprint: " << recipient.keyID();
1223 if (found_keys.size() != 1) {
1225 qCDebug(MIMETREEPARSER_LOG) <<
"Oops: Found no Key for Fingerprint: " << recipient.keyID();
1227 key = found_keys[0];
1230 mDecryptRecipients.emplace_back(recipient, key);
1233 if (!bDecryptionOk && partMetaData()->isSigned) {
1235 partMetaData()->isEncrypted =
false;
1236 bDecryptionOk =
true;
1237 mDecryptedData = plainText;
1239 mPassphraseError = decryptResult.error().isCanceled() || decryptResult.error().code() == GPG_ERR_NO_SECKEY;
1240 partMetaData()->isEncrypted = bDecryptionOk || decryptResult.error().code() != GPG_ERR_NO_DATA;
1242 if (decryptResult.error().isCanceled()) {
1243 setDecryptMessage(
false);
1247 if (partMetaData()->isEncrypted && decryptResult.numRecipients() > 0) {
1248 partMetaData()->keyId = decryptResult.recipient(0).keyID();
1251 if (bDecryptionOk) {
1252 mDecryptedData = plainText;
1255 const auto decryRecipients = decryptResult.recipients();
1256 for (
const GpgME::DecryptionResult::Recipient &recipient : decryRecipients) {
1257 mNoSecKey &= (recipient.status().code() == GPG_ERR_NO_SECKEY);
1259 if (!mPassphraseError && !mNoSecKey) {
1260 mPassphraseError =
true;
1266 if (!bDecryptionOk) {
1269 cryptPlugLibName = mCryptoProto->name();
1272 if (!mCryptoProto) {
1273 partMetaData()->errorText =
i18n(
"No appropriate crypto plug-in was found.");
1274 }
else if (cannotDecrypt) {
1275 partMetaData()->errorText =
i18n(
"Crypto plug-in \"%1\" cannot decrypt messages.", cryptPlugLibName);
1276 }
else if (!passphraseError()) {
1277 partMetaData()->errorText =
i18n(
"Crypto plug-in \"%1\" could not decrypt the data.", cryptPlugLibName) +
QLatin1String(
"<br />")
1278 +
i18n(
"Error: %1", partMetaData()->errorText);
1281 return bDecryptionOk;
1294 partMetaData()->isEncrypted =
true;
1296 bool bOkDecrypt = okDecryptMIME(*data);
1298 if (partMetaData()->inProgress) {
1301 partMetaData()->isDecryptable = bOkDecrypt;
1303 if (!partMetaData()->isDecryptable) {
1307 if (partMetaData()->isEncrypted && !decryptMessage()) {
1308 partMetaData()->isDecryptable =
true;
1311 if (
content() && !partMetaData()->isSigned) {
1312 mOtp->nodeHelper()->setPartMetaData(
content(), *partMetaData());
1314 if (decryptMessage()) {
1316 tempNode->setContent(KMime::CRLFtoLF(mDecryptedData.
constData()));
1319 if (!tempNode->head().isEmpty()) {
1320 tempNode->contentDescription()->from7BitString(
"encrypted data");
1324 parseInternal(tempNode,
false);
1329 QString EncryptedMessagePart::plaintextContent()
const
1332 return MessagePart::text();
1338 QString EncryptedMessagePart::htmlContent()
const
1341 return MessagePart::text();
1347 QString EncryptedMessagePart::text()
const
1349 if (hasSubParts()) {
1350 auto _mp = (subParts()[0]).dynamicCast<SignedMessagePart>();
1354 return MessagePart::text();
1357 return MessagePart::text();
1361 const QGpgME::Protocol *EncryptedMessagePart::cryptoProto()
const
1363 return mCryptoProto;
1366 QString EncryptedMessagePart::fromAddress()
const
1368 return mFromAddress;
1371 const std::vector<std::pair<GpgME::DecryptionResult::Recipient, GpgME::Key>> &EncryptedMessagePart::decryptRecipients()
const
1373 return mDecryptRecipients;
1376 bool EncryptedMessagePart::hasHeader(
const char *headerType)
const
1378 const auto extraContent = mOtp->nodeHelper()->decryptedNodeForContent(
content());
1380 return nodeHelper()->hasMailHeader(headerType, extraContent);
1387 const auto extraContent = mOtp->nodeHelper()->decryptedNodeForContent(
content());
1389 return nodeHelper()->mailHeaderAsBase(headerType, extraContent);
1396 const auto extraContent = mOtp->nodeHelper()->decryptedNodeForContent(
content());
1398 return nodeHelper()->headers(headerType, extraContent);
1408 partMetaData()->isEncrypted =
false;
1409 partMetaData()->isSigned =
false;
1410 partMetaData()->isEncapsulatedRfc822Message =
true;
1412 mOtp->nodeHelper()->setNodeDisplayedEmbedded(node,
true);
1413 mOtp->nodeHelper()->setPartMetaData(node, *partMetaData());
1416 qCWarning(MIMETREEPARSER_LOG) <<
"Node is of type message/rfc822 but doesn't have a message!";
1427 EncapsulatedRfc822MessagePart::~EncapsulatedRfc822MessagePart() =
default;
1429 QString EncapsulatedRfc822MessagePart::text()
const
1431 return renderInternalText();
1434 void EncapsulatedRfc822MessagePart::fix()
const