From 31bf3102fe8f8cdd3f1448f0f22f182d0c2820d2 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Tue, 23 May 2017 21:00:50 +0200 Subject: Moved MIME related stuff to a mime subdir --- .../src/domain/mimetreeparser/otp/messagepart.cpp | 1352 -------------------- 1 file changed, 1352 deletions(-) delete mode 100644 framework/src/domain/mimetreeparser/otp/messagepart.cpp (limited to 'framework/src/domain/mimetreeparser/otp/messagepart.cpp') diff --git a/framework/src/domain/mimetreeparser/otp/messagepart.cpp b/framework/src/domain/mimetreeparser/otp/messagepart.cpp deleted file mode 100644 index 3228a387..00000000 --- a/framework/src/domain/mimetreeparser/otp/messagepart.cpp +++ /dev/null @@ -1,1352 +0,0 @@ -/* - Copyright (c) 2015 Sandro Knauß - - This library is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published by - the Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This library is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. -*/ - -#include "messagepart.h" -#include "mimetreeparser_debug.h" -#include "attachmentstrategy.h" -#include "cryptohelper.h" -#include "objecttreeparser.h" -#include "htmlwriter.h" -#include "qgpgmejobexecutor.h" - -#include "cryptobodypartmemento.h" -#include "decryptverifybodypartmemento.h" -#include "verifydetachedbodypartmemento.h" -#include "verifyopaquebodypartmemento.h" - -#include "utils.h" - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include - -using namespace MimeTreeParser; - -//------MessagePart----------------------- -MessagePart::MessagePart(ObjectTreeParser *otp, - const QString &text) - : mText(text) - , mOtp(otp) - , mAttachmentNode(nullptr) - , mRoot(false) -{ -} - -MessagePart::~MessagePart() -{ -} - -PartMetaData *MessagePart::partMetaData() -{ - return &mMetaData; -} - -void MessagePart::setAttachmentFlag(KMime::Content *node) -{ - mAttachmentNode = node; -} - -bool MessagePart::isAttachment() const -{ - return mAttachmentNode; -} - -KMime::Content *MessagePart::attachmentNode() const -{ - return mAttachmentNode; -} - -void MessagePart::setIsRoot(bool root) -{ - mRoot = root; -} - -bool MessagePart::isRoot() const -{ - return mRoot; -} - -QString MessagePart::text() const -{ - return mText; -} - -void MessagePart::setText(const QString &text) -{ - mText = text; -} - -bool MessagePart::isHtml() const -{ - return false; -} - -bool MessagePart::isHidden() const -{ - return false; -} - -Interface::ObjectTreeSource *MessagePart::source() const -{ - Q_ASSERT(mOtp); - return mOtp->mSource; -} - -HtmlWriter *MessagePart::htmlWriter() const -{ - Q_ASSERT(mOtp); - return mOtp->htmlWriter(); -} - -void MessagePart::setHtmlWriter(HtmlWriter *htmlWriter) const -{ - mOtp->mHtmlWriter = htmlWriter; -} - -void MessagePart::parseInternal(KMime::Content *node, bool onlyOneMimePart) -{ - auto subMessagePart = mOtp->parseObjectTreeInternal(node, onlyOneMimePart); - mRoot = subMessagePart->isRoot(); - foreach (const auto &part, subMessagePart->subParts()) { - appendSubPart(part); - } -} - -QString MessagePart::renderInternalText() const -{ - QString text; - foreach (const auto &mp, subParts()) { - text += mp->text(); - } - return text; -} - -void MessagePart::copyContentFrom() const -{ - foreach (const auto &mp, subParts()) { - const auto m = mp.dynamicCast(); - if (m) { - m->copyContentFrom(); - } - } -} - -void MessagePart::fix() const -{ - foreach (const auto &mp, subParts()) { - const auto m = mp.dynamicCast(); - if (m) { - m->fix(); - } - } -} - -void MessagePart::appendSubPart(const Interface::MessagePart::Ptr &messagePart) -{ - messagePart->setParentPart(this); - mBlocks.append(messagePart); -} - -const QVector &MessagePart::subParts() const -{ - return mBlocks; -} - -bool MessagePart::hasSubParts() const -{ - return !mBlocks.isEmpty(); -} - -//-----MessagePartList---------------------- -MessagePartList::MessagePartList(ObjectTreeParser *otp) - : MessagePart(otp, QString()) -{ -} - -MessagePartList::~MessagePartList() -{ - -} - -QString MessagePartList::text() const -{ - return renderInternalText(); -} - -QString MessagePartList::plaintextContent() const -{ - return QString(); -} - -QString MessagePartList::htmlContent() const -{ - return QString(); -} - -//-----TextMessageBlock---------------------- - -TextMessagePart::TextMessagePart(ObjectTreeParser *otp, KMime::Content *node, bool drawFrame, bool showLink, bool decryptMessage) - : MessagePartList(otp) - , mNode(node) - , mDrawFrame(drawFrame) - , mShowLink(showLink) - , mDecryptMessage(decryptMessage) - , mIsHidden(false) -{ - if (!mNode) { - qCWarning(MIMETREEPARSER_LOG) << "not a valid node"; - return; - } - - mIsHidden = mOtp->nodeHelper()->isNodeDisplayedHidden(mNode); - - parseContent(); -} - -TextMessagePart::~TextMessagePart() -{ - -} - -bool TextMessagePart::decryptMessage() const -{ - return mDecryptMessage; -} - -void TextMessagePart::parseContent() -{ - const auto aCodec = mOtp->codecFor(mNode); - const QString &fromAddress = mOtp->nodeHelper()->fromAsString(mNode); - mSignatureState = KMMsgNotSigned; - mEncryptionState = KMMsgNotEncrypted; - const auto blocks = prepareMessageForDecryption(mNode->decodedContent()); - - const auto cryptProto = QGpgME::openpgp(); - - if (!blocks.isEmpty()) { - - /* The (overall) signature/encrypted status is broken - * if one unencrypted part is at the beginning or in the middle - * because mailmain adds an unencrypted part at the end this should not break the overall status - * - * That's why we first set the tmp status and if one crypted/signed block comes afterwards, than - * the status is set to unencryped - */ - bool fullySignedOrEncrypted = true; - bool fullySignedOrEncryptedTmp = true; - - for (const auto &block : blocks) { - - if (!fullySignedOrEncryptedTmp) { - fullySignedOrEncrypted = false; - } - - if (block.type() == NoPgpBlock && !block.text().trimmed().isEmpty()) { - fullySignedOrEncryptedTmp = false; - appendSubPart(MessagePart::Ptr(new MessagePart(mOtp, aCodec->toUnicode(block.text())))); - } else if (block.type() == PgpMessageBlock) { - EncryptedMessagePart::Ptr mp(new EncryptedMessagePart(mOtp, QString(), cryptProto, fromAddress, nullptr)); - mp->setDecryptMessage(decryptMessage()); - mp->setIsEncrypted(true); - appendSubPart(mp); - if (!decryptMessage()) { - continue; - } - mp->startDecryption(block.text(), aCodec); - if (mp->partMetaData()->inProgress) { - continue; - } - } else if (block.type() == ClearsignedBlock) { - SignedMessagePart::Ptr mp(new SignedMessagePart(mOtp, QString(), cryptProto, fromAddress, nullptr)); - appendSubPart(mp); - mp->startVerification(block.text(), aCodec); - } else { - continue; - } - - const auto mp = subParts().last().staticCast(); - const PartMetaData *messagePart(mp->partMetaData()); - - if (!messagePart->isEncrypted && !messagePart->isSigned && !block.text().trimmed().isEmpty()) { - mp->setText(aCodec->toUnicode(block.text())); - } - - if (messagePart->isEncrypted) { - mEncryptionState = KMMsgPartiallyEncrypted; - } - - if (messagePart->isSigned) { - mSignatureState = KMMsgPartiallySigned; - } - } - - //Do we have an fully Signed/Encrypted Message? - if (fullySignedOrEncrypted) { - if (mSignatureState == KMMsgPartiallySigned) { - mSignatureState = KMMsgFullySigned; - } - if (mEncryptionState == KMMsgPartiallyEncrypted) { - mEncryptionState = KMMsgFullyEncrypted; - } - } - } -} - -KMMsgEncryptionState TextMessagePart::encryptionState() const -{ - return mEncryptionState; -} - -KMMsgSignatureState TextMessagePart::signatureState() const -{ - return mSignatureState; -} - -bool TextMessagePart::isHidden() const -{ - return mIsHidden; -} - -bool TextMessagePart::showLink() const -{ - return mShowLink; -} - -bool TextMessagePart::showTextFrame() const -{ - return mDrawFrame; -} - -//-----AttachmentMessageBlock---------------------- - -AttachmentMessagePart::AttachmentMessagePart(ObjectTreeParser *otp, KMime::Content *node, bool drawFrame, bool showLink, bool decryptMessage) - : TextMessagePart(otp, node, drawFrame, showLink, decryptMessage) - , mIsImage(false) - , mNeverDisplayInline(false) -{ - -} - -AttachmentMessagePart::~AttachmentMessagePart() -{ - -} - -bool AttachmentMessagePart::neverDisplayInline() const -{ - return mNeverDisplayInline; -} - -void AttachmentMessagePart::setNeverDisplayInline(bool displayInline) -{ - mNeverDisplayInline = displayInline; -} - -bool AttachmentMessagePart::isImage() const -{ - return mIsImage; -} - -void AttachmentMessagePart::setIsImage(bool image) -{ - mIsImage = image; -} - -IconType AttachmentMessagePart::asIcon() const -{ - const AttachmentStrategy *const as = mOtp->attachmentStrategy(); - const bool defaultHidden(as && as->defaultDisplay(mNode) == AttachmentStrategy::None); - const bool showOnlyOneMimePart(mOtp->showOnlyOneMimePart()); - auto preferredMode = source()->preferredMode(); - bool isHtmlPreferred = (preferredMode == Util::Html) || (preferredMode == Util::MultipartHtml); - - QByteArray mediaType("text"); - QByteArray subType("plain"); - if (mNode->contentType(false) && !mNode->contentType()->mediaType().isEmpty() && - !mNode->contentType()->subType().isEmpty()) { - mediaType = mNode->contentType()->mediaType(); - subType = mNode->contentType()->subType(); - } - const bool isTextPart = (mediaType == QByteArrayLiteral("text")); - - bool defaultAsIcon = true; - if (!neverDisplayInline()) { - if (as) { - defaultAsIcon = as->defaultDisplay(mNode) == AttachmentStrategy::AsIcon; - } - } - if (isImage() && showOnlyOneMimePart && !neverDisplayInline()) { - defaultAsIcon = false; - } - - // neither image nor text -> show as icon - if (!isImage() && !isTextPart) { - defaultAsIcon = true; - } - - if (isTextPart) { - if (as && as->defaultDisplay(mNode) != AttachmentStrategy::Inline) { - return MimeTreeParser::IconExternal; - } - return MimeTreeParser::NoIcon; - } else { - if (isImage() && isHtmlPreferred && - mNode->parent() && mNode->parent()->contentType()->subType() == "related") { - return MimeTreeParser::IconInline; - } - - if (defaultHidden && !showOnlyOneMimePart && mNode->parent()) { - return MimeTreeParser::IconInline; - } - - if (defaultAsIcon) { - return MimeTreeParser::IconExternal; - } else if (isImage()) { - return MimeTreeParser::IconInline; - } else { - return MimeTreeParser::NoIcon; - } - } -} - -bool AttachmentMessagePart::isHidden() const -{ - const AttachmentStrategy *const as = mOtp->attachmentStrategy(); - const bool defaultHidden(as && as->defaultDisplay(mNode) == AttachmentStrategy::None); - const bool showOnlyOneMimePart(mOtp->showOnlyOneMimePart()); - auto preferredMode = source()->preferredMode(); - bool isHtmlPreferred = (preferredMode == Util::Html) || (preferredMode == Util::MultipartHtml); - - QByteArray mediaType("text"); - QByteArray subType("plain"); - if (mNode->contentType(false) && !mNode->contentType()->mediaType().isEmpty() && - !mNode->contentType()->subType().isEmpty()) { - mediaType = mNode->contentType()->mediaType(); - subType = mNode->contentType()->subType(); - } - const bool isTextPart = (mediaType == QByteArrayLiteral("text")); - - bool defaultAsIcon = true; - if (!neverDisplayInline()) { - if (as) { - defaultAsIcon = as->defaultDisplay(mNode) == AttachmentStrategy::AsIcon; - } - } - if (isImage() && showOnlyOneMimePart && !neverDisplayInline()) { - defaultAsIcon = false; - } - - // neither image nor text -> show as icon - if (!isImage() && !isTextPart) { - defaultAsIcon = true; - } - - bool hidden(false); - if (isTextPart) { - hidden = defaultHidden && !showOnlyOneMimePart; - } else { - if (isImage() && isHtmlPreferred && - mNode->parent() && mNode->parent()->contentType()->subType() == "related") { - hidden = true; - } else { - hidden = defaultHidden && !showOnlyOneMimePart && mNode->parent(); - hidden |= defaultAsIcon && (defaultHidden || showOnlyOneMimePart); - } - } - mOtp->nodeHelper()->setNodeDisplayedHidden(mNode, hidden); - return hidden; -} - -//-----HtmlMessageBlock---------------------- - -HtmlMessagePart::HtmlMessagePart(ObjectTreeParser *otp, KMime::Content *node, Interface::ObjectTreeSource *source) - : MessagePart(otp, QString()) - , mNode(node) - , mSource(source) -{ - if (!mNode) { - qCWarning(MIMETREEPARSER_LOG) << "not a valid node"; - return; - } - - const QByteArray partBody(mNode->decodedContent()); - mBodyHTML = mOtp->codecFor(mNode)->toUnicode(partBody); - mCharset = NodeHelper::charset(mNode); -} - -HtmlMessagePart::~HtmlMessagePart() -{ -} - -void HtmlMessagePart::fix() const -{ - mOtp->mHtmlContent += mBodyHTML; - mOtp->mHtmlContentCharset = mCharset; -} - -QString HtmlMessagePart::text() const -{ - return mBodyHTML; -} - -bool HtmlMessagePart::isHtml() const -{ - return true; -} - -//-----MimeMessageBlock---------------------- - -MimeMessagePart::MimeMessagePart(ObjectTreeParser *otp, KMime::Content *node, bool onlyOneMimePart) - : MessagePart(otp, QString()) - , mNode(node) - , mOnlyOneMimePart(onlyOneMimePart) -{ - if (!mNode) { - qCWarning(MIMETREEPARSER_LOG) << "not a valid node"; - return; - } - - parseInternal(mNode, mOnlyOneMimePart); -} - -MimeMessagePart::~MimeMessagePart() -{ - -} - -QString MimeMessagePart::text() const -{ - return renderInternalText(); -} - -QString MimeMessagePart::plaintextContent() const -{ - return QString(); -} - -QString MimeMessagePart::htmlContent() const -{ - return QString(); -} - -//-----AlternativeMessagePart---------------------- - -AlternativeMessagePart::AlternativeMessagePart(ObjectTreeParser *otp, KMime::Content *node, Util::HtmlMode preferredMode) - : MessagePart(otp, QString()) - , mNode(node) - , mPreferredMode(preferredMode) -{ - KMime::Content *dataIcal = findTypeInDirectChilds(mNode, "text/calendar"); - KMime::Content *dataHtml = findTypeInDirectChilds(mNode, "text/html"); - KMime::Content *dataText = findTypeInDirectChilds(mNode, "text/plain"); - - if (!dataHtml) { - // If we didn't find the HTML part as the first child of the multipart/alternative, it might - // be that this is a HTML message with images, and text/plain and multipart/related are the - // immediate children of this multipart/alternative node. - // In this case, the HTML node is a child of multipart/related. - dataHtml = findTypeInDirectChilds(mNode, "multipart/related"); - - // Still not found? Stupid apple mail actually puts the attachments inside of the - // multipart/alternative, which is wrong. Therefore we also have to look for multipart/mixed - // here. - // Do this only when prefering HTML mail, though, since otherwise the attachments are hidden - // when displaying plain text. - if (!dataHtml) { - dataHtml = findTypeInDirectChilds(mNode, "multipart/mixed"); - } - } - - if (dataIcal) { - mChildNodes[Util::MultipartIcal] = dataIcal; - } - - if (dataText) { - mChildNodes[Util::MultipartPlain] = dataText; - } - - if (dataHtml) { - mChildNodes[Util::MultipartHtml] = dataHtml; - } - - if (mChildNodes.isEmpty()) { - qCWarning(MIMETREEPARSER_LOG) << "no valid nodes"; - return; - } - - QMapIterator i(mChildNodes); - while (i.hasNext()) { - i.next(); - mChildParts[i.key()] = MimeMessagePart::Ptr(new MimeMessagePart(mOtp, i.value(), true)); - } -} - -AlternativeMessagePart::~AlternativeMessagePart() -{ - -} - -Util::HtmlMode AlternativeMessagePart::preferredMode() const -{ - return mPreferredMode; -} - -QList AlternativeMessagePart::availableModes() -{ - return mChildParts.keys(); -} - -QString AlternativeMessagePart::text() const -{ - if (mChildParts.contains(Util::MultipartPlain)) { - return mChildParts[Util::MultipartPlain]->text(); - } - return QString(); -} - -void AlternativeMessagePart::fix() const -{ - if (mChildParts.contains(Util::MultipartPlain)) { - mChildParts[Util::MultipartPlain]->fix(); - } - - const auto mode = preferredMode(); - if (mode != Util::MultipartPlain && mChildParts.contains(mode)) { - mChildParts[mode]->fix(); - } -} - -void AlternativeMessagePart::copyContentFrom() const -{ - if (mChildParts.contains(Util::MultipartPlain)) { - mChildParts[Util::MultipartPlain]->copyContentFrom(); - } - - const auto mode = preferredMode(); - if (mode != Util::MultipartPlain && mChildParts.contains(mode)) { - mChildParts[mode]->copyContentFrom(); - } -} - -bool AlternativeMessagePart::isHtml() const -{ - return mChildParts.contains(Util::MultipartHtml); -} - -QString AlternativeMessagePart::plaintextContent() const -{ - return text(); -} - -QString AlternativeMessagePart::htmlContent() const -{ - if (mChildParts.contains(Util::MultipartHtml)) { - return mChildParts[Util::MultipartHtml]->text(); - } else { - return plaintextContent(); - } -} - -//-----CertMessageBlock---------------------- - -CertMessagePart::CertMessagePart(ObjectTreeParser *otp, KMime::Content *node, const QGpgME::Protocol *cryptoProto, bool autoImport) - : MessagePart(otp, QString()) - , mNode(node) - , mAutoImport(autoImport) - , mCryptoProto(cryptoProto) -{ - if (!mNode) { - qCWarning(MIMETREEPARSER_LOG) << "not a valid node"; - return; - } - - if (!mAutoImport) { - return; - } - - const QByteArray certData = node->decodedContent(); - - QGpgME::ImportJob *import = mCryptoProto->importJob(); - QGpgMEJobExecutor executor; - mImportResult = executor.exec(import, certData); -} - -CertMessagePart::~CertMessagePart() -{ - -} - -QString CertMessagePart::text() const -{ - return QString(); -} - -//-----SignedMessageBlock--------------------- -SignedMessagePart::SignedMessagePart(ObjectTreeParser *otp, - const QString &text, - const QGpgME::Protocol *cryptoProto, - const QString &fromAddress, - KMime::Content *node) - : MessagePart(otp, text) - , mCryptoProto(cryptoProto) - , mFromAddress(fromAddress) - , mNode(node) -{ - mMetaData.technicalProblem = (mCryptoProto == nullptr); - mMetaData.isSigned = true; - mMetaData.isGoodSignature = false; - mMetaData.keyTrust = GpgME::Signature::Unknown; - mMetaData.status = i18n("Wrong Crypto Plug-In."); - mMetaData.status_code = GPGME_SIG_STAT_NONE; -} - -SignedMessagePart::~SignedMessagePart() -{ - -} - -void SignedMessagePart::setIsSigned(bool isSigned) -{ - mMetaData.isSigned = isSigned; -} - -bool SignedMessagePart::isSigned() const -{ - return mMetaData.isSigned; -} - -bool SignedMessagePart::okVerify(const QByteArray &data, const QByteArray &signature, KMime::Content *textNode) -{ - NodeHelper *nodeHelper = mOtp->nodeHelper(); - Interface::ObjectTreeSource *_source = source(); - - mMetaData.isSigned = false; - mMetaData.technicalProblem = (mCryptoProto == nullptr); - mMetaData.keyTrust = GpgME::Signature::Unknown; - mMetaData.status = i18n("Wrong Crypto Plug-In."); - mMetaData.status_code = GPGME_SIG_STAT_NONE; - - const QByteArray mementoName = "verification"; - - CryptoBodyPartMemento *m = dynamic_cast(nodeHelper->bodyPartMemento(mNode, mementoName)); - Q_ASSERT(!m || mCryptoProto); //No CryptoPlugin and having a bodyPartMemento -> there is something completely wrong - - if (!m && mCryptoProto) { - if (!signature.isEmpty()) { - QGpgME::VerifyDetachedJob *job = mCryptoProto->verifyDetachedJob(); - if (job) { - m = new VerifyDetachedBodyPartMemento(job, mCryptoProto->keyListJob(), signature, data); - } - } else { - QGpgME::VerifyOpaqueJob *job = mCryptoProto->verifyOpaqueJob(); - if (job) { - m = new VerifyOpaqueBodyPartMemento(job, mCryptoProto->keyListJob(), data); - } - } - if (m) { - if (mOtp->allowAsync()) { - QObject::connect(m, &CryptoBodyPartMemento::update, - nodeHelper, &NodeHelper::update); - QObject::connect(m, SIGNAL(update(MimeTreeParser::UpdateMode)), - _source->sourceObject(), SLOT(update(MimeTreeParser::UpdateMode))); - - if (m->start()) { - mMetaData.inProgress = true; - mOtp->mHasPendingAsyncJobs = true; - } - } else { - m->exec(); - } - nodeHelper->setBodyPartMemento(mNode, mementoName, m); - } - } else if (m->isRunning()) { - mMetaData.inProgress = true; - mOtp->mHasPendingAsyncJobs = true; - } else { - mMetaData.inProgress = false; - mOtp->mHasPendingAsyncJobs = false; - } - - if (m && !mMetaData.inProgress) { - if (!signature.isEmpty()) { - mVerifiedText = data; - } - setVerificationResult(m, textNode); - } - - if (!m && !mMetaData.inProgress) { - QString errorMsg; - QString cryptPlugLibName; - QString cryptPlugDisplayName; - if (mCryptoProto) { - cryptPlugLibName = mCryptoProto->name(); - cryptPlugDisplayName = mCryptoProto->displayName(); - } - - if (!mCryptoProto) { - if (cryptPlugDisplayName.isEmpty()) { - errorMsg = i18n("No appropriate crypto plug-in was found."); - } else { - errorMsg = i18nc("%1 is either 'OpenPGP' or 'S/MIME'", - "No %1 plug-in was found.", - cryptPlugDisplayName); - } - } else { - errorMsg = i18n("Crypto plug-in \"%1\" cannot verify signatures.", - cryptPlugLibName); - } - mMetaData.errorText = i18n("The message is signed, but the " - "validity of the signature cannot be " - "verified.
" - "Reason: %1", - errorMsg); - } - - return mMetaData.isSigned; -} - -static int signatureToStatus(const GpgME::Signature &sig) -{ - switch (sig.status().code()) { - case GPG_ERR_NO_ERROR: - return GPGME_SIG_STAT_GOOD; - case GPG_ERR_BAD_SIGNATURE: - return GPGME_SIG_STAT_BAD; - case GPG_ERR_NO_PUBKEY: - return GPGME_SIG_STAT_NOKEY; - case GPG_ERR_NO_DATA: - return GPGME_SIG_STAT_NOSIG; - case GPG_ERR_SIG_EXPIRED: - return GPGME_SIG_STAT_GOOD_EXP; - case GPG_ERR_KEY_EXPIRED: - return GPGME_SIG_STAT_GOOD_EXPKEY; - default: - return GPGME_SIG_STAT_ERROR; - } -} - -QString prettifyDN(const char *uid) -{ - return QGpgME::DN(uid).prettyDN(); -} - -void SignedMessagePart::sigStatusToMetaData() -{ - GpgME::Key key; - if (mMetaData.isSigned) { - GpgME::Signature signature = mSignatures.front(); - mMetaData.status_code = signatureToStatus(signature); - mMetaData.isGoodSignature = mMetaData.status_code & GPGME_SIG_STAT_GOOD; - // save extended signature status flags - mMetaData.sigSummary = signature.summary(); - - if (mMetaData.isGoodSignature && !key.keyID()) { - // Search for the key by its fingerprint so that we can check for - // trust etc. - QGpgME::KeyListJob *job = mCryptoProto->keyListJob(false); // local, no sigs - if (!job) { - qCDebug(MIMETREEPARSER_LOG) << "The Crypto backend does not support listing keys. "; - } else { - std::vector found_keys; - // As we are local it is ok to make this synchronous - GpgME::KeyListResult res = job->exec(QStringList(QLatin1String(signature.fingerprint())), false, found_keys); - if (res.error()) { - qCDebug(MIMETREEPARSER_LOG) << "Error while searching key for Fingerprint: " << signature.fingerprint(); - } - if (found_keys.size() > 1) { - // Should not Happen - qCDebug(MIMETREEPARSER_LOG) << "Oops: Found more then one Key for Fingerprint: " << signature.fingerprint(); - } - if (found_keys.size() != 1) { - // Should not Happen at this point - qCDebug(MIMETREEPARSER_LOG) << "Oops: Found no Key for Fingerprint: " << signature.fingerprint(); - } else { - key = found_keys[0]; - } - delete job; - } - } - - if (key.keyID()) { - mMetaData.keyId = key.keyID(); - } - if (mMetaData.keyId.isEmpty()) { - mMetaData.keyId = signature.fingerprint(); - } - mMetaData.keyTrust = signature.validity(); - if (key.numUserIDs() > 0 && key.userID(0).id()) { - mMetaData.signer = prettifyDN(key.userID(0).id()); - } - for (uint iMail = 0; iMail < key.numUserIDs(); ++iMail) { - // The following if /should/ always result in TRUE but we - // won't trust implicitely the plugin that gave us these data. - if (key.userID(iMail).email()) { - QString email = QString::fromUtf8(key.userID(iMail).email()); - // ### work around gpgme 0.3.QString text() const Q_DECL_OVERRIDE;x / cryptplug bug where the - // ### email addresses are specified as angle-addr, not addr-spec: - if (email.startsWith(QLatin1Char('<')) && email.endsWith(QLatin1Char('>'))) { - email = email.mid(1, email.length() - 2); - } - if (!email.isEmpty()) { - mMetaData.signerMailAddresses.append(email); - } - } - } - - if (signature.creationTime()) { - mMetaData.creationTime.setTime_t(signature.creationTime()); - } else { - mMetaData.creationTime = QDateTime(); - } - if (mMetaData.signer.isEmpty()) { - if (key.numUserIDs() > 0 && key.userID(0).name()) { - mMetaData.signer = prettifyDN(key.userID(0).name()); - } - if (!mMetaData.signerMailAddresses.empty()) { - if (mMetaData.signer.isEmpty()) { - mMetaData.signer = mMetaData.signerMailAddresses.front(); - } else { - mMetaData.signer += QLatin1String(" <") + mMetaData.signerMailAddresses.front() + QLatin1Char('>'); - } - } - } - } -} - -void SignedMessagePart::startVerification(const QByteArray &text, const QTextCodec *aCodec) -{ - startVerificationDetached(text, nullptr, QByteArray()); - - if (!mNode && mMetaData.isSigned) { - setText(aCodec->toUnicode(mVerifiedText)); - } -} - -void SignedMessagePart::startVerificationDetached(const QByteArray &text, KMime::Content *textNode, const QByteArray &signature) -{ - mMetaData.isEncrypted = false; - mMetaData.isDecryptable = false; - - if (textNode) { - parseInternal(textNode, false); - } - - okVerify(text, signature, textNode); - - if (!mMetaData.isSigned) { - mMetaData.creationTime = QDateTime(); - } -} - -void SignedMessagePart::setVerificationResult(const CryptoBodyPartMemento *m, KMime::Content *textNode) -{ - { - const auto vm = dynamic_cast(m); - if (vm) { - mSignatures = vm->verifyResult().signatures(); - } - } - { - const auto vm = dynamic_cast(m); - if (vm) { - mVerifiedText = vm->plainText(); - mSignatures = vm->verifyResult().signatures(); - } - } - { - const auto vm = dynamic_cast(m); - if (vm) { - mVerifiedText = vm->plainText(); - mSignatures = vm->verifyResult().signatures(); - } - } - mMetaData.auditLogError = m->auditLogError(); - mMetaData.auditLog = m->auditLogAsHtml(); - mMetaData.isSigned = !mSignatures.empty(); - - if (mMetaData.isSigned) { - sigStatusToMetaData(); - if (mNode) { - mOtp->nodeHelper()->setSignatureState(mNode, KMMsgFullySigned); - if (!textNode) { - mOtp->mNodeHelper->setPartMetaData(mNode, mMetaData); - - if (!mVerifiedText.isEmpty()) { - auto tempNode = new KMime::Content(); - tempNode->setContent(KMime::CRLFtoLF(mVerifiedText.constData())); - tempNode->parse(); - - if (!tempNode->head().isEmpty()) { - tempNode->contentDescription()->from7BitString("signed data"); - } - mOtp->mNodeHelper->attachExtraContent(mNode, tempNode); - - parseInternal(tempNode, false); - } - } - } - } -} - -QString SignedMessagePart::plaintextContent() const -{ - if (!mNode) { - return MessagePart::text(); - } else { - return QString(); - } -} - -QString SignedMessagePart::htmlContent() const -{ - if (!mNode) { - return MessagePart::text(); - } else { - return QString(); - } -} - -//-----CryptMessageBlock--------------------- -EncryptedMessagePart::EncryptedMessagePart(ObjectTreeParser *otp, - const QString &text, - const QGpgME::Protocol *cryptoProto, - const QString &fromAddress, - KMime::Content *node) - : MessagePart(otp, text) - , mPassphraseError(false) - , mNoSecKey(false) - , mCryptoProto(cryptoProto) - , mFromAddress(fromAddress) - , mNode(node) - , mDecryptMessage(false) -{ - mMetaData.technicalProblem = (mCryptoProto == nullptr); - mMetaData.isSigned = false; - mMetaData.isGoodSignature = false; - mMetaData.isEncrypted = false; - mMetaData.isDecryptable = false; - mMetaData.keyTrust = GpgME::Signature::Unknown; - mMetaData.status = i18n("Wrong Crypto Plug-In."); - mMetaData.status_code = GPGME_SIG_STAT_NONE; -} - -EncryptedMessagePart::~EncryptedMessagePart() -{ - -} - -void EncryptedMessagePart::setDecryptMessage(bool decrypt) -{ - mDecryptMessage = decrypt; -} - -bool EncryptedMessagePart::decryptMessage() const -{ - return mDecryptMessage; -} - -void EncryptedMessagePart::setIsEncrypted(bool encrypted) -{ - mMetaData.isEncrypted = encrypted; -} - -bool EncryptedMessagePart::isEncrypted() const -{ - return mMetaData.isEncrypted; -} - -bool EncryptedMessagePart::isDecryptable() const -{ - return mMetaData.isDecryptable; -} - -bool EncryptedMessagePart::passphraseError() const -{ - return mPassphraseError; -} - -void EncryptedMessagePart::startDecryption(const QByteArray &text, const QTextCodec *aCodec) -{ - KMime::Content *content = new KMime::Content; - content->setBody(text); - content->parse(); - - startDecryption(content); - - if (!mMetaData.inProgress && mMetaData.isDecryptable) { - if (hasSubParts()) { - auto _mp = (subParts()[0]).dynamicCast(); - if (_mp) { - _mp->setText(aCodec->toUnicode(mDecryptedData)); - } else { - setText(aCodec->toUnicode(mDecryptedData)); - } - } else { - setText(aCodec->toUnicode(mDecryptedData)); - } - } -} - -bool EncryptedMessagePart::okDecryptMIME(KMime::Content &data) -{ - mPassphraseError = false; - mMetaData.inProgress = false; - mMetaData.errorText.clear(); - mMetaData.auditLogError = GpgME::Error(); - mMetaData.auditLog.clear(); - bool bDecryptionOk = false; - bool cannotDecrypt = false; - Interface::ObjectTreeSource *_source = source(); - NodeHelper *nodeHelper = mOtp->nodeHelper(); - - Q_ASSERT(decryptMessage()); - - // Check whether the memento contains a result from last time: - const DecryptVerifyBodyPartMemento *m - = dynamic_cast(nodeHelper->bodyPartMemento(&data, "decryptverify")); - - Q_ASSERT(!m || mCryptoProto); //No CryptoPlugin and having a bodyPartMemento -> there is something completely wrong - - if (!m && mCryptoProto) { - QGpgME::DecryptVerifyJob *job = mCryptoProto->decryptVerifyJob(); - if (!job) { - cannotDecrypt = true; - } else { - const QByteArray ciphertext = data.decodedContent(); - DecryptVerifyBodyPartMemento *newM - = new DecryptVerifyBodyPartMemento(job, ciphertext); - if (mOtp->allowAsync()) { - QObject::connect(newM, &CryptoBodyPartMemento::update, - nodeHelper, &NodeHelper::update); - QObject::connect(newM, SIGNAL(update(MimeTreeParser::UpdateMode)), _source->sourceObject(), - SLOT(update(MimeTreeParser::UpdateMode))); - if (newM->start()) { - mMetaData.inProgress = true; - mOtp->mHasPendingAsyncJobs = true; - } else { - m = newM; - } - } else { - newM->exec(); - m = newM; - } - nodeHelper->setBodyPartMemento(&data, "decryptverify", newM); - } - } else if (m->isRunning()) { - mMetaData.inProgress = true; - mOtp->mHasPendingAsyncJobs = true; - m = nullptr; - } - - if (m) { - const QByteArray &plainText = m->plainText(); - const GpgME::DecryptionResult &decryptResult = m->decryptResult(); - const GpgME::VerificationResult &verifyResult = m->verifyResult(); - mMetaData.isSigned = verifyResult.signatures().size() > 0; - - if (verifyResult.signatures().size() > 0) { - auto subPart = SignedMessagePart::Ptr(new SignedMessagePart(mOtp, MessagePart::text(), mCryptoProto, mFromAddress, mNode)); - subPart->setVerificationResult(m, nullptr); - appendSubPart(subPart); - } - - mDecryptRecipients = decryptResult.recipients(); - bDecryptionOk = !decryptResult.error(); -// std::stringstream ss; -// ss << decryptResult << '\n' << verifyResult; -// qCDebug(MIMETREEPARSER_LOG) << ss.str().c_str(); - - if (!bDecryptionOk && mMetaData.isSigned) { - //Only a signed part - mMetaData.isEncrypted = false; - bDecryptionOk = true; - mDecryptedData = plainText; - } else { - mPassphraseError = decryptResult.error().isCanceled() || decryptResult.error().code() == GPG_ERR_NO_SECKEY; - mMetaData.isEncrypted = decryptResult.error().code() != GPG_ERR_NO_DATA; - mMetaData.errorText = QString::fromLocal8Bit(decryptResult.error().asString()); - if (mMetaData.isEncrypted && decryptResult.numRecipients() > 0) { - mMetaData.keyId = decryptResult.recipient(0).keyID(); - } - - if (bDecryptionOk) { - mDecryptedData = plainText; - } else { - mNoSecKey = true; - foreach (const GpgME::DecryptionResult::Recipient &recipient, decryptResult.recipients()) { - mNoSecKey &= (recipient.status().code() == GPG_ERR_NO_SECKEY); - } - if (!mPassphraseError && !mNoSecKey) { // GpgME do not detect passphrase error correctly - mPassphraseError = true; - } - } - } - } - - if (!bDecryptionOk) { - QString cryptPlugLibName; - if (mCryptoProto) { - cryptPlugLibName = mCryptoProto->name(); - } - - if (!mCryptoProto) { - mMetaData.errorText = i18n("No appropriate crypto plug-in was found."); - } else if (cannotDecrypt) { - mMetaData.errorText = i18n("Crypto plug-in \"%1\" cannot decrypt messages.", - cryptPlugLibName); - } else if (!passphraseError()) { - mMetaData.errorText = i18n("Crypto plug-in \"%1\" could not decrypt the data.", cryptPlugLibName) - + QLatin1String("
") - + i18n("Error: %1", mMetaData.errorText); - } - } - return bDecryptionOk; -} - -void EncryptedMessagePart::startDecryption(KMime::Content *data) -{ - if (!mNode && !data) { - return; - } - - if (!data) { - data = mNode; - } - - mMetaData.isEncrypted = true; - - bool bOkDecrypt = okDecryptMIME(*data); - - if (mMetaData.inProgress) { - return; - } - mMetaData.isDecryptable = bOkDecrypt; - - if (!mMetaData.isDecryptable) { - setText(QString::fromUtf8(mDecryptedData.constData())); - } - - if (mMetaData.isEncrypted && !decryptMessage()) { - mMetaData.isDecryptable = true; - } - - if (mNode && !mMetaData.isSigned) { - mOtp->mNodeHelper->setPartMetaData(mNode, mMetaData); - - if (decryptMessage()) { - auto tempNode = new KMime::Content(); - tempNode->setContent(KMime::CRLFtoLF(mDecryptedData.constData())); - tempNode->parse(); - - if (!tempNode->head().isEmpty()) { - tempNode->contentDescription()->from7BitString("encrypted data"); - } - mOtp->mNodeHelper->attachExtraContent(mNode, tempNode); - - parseInternal(tempNode, false); - } - } -} - -QString EncryptedMessagePart::plaintextContent() const -{ - if (!mNode) { - return MessagePart::text(); - } else { - return QString(); - } -} - -QString EncryptedMessagePart::htmlContent() const -{ - if (!mNode) { - return MessagePart::text(); - } else { - return QString(); - } -} - -QString EncryptedMessagePart::text() const -{ - if (hasSubParts()) { - auto _mp = (subParts()[0]).dynamicCast(); - if (_mp) { - return _mp->text(); - } else { - return MessagePart::text(); - } - } else { - return MessagePart::text(); - } -} - -EncapsulatedRfc822MessagePart::EncapsulatedRfc822MessagePart(ObjectTreeParser *otp, KMime::Content *node, const KMime::Message::Ptr &message) - : MessagePart(otp, QString()) - , mMessage(message) - , mNode(node) -{ - mMetaData.isEncrypted = false; - mMetaData.isSigned = false; - mMetaData.isEncapsulatedRfc822Message = true; - - mOtp->nodeHelper()->setNodeDisplayedEmbedded(mNode, true); - mOtp->nodeHelper()->setPartMetaData(mNode, mMetaData); - - if (!mMessage) { - qCWarning(MIMETREEPARSER_LOG) << "Node is of type message/rfc822 but doesn't have a message!"; - return; - } - - // The link to "Encapsulated message" is clickable, therefore the temp file needs to exists, - // since the user can click the link and expect to have normal attachment operations there. - mOtp->nodeHelper()->writeNodeToTempFile(message.data()); - - parseInternal(message.data(), false); -} - -EncapsulatedRfc822MessagePart::~EncapsulatedRfc822MessagePart() -{ - -} - -QString EncapsulatedRfc822MessagePart::text() const -{ - return renderInternalText(); -} - -void EncapsulatedRfc822MessagePart::copyContentFrom() const -{ -} - -void EncapsulatedRfc822MessagePart::fix() const -{ -} -- cgit v1.2.3