File indexing completed on 2025-01-26 04:58:14
0001 /* 0002 Copyright (c) 2015 Sandro Knauß <sknauss@kde.org> 0003 Copyright (c) 2017 Christian Mollekopf <mollekopf@kolabsys.com> 0004 0005 This library is free software; you can redistribute it and/or modify it 0006 under the terms of the GNU Library General Public License as published by 0007 the Free Software Foundation; either version 2 of the License, or (at your 0008 option) any later version. 0009 0010 This library is distributed in the hope that it will be useful, but WITHOUT 0011 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0012 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 0013 License for more details. 0014 0015 You should have received a copy of the GNU Library General Public License 0016 along with this library; see the file COPYING.LIB. If not, write to the 0017 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 0018 02110-1301, USA. 0019 */ 0020 0021 #include "messagepart.h" 0022 #include "mimetreeparser_debug.h" 0023 #include "cryptohelper.h" 0024 #include "objecttreeparser.h" 0025 0026 #include "utils.h" 0027 0028 #include <KMime/Content> 0029 0030 #include <QTextCodec> 0031 0032 using namespace MimeTreeParser; 0033 using namespace Crypto; 0034 0035 //------MessagePart----------------------- 0036 MessagePart::MessagePart(ObjectTreeParser *otp, const QString &text, KMime::Content *node) 0037 : mText(text) 0038 , mOtp(otp) 0039 , mParentPart(nullptr) 0040 , mNode(node) //only null for messagepartlist 0041 , mError(NoError) 0042 , mRoot(false) 0043 { 0044 } 0045 0046 MessagePart::~MessagePart() 0047 { 0048 for (auto n : mNodesToDelete) { 0049 delete n; 0050 } 0051 } 0052 0053 MessagePart::Disposition MessagePart::disposition() const 0054 { 0055 if (!mNode) { 0056 return Invalid; 0057 } 0058 const auto cd = mNode->contentDisposition(false); 0059 if (!cd) { 0060 return Invalid; 0061 } 0062 switch (cd->disposition()){ 0063 case KMime::Headers::CDinline: 0064 return Inline; 0065 case KMime::Headers::CDattachment: 0066 return Attachment; 0067 default: 0068 return Invalid; 0069 } 0070 } 0071 0072 QString MessagePart::filename() const 0073 { 0074 if (!mNode) { 0075 return {}; 0076 } 0077 0078 if (const auto cd = mNode->contentDisposition(false)) { 0079 const auto name = cd->filename(); 0080 //Allow for a fallback for mails that have a ContentDisposition header, but don't set the filename anyways. 0081 //Not the recommended way, but exists. 0082 if (!name.isEmpty()) { 0083 return name; 0084 } 0085 } 0086 if (const auto ct = mNode->contentType(false)) { 0087 return ct->name(); 0088 } 0089 return {}; 0090 } 0091 0092 static KMime::Headers::ContentType *contentType(KMime::Content *node) 0093 { 0094 if (node) { 0095 return node->contentType(false); 0096 } 0097 return nullptr; 0098 } 0099 0100 QByteArray MessagePart::charset() const 0101 { 0102 if (!mNode) { 0103 return "us-ascii"; 0104 } 0105 if (auto ct = contentType(mNode)) { 0106 return ct->charset(); 0107 } 0108 // Per rfc2045 us-ascii is the default 0109 return "us-ascii"; 0110 } 0111 0112 QByteArray MessagePart::mimeType() const 0113 { 0114 if (auto ct = contentType(mNode)) { 0115 return ct->mimeType(); 0116 } 0117 return {}; 0118 } 0119 0120 bool MessagePart::isText() const 0121 { 0122 if (auto ct = contentType(mNode)) { 0123 return ct->isText(); 0124 } 0125 return false; 0126 } 0127 0128 MessagePart::Error MessagePart::error() const 0129 { 0130 return mError; 0131 } 0132 0133 QString MessagePart::errorString() const 0134 { 0135 return mMetaData.errorText; 0136 } 0137 0138 PartMetaData *MessagePart::partMetaData() 0139 { 0140 return &mMetaData; 0141 } 0142 0143 bool MessagePart::isAttachment() const 0144 { 0145 if (mNode) { 0146 return KMime::isAttachment(mNode); 0147 } 0148 return false; 0149 } 0150 0151 KMime::Content *MessagePart::node() const 0152 { 0153 return mNode; 0154 } 0155 0156 void MessagePart::setIsRoot(bool root) 0157 { 0158 mRoot = root; 0159 } 0160 0161 bool MessagePart::isRoot() const 0162 { 0163 return mRoot; 0164 } 0165 0166 QString MessagePart::text() const 0167 { 0168 return mText; 0169 } 0170 0171 void MessagePart::setText(const QString &text) 0172 { 0173 mText = text; 0174 } 0175 0176 bool MessagePart::isHtml() const 0177 { 0178 return false; 0179 } 0180 0181 MessagePart *MessagePart::parentPart() const 0182 { 0183 return mParentPart; 0184 } 0185 0186 void MessagePart::setParentPart(MessagePart *parentPart) 0187 { 0188 mParentPart = parentPart; 0189 } 0190 0191 QString MessagePart::htmlContent() const 0192 { 0193 return text(); 0194 } 0195 0196 QString MessagePart::plaintextContent() const 0197 { 0198 return text(); 0199 } 0200 0201 0202 0203 void MessagePart::parseInternal(KMime::Content *node, bool onlyOneMimePart) 0204 { 0205 auto subMessagePart = mOtp->parseObjectTreeInternal(node, onlyOneMimePart); 0206 mRoot = subMessagePart->isRoot(); 0207 foreach (const auto &part, subMessagePart->subParts()) { 0208 appendSubPart(part); 0209 } 0210 } 0211 0212 void MessagePart::parseInternal(const QByteArray &data) 0213 { 0214 auto tempNode = new KMime::Content(); 0215 0216 const auto lfData = KMime::CRLFtoLF(data); 0217 //We have to deal with both bodies and full parts. In inline encrypted/signed parts we can have nested parts, 0218 //or just plain-text, and both ends up here. setContent defaults to setting only the header, so we have to avoid this. 0219 if (lfData.contains("\n\n")) { 0220 tempNode->setContent(lfData); 0221 } else { 0222 tempNode->setBody(lfData); 0223 } 0224 tempNode->parse(); 0225 tempNode->contentType()->setCharset(charset()); 0226 bindLifetime(tempNode); 0227 0228 if (!tempNode->head().isEmpty()) { 0229 tempNode->contentDescription()->from7BitString("temporary node"); 0230 } 0231 0232 parseInternal(tempNode); 0233 } 0234 0235 QString MessagePart::renderInternalText() const 0236 { 0237 QString text; 0238 foreach (const auto &mp, subParts()) { 0239 text += mp->text(); 0240 } 0241 return text; 0242 } 0243 0244 void MessagePart::appendSubPart(const MessagePart::Ptr &messagePart) 0245 { 0246 messagePart->setParentPart(this); 0247 mBlocks.append(messagePart); 0248 } 0249 0250 const QVector<MessagePart::Ptr> &MessagePart::subParts() const 0251 { 0252 return mBlocks; 0253 } 0254 0255 bool MessagePart::hasSubParts() const 0256 { 0257 return !mBlocks.isEmpty(); 0258 } 0259 0260 QVector<SignedMessagePart*> MessagePart::signatures() const 0261 { 0262 QVector<SignedMessagePart*> list; 0263 if (auto sig = dynamic_cast<SignedMessagePart*>(const_cast<MessagePart*>(this))) { 0264 list << sig; 0265 } 0266 auto parent = parentPart(); 0267 while (parent) { 0268 if (auto sig = dynamic_cast<SignedMessagePart*>(parent)) { 0269 list << sig; 0270 } 0271 parent = parent->parentPart(); 0272 } 0273 return list; 0274 } 0275 0276 QVector<EncryptedMessagePart*> MessagePart::encryptions() const 0277 { 0278 QVector<EncryptedMessagePart*> list; 0279 if (auto sig = dynamic_cast<EncryptedMessagePart*>(const_cast<MessagePart*>(this))) { 0280 list << sig; 0281 } 0282 auto parent = parentPart(); 0283 while (parent) { 0284 if (auto sig = dynamic_cast<EncryptedMessagePart*>(parent)) { 0285 list << sig; 0286 } 0287 parent = parent->parentPart(); 0288 } 0289 return list; 0290 } 0291 0292 KMMsgEncryptionState MessagePart::encryptionState() const 0293 { 0294 if (!encryptions().isEmpty()) { 0295 return KMMsgFullyEncrypted; 0296 } 0297 return KMMsgNotEncrypted; 0298 } 0299 0300 KMMsgSignatureState MessagePart::signatureState() const 0301 { 0302 if (!signatures().isEmpty()) { 0303 return KMMsgFullySigned; 0304 } 0305 return KMMsgNotSigned; 0306 } 0307 0308 void MessagePart::bindLifetime(KMime::Content *node) 0309 { 0310 mNodesToDelete << node; 0311 } 0312 0313 KMime::Headers::Base *MimeTreeParser::MessagePart::header(const char *header) const 0314 { 0315 if (node() && node()->hasHeader(header)) { 0316 return node()->headerByType(header); 0317 } 0318 if (auto parent = parentPart()) { 0319 return parent->header(header); 0320 } 0321 0322 return nullptr; 0323 } 0324 0325 //-----MessagePartList---------------------- 0326 MessagePartList::MessagePartList(ObjectTreeParser *otp, KMime::Content *node) 0327 : MessagePart(otp, QString(), node) 0328 { 0329 } 0330 0331 QString MessagePartList::text() const 0332 { 0333 return renderInternalText(); 0334 } 0335 0336 QString MessagePartList::plaintextContent() const 0337 { 0338 return QString(); 0339 } 0340 0341 QString MessagePartList::htmlContent() const 0342 { 0343 return QString(); 0344 } 0345 0346 //-----TextMessageBlock---------------------- 0347 0348 TextMessagePart::TextMessagePart(ObjectTreeParser *otp, KMime::Content *node) 0349 : MessagePartList(otp, node), 0350 mSignatureState(KMMsgSignatureStateUnknown), 0351 mEncryptionState(KMMsgEncryptionStateUnknown) 0352 { 0353 if (!mNode) { 0354 qCWarning(MIMETREEPARSER_LOG) << "not a valid node"; 0355 return; 0356 } 0357 0358 0359 parseContent(); 0360 } 0361 0362 void TextMessagePart::parseContent() 0363 { 0364 mSignatureState = KMMsgNotSigned; 0365 mEncryptionState = KMMsgNotEncrypted; 0366 const auto blocks = prepareMessageForDecryption(mNode->decodedContent()); 0367 // We also get blocks for unencrypted messages 0368 if (!blocks.isEmpty()) { 0369 const auto aCodec = mOtp->codecFor(mNode); 0370 const auto cryptProto = OpenPGP; 0371 0372 /* The (overall) signature/encrypted status is broken 0373 * if one unencrypted part is at the beginning or in the middle 0374 * because mailmain adds an unencrypted part at the end this should not break the overall status 0375 * 0376 * That's why we first set the tmp status and if one crypted/signed block comes afterwards, than 0377 * the status is set to unencryped 0378 */ 0379 bool fullySignedOrEncrypted = true; 0380 bool fullySignedOrEncryptedTmp = true; 0381 0382 for (const auto &block : blocks) { 0383 0384 if (!fullySignedOrEncryptedTmp) { 0385 fullySignedOrEncrypted = false; 0386 } 0387 0388 if (block.type() == NoPgpBlock && !block.text().trimmed().isEmpty()) { 0389 fullySignedOrEncryptedTmp = false; 0390 appendSubPart(MessagePart::Ptr(new MessagePart(mOtp, aCodec->toUnicode(KMime::CRLFtoLF(block.text()))))); 0391 } else if (block.type() == PgpMessageBlock) { 0392 KMime::Content *content = new KMime::Content; 0393 content->setBody(block.text()); 0394 content->parse(); 0395 content->contentType()->setCharset(charset()); 0396 EncryptedMessagePart::Ptr mp(new EncryptedMessagePart(mOtp, QString(), cryptProto, content, content, false)); 0397 mp->bindLifetime(content); 0398 mp->setIsEncrypted(true); 0399 appendSubPart(mp); 0400 } else if (block.type() == ClearsignedBlock) { 0401 KMime::Content *content = new KMime::Content; 0402 content->setBody(block.text()); 0403 content->parse(); 0404 content->contentType()->setCharset(charset()); 0405 SignedMessagePart::Ptr mp(new SignedMessagePart(mOtp, cryptProto, nullptr, content, false)); 0406 mp->bindLifetime(content); 0407 mp->setIsSigned(true); 0408 appendSubPart(mp); 0409 } else { 0410 continue; 0411 } 0412 0413 const auto mp = subParts().last().staticCast<MessagePart>(); 0414 const PartMetaData *messagePart(mp->partMetaData()); 0415 0416 if (!messagePart->isEncrypted && !messagePart->isSigned && !block.text().trimmed().isEmpty()) { 0417 mp->setText(aCodec->toUnicode(KMime::CRLFtoLF(block.text()))); 0418 } 0419 0420 if (messagePart->isEncrypted) { 0421 mEncryptionState = KMMsgPartiallyEncrypted; 0422 } 0423 0424 if (messagePart->isSigned) { 0425 mSignatureState = KMMsgPartiallySigned; 0426 } 0427 } 0428 0429 //Do we have an fully Signed/Encrypted Message? 0430 if (fullySignedOrEncrypted) { 0431 if (mSignatureState == KMMsgPartiallySigned) { 0432 mSignatureState = KMMsgFullySigned; 0433 } 0434 if (mEncryptionState == KMMsgPartiallyEncrypted) { 0435 mEncryptionState = KMMsgFullyEncrypted; 0436 } 0437 } 0438 } 0439 } 0440 0441 KMMsgEncryptionState TextMessagePart::encryptionState() const 0442 { 0443 if (mEncryptionState == KMMsgNotEncrypted) { 0444 return MessagePart::encryptionState(); 0445 } 0446 return mEncryptionState; 0447 } 0448 0449 KMMsgSignatureState TextMessagePart::signatureState() const 0450 { 0451 if (mSignatureState == KMMsgNotSigned) { 0452 return MessagePart::signatureState(); 0453 } 0454 return mSignatureState; 0455 } 0456 0457 //-----AttachmentMessageBlock---------------------- 0458 0459 AttachmentMessagePart::AttachmentMessagePart(ObjectTreeParser *otp, KMime::Content *node) 0460 : TextMessagePart(otp, node) 0461 { 0462 0463 } 0464 0465 0466 //-----HtmlMessageBlock---------------------- 0467 0468 HtmlMessagePart::HtmlMessagePart(ObjectTreeParser *otp, KMime::Content *node) 0469 : MessagePart(otp, QString(), node) 0470 { 0471 if (!mNode) { 0472 qCWarning(MIMETREEPARSER_LOG) << "not a valid node"; 0473 return; 0474 } 0475 0476 setText(mOtp->codecFor(mNode)->toUnicode(KMime::CRLFtoLF(mNode->decodedContent()))); 0477 } 0478 0479 //-----MimeMessageBlock---------------------- 0480 0481 MimeMessagePart::MimeMessagePart(ObjectTreeParser *otp, KMime::Content *node, bool onlyOneMimePart) 0482 : MessagePart(otp, QString(), node) 0483 { 0484 if (!mNode) { 0485 qCWarning(MIMETREEPARSER_LOG) << "not a valid node"; 0486 return; 0487 } 0488 0489 parseInternal(mNode, onlyOneMimePart); 0490 } 0491 0492 MimeMessagePart::~MimeMessagePart() 0493 { 0494 0495 } 0496 0497 QString MimeMessagePart::text() const 0498 { 0499 return renderInternalText(); 0500 } 0501 0502 QString MimeMessagePart::plaintextContent() const 0503 { 0504 return QString(); 0505 } 0506 0507 QString MimeMessagePart::htmlContent() const 0508 { 0509 return QString(); 0510 } 0511 0512 //-----AlternativeMessagePart---------------------- 0513 0514 AlternativeMessagePart::AlternativeMessagePart(ObjectTreeParser *otp, KMime::Content *node) 0515 : MessagePart(otp, QString(), node) 0516 { 0517 if (auto dataIcal = findTypeInDirectChildren(mNode, "text/calendar")) { 0518 mChildParts[MultipartIcal] = MimeMessagePart::Ptr(new MimeMessagePart(mOtp, dataIcal, true)); 0519 } 0520 0521 if (auto dataText = findTypeInDirectChildren(mNode, "text/plain")) { 0522 mChildParts[MultipartPlain] = MimeMessagePart::Ptr(new MimeMessagePart(mOtp, dataText, true)); 0523 } 0524 0525 if (auto dataHtml = findTypeInDirectChildren(mNode, "text/html")) { 0526 mChildParts[MultipartHtml] = MimeMessagePart::Ptr(new MimeMessagePart(mOtp, dataHtml, true)); 0527 } else { 0528 // If we didn't find the HTML part as the first child of the multipart/alternative, it might 0529 // be that this is a HTML message with images, and text/plain and multipart/related are the 0530 // immediate children of this multipart/alternative node. 0531 // In this case, the HTML node is a child of multipart/related. 0532 // In the case of multipart/related we don't expect multiple html parts, it is usually used to group attachments 0533 // with html content. 0534 // 0535 // In any case, this is not a complete implementation of MIME, but an approximation for the kind of mails we actually see in the wild. 0536 auto data = [&] { 0537 if (auto d = findTypeInDirectChildren(mNode, "multipart/related")) { 0538 return d; 0539 } 0540 return findTypeInDirectChildren(mNode, "multipart/mixed"); 0541 }(); 0542 if (data) { 0543 QString htmlContent; 0544 const auto parts = data->contents(); 0545 for (auto p : data->contents()) { 0546 if ((!p->contentType()->isEmpty()) 0547 && (p->contentType()->mimeType() == "text/html")) { 0548 htmlContent += MimeMessagePart(mOtp, p, true).text(); 0549 } else if (KMime::isAttachment(p)) { 0550 appendSubPart(MimeMessagePart::Ptr(new MimeMessagePart(otp, p, true))); 0551 } 0552 } 0553 mChildParts[MultipartHtml] = MessagePart::Ptr(new MessagePart(mOtp, htmlContent, nullptr)); 0554 } 0555 } 0556 } 0557 0558 AlternativeMessagePart::~AlternativeMessagePart() 0559 { 0560 0561 } 0562 0563 QList<AlternativeMessagePart::HtmlMode> AlternativeMessagePart::availableModes() 0564 { 0565 return mChildParts.keys(); 0566 } 0567 0568 QString AlternativeMessagePart::text() const 0569 { 0570 if (mChildParts.contains(MultipartPlain)) { 0571 return mChildParts[MultipartPlain]->text(); 0572 } 0573 return QString(); 0574 } 0575 0576 bool AlternativeMessagePart::isHtml() const 0577 { 0578 return mChildParts.contains(MultipartHtml); 0579 } 0580 0581 QString AlternativeMessagePart::plaintextContent() const 0582 { 0583 return text(); 0584 } 0585 0586 QString AlternativeMessagePart::htmlContent() const 0587 { 0588 if (mChildParts.contains(MultipartHtml)) { 0589 return mChildParts[MultipartHtml]->text(); 0590 } else { 0591 return plaintextContent(); 0592 } 0593 } 0594 0595 QString AlternativeMessagePart::icalContent() const 0596 { 0597 if (mChildParts.contains(MultipartIcal)) { 0598 return mChildParts[MultipartIcal]->text(); 0599 } 0600 return {}; 0601 } 0602 0603 //-----CertMessageBlock---------------------- 0604 0605 CertMessagePart::CertMessagePart(ObjectTreeParser *otp, KMime::Content *node, const CryptoProtocol cryptoProto) 0606 : MessagePart(otp, QString(), node) 0607 , mProtocol(cryptoProto) 0608 { 0609 if (!mNode) { 0610 qCWarning(MIMETREEPARSER_LOG) << "not a valid node"; 0611 return; 0612 } 0613 } 0614 0615 CertMessagePart::~CertMessagePart() 0616 { 0617 0618 } 0619 0620 void CertMessagePart::import() 0621 { 0622 importKey(mProtocol, mNode->decodedContent()); 0623 } 0624 0625 QString CertMessagePart::text() const 0626 { 0627 return QString(); 0628 } 0629 0630 //-----SignedMessageBlock--------------------- 0631 SignedMessagePart::SignedMessagePart(ObjectTreeParser *otp, 0632 const CryptoProtocol cryptoProto, 0633 KMime::Content *node, KMime::Content *signedData, bool parseAfterDecryption) 0634 : MessagePart(otp, {}, node) 0635 , mParseAfterDecryption(parseAfterDecryption) 0636 , mProtocol(cryptoProto) 0637 , mSignedData(signedData) 0638 { 0639 mMetaData.isSigned = true; 0640 mMetaData.isGoodSignature = false; 0641 mMetaData.status = tr("Wrong Crypto Plug-In."); 0642 } 0643 0644 SignedMessagePart::~SignedMessagePart() 0645 { 0646 0647 } 0648 0649 void SignedMessagePart::setIsSigned(bool isSigned) 0650 { 0651 mMetaData.isSigned = isSigned; 0652 } 0653 0654 bool SignedMessagePart::isSigned() const 0655 { 0656 return mMetaData.isSigned; 0657 } 0658 0659 0660 static QString prettifyDN(const char *uid) 0661 { 0662 // We used to use QGpgME::DN::prettyDN here. But I'm not sure what we actually need it for. 0663 return QString::fromUtf8(uid); 0664 } 0665 0666 static void sigStatusToMetaData(PartMetaData &mMetaData, const Signature &signature) 0667 { 0668 mMetaData.isGoodSignature = !signature.status; 0669 if (!mMetaData.isGoodSignature) { 0670 qWarning() << "The signature is bad." << signature.status; 0671 // if (signature.status.errorCode() == GPG_ERR_NO_PUBKEY) { 0672 // qWarning() << "No public key to verify signature."; 0673 // } else { 0674 // qWarning() << "Is no good signature" << signature.status; 0675 // } 0676 } 0677 // save extended signature status flags 0678 mMetaData.keyMissing = signature.result == Crypto::Signature::KeyNotFound; 0679 mMetaData.keyExpired = signature.result == Crypto::Signature::Expired; 0680 //FIXME 0681 // mMetaData.keyRevoked = summary & GPGME_SIGSUM_KEY_REVOKED; 0682 // mMetaData.sigExpired = summary & GPGME_SIGSUM_SIG_EXPIRED; 0683 // mMetaData.crlMissing = summary & GPGME_SIGSUM_CRL_MISSING; 0684 // mMetaData.crlTooOld = summary & GPGME_SIGSUM_CRL_TOO_OLD; 0685 0686 Key key; 0687 if (mMetaData.isGoodSignature) { 0688 // Search for the key by its fingerprint so that we can check for trust etc. 0689 const auto keys = findKeys({signature.fingerprint}); 0690 if (keys.size() > 1) { 0691 // Should not happen 0692 qCDebug(MIMETREEPARSER_LOG) << "Oops: Found more then one Key for Fingerprint: " << signature.fingerprint; 0693 } 0694 if (keys.empty()) { 0695 // Should not happen at this point 0696 qCWarning(MIMETREEPARSER_LOG) << "Oops: Found no Key for Fingerprint: " << signature.fingerprint; 0697 } else { 0698 key = keys[0]; 0699 } 0700 } 0701 0702 mMetaData.keyId = key.keyId; 0703 if (mMetaData.keyId.isEmpty()) { 0704 mMetaData.keyId = signature.fingerprint; 0705 } 0706 mMetaData.keyIsTrusted = signature.isTrusted; 0707 if (!key.userIds.empty()) { 0708 mMetaData.signer = prettifyDN(key.userIds[0].id); 0709 } 0710 for (const auto &userId : key.userIds) { 0711 QString email = QString::fromUtf8(userId.email); 0712 // ### work around gpgme 0.3.QString text() const Q_DECL_OVERRIDE;x / cryptplug bug where the 0713 // ### email addresses are specified as angle-addr, not addr-spec: 0714 if (email.startsWith(QLatin1Char('<')) && email.endsWith(QLatin1Char('>'))) { 0715 email = email.mid(1, email.length() - 2); 0716 } 0717 if (!email.isEmpty()) { 0718 mMetaData.signerMailAddresses.append(email); 0719 } 0720 } 0721 0722 mMetaData.creationTime = signature.creationTime; 0723 if (mMetaData.signer.isEmpty()) { 0724 if (!key.userIds.empty()) { 0725 mMetaData.signer = prettifyDN(key.userIds[0].name); 0726 } 0727 if (!mMetaData.signerMailAddresses.empty()) { 0728 if (mMetaData.signer.isEmpty()) { 0729 mMetaData.signer = mMetaData.signerMailAddresses.front(); 0730 } else { 0731 mMetaData.signer += QLatin1String(" <") + mMetaData.signerMailAddresses.front() + QLatin1Char('>'); 0732 } 0733 } 0734 } 0735 } 0736 0737 void SignedMessagePart::startVerification() 0738 { 0739 if (!mSignedData) { 0740 return; 0741 } 0742 0743 mMetaData.isSigned = false; 0744 mMetaData.status = tr("Wrong Crypto Plug-In."); 0745 mMetaData.isEncrypted = false; 0746 mMetaData.isDecryptable = false; 0747 0748 const auto codec = mOtp->codecFor(mSignedData); 0749 0750 //If we have a mNode, this is a detached signature 0751 if (mNode) { 0752 const auto signature = mNode->decodedContent(); 0753 0754 //This is necessary in case the original data contained CRLF's. Otherwise the signature will not match the data (since KMIME normalizes to LF) 0755 const QByteArray signedData = KMime::LFtoCRLF(mSignedData->encodedContent()); 0756 0757 setVerificationResult(Crypto::verifyDetachedSignature(mProtocol, signature, signedData), signedData); 0758 setText(codec->toUnicode(KMime::CRLFtoLF(signedData))); 0759 } else { 0760 QByteArray outdata; 0761 setVerificationResult(Crypto::verifyOpaqueSignature(mProtocol, mSignedData->decodedContent(), outdata), outdata); 0762 setText(codec->toUnicode(KMime::CRLFtoLF(outdata))); 0763 } 0764 0765 if (!mMetaData.isSigned) { 0766 mMetaData.creationTime = QDateTime(); 0767 } 0768 } 0769 0770 void SignedMessagePart::setVerificationResult(const VerificationResult &result, const QByteArray &signedData) 0771 { 0772 const auto signatures = result.signatures; 0773 // FIXME 0774 // mMetaData.auditLogError = result.error; 0775 if (!signatures.empty()) { 0776 mMetaData.isSigned = true; 0777 sigStatusToMetaData(mMetaData, signatures.front()); 0778 if (!signedData.isEmpty() && mParseAfterDecryption) { 0779 parseInternal(signedData); 0780 } 0781 } 0782 } 0783 0784 QString SignedMessagePart::plaintextContent() const 0785 { 0786 if (!mNode) { 0787 return MessagePart::text(); 0788 } else { 0789 return QString(); 0790 } 0791 } 0792 0793 QString SignedMessagePart::htmlContent() const 0794 { 0795 if (!mNode) { 0796 return MessagePart::text(); 0797 } else { 0798 return QString(); 0799 } 0800 } 0801 0802 //-----CryptMessageBlock--------------------- 0803 EncryptedMessagePart::EncryptedMessagePart(ObjectTreeParser *otp, 0804 const QString &text, 0805 const CryptoProtocol cryptoProto, 0806 KMime::Content *node, KMime::Content *encryptedNode, bool parseAfterDecryption) 0807 : MessagePart(otp, text, node) 0808 , mParseAfterDecryption(parseAfterDecryption) 0809 , mProtocol(cryptoProto) 0810 , mEncryptedNode(encryptedNode) 0811 { 0812 mMetaData.isSigned = false; 0813 mMetaData.isGoodSignature = false; 0814 mMetaData.isEncrypted = false; 0815 mMetaData.isDecryptable = false; 0816 mMetaData.status = tr("Wrong Crypto Plug-In."); 0817 } 0818 0819 void EncryptedMessagePart::setIsEncrypted(bool encrypted) 0820 { 0821 mMetaData.isEncrypted = encrypted; 0822 } 0823 0824 bool EncryptedMessagePart::isEncrypted() const 0825 { 0826 return mMetaData.isEncrypted; 0827 } 0828 0829 bool EncryptedMessagePart::isDecryptable() const 0830 { 0831 return mMetaData.isDecryptable; 0832 } 0833 0834 bool EncryptedMessagePart::decrypt(KMime::Content &data) 0835 { 0836 mError = NoError; 0837 mMetaData.errorText.clear(); 0838 //FIXME 0839 // mMetaData.auditLogError = GpgME::Error(); 0840 mMetaData.auditLog.clear(); 0841 0842 const QByteArray ciphertext = data.decodedContent(); 0843 QByteArray plainText; 0844 DecryptionResult decryptResult; 0845 VerificationResult verifyResult; 0846 std::tie(decryptResult, verifyResult) = Crypto::decryptAndVerify(mProtocol, ciphertext, plainText); 0847 mMetaData.isSigned = verifyResult.signatures.size() > 0; 0848 0849 // Normalize CRLF's 0850 plainText = KMime::CRLFtoLF(plainText); 0851 const auto codec = mOtp->codecFor(&data); 0852 const auto decoded = codec->toUnicode(plainText); 0853 0854 if (verifyResult.signatures.size() > 0) { 0855 //We simply attach a signed message part to indicate that this content is also signed 0856 //We're forwarding mNode to not loose the encoding information 0857 auto subPart = SignedMessagePart::Ptr(new SignedMessagePart(mOtp, mProtocol, mNode, nullptr)); 0858 subPart->setText(decoded); 0859 subPart->setVerificationResult(verifyResult, plainText); 0860 appendSubPart(subPart); 0861 } 0862 0863 if (decryptResult.error && mMetaData.isSigned) { 0864 //Only a signed part 0865 mMetaData.isEncrypted = false; 0866 mDecryptedData = plainText; 0867 return true; 0868 } 0869 0870 if (mMetaData.isEncrypted) { 0871 mMetaData.keyId = [&] { 0872 foreach (const auto &recipient, decryptResult.recipients) { 0873 if (recipient.secretKeyAvailable) { 0874 return recipient.keyId; 0875 } 0876 } 0877 return QByteArray{}; 0878 }(); 0879 } 0880 0881 if (!decryptResult.error) { 0882 mDecryptedData = plainText; 0883 setText(decoded); 0884 } else { 0885 mMetaData.isEncrypted = decryptResult.result != Crypto::DecryptionResult::NotEncrypted; 0886 qWarning() << "Failed to decrypt : " << decryptResult.error; 0887 0888 if(decryptResult.result == Crypto::DecryptionResult::NoSecretKeyError) { 0889 mError = NoKeyError; 0890 mMetaData.errorText = tr("Could not decrypt the data: no key found for recipients."); 0891 } else if (decryptResult.result == Crypto::DecryptionResult::PassphraseError) { 0892 mError = PassphraseError; 0893 } else { 0894 mError = UnknownError; 0895 mMetaData.errorText = tr("Could not decrypt the data."); 0896 } 0897 setText(QString::fromUtf8(mDecryptedData.constData())); 0898 return false; 0899 } 0900 0901 return true; 0902 } 0903 0904 void EncryptedMessagePart::startDecryption(KMime::Content *data) 0905 { 0906 mMetaData.isEncrypted = true; 0907 mMetaData.isDecryptable = decrypt(*data); 0908 0909 if (mParseAfterDecryption && !mMetaData.isSigned) { 0910 parseInternal(mDecryptedData); 0911 } 0912 } 0913 0914 void EncryptedMessagePart::startDecryption() 0915 { 0916 if (mEncryptedNode) { 0917 startDecryption(mEncryptedNode); 0918 } else { 0919 startDecryption(mNode); 0920 } 0921 } 0922 0923 QString EncryptedMessagePart::plaintextContent() const 0924 { 0925 if (!mNode) { 0926 return MessagePart::text(); 0927 } else { 0928 return QString(); 0929 } 0930 } 0931 0932 QString EncryptedMessagePart::htmlContent() const 0933 { 0934 if (!mNode) { 0935 return MessagePart::text(); 0936 } else { 0937 return QString(); 0938 } 0939 } 0940 0941 QString EncryptedMessagePart::text() const 0942 { 0943 if (hasSubParts()) { 0944 auto _mp = (subParts()[0]).dynamicCast<SignedMessagePart>(); 0945 if (_mp) { 0946 return _mp->text(); 0947 } else { 0948 return MessagePart::text(); 0949 } 0950 } else { 0951 return MessagePart::text(); 0952 } 0953 } 0954 0955 EncapsulatedRfc822MessagePart::EncapsulatedRfc822MessagePart(ObjectTreeParser *otp, KMime::Content *node, const KMime::Message::Ptr &message) 0956 : MessagePart(otp, QString(), node) 0957 , mMessage(message) 0958 { 0959 mMetaData.isEncrypted = false; 0960 mMetaData.isSigned = false; 0961 mMetaData.isEncapsulatedRfc822Message = true; 0962 0963 if (!mMessage) { 0964 qCWarning(MIMETREEPARSER_LOG) << "Node is of type message/rfc822 but doesn't have a message!"; 0965 return; 0966 } 0967 0968 parseInternal(message.data()); 0969 } 0970 0971 QString EncapsulatedRfc822MessagePart::text() const 0972 { 0973 return renderInternalText(); 0974 } 0975 0976 QString EncapsulatedRfc822MessagePart::from() const 0977 { 0978 if (auto from = mMessage->from(false)) { 0979 return from->asUnicodeString(); 0980 } 0981 return {}; 0982 } 0983 0984 QDateTime EncapsulatedRfc822MessagePart::date() const 0985 { 0986 if (auto date = mMessage->date(false)) { 0987 return date->dateTime(); 0988 } 0989 return {}; 0990 } 0991 0992 HeadersPart::HeadersPart(ObjectTreeParser *otp, KMime::Content *node) 0993 : MessagePart(otp, QString(), node) 0994 { 0995 }