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 }