diff --git a/mimetreeparser/autotests/data/headeronly/openpgp-encrypted-no-text-attachment-non-encrypted.mbox.html b/mimetreeparser/autotests/data/headeronly/openpgp-encrypted-no-text-attachment-non-encrypted.mbox.html
new file mode 100644
--- /dev/null
+++ b/mimetreeparser/autotests/data/headeronly/openpgp-encrypted-no-text-attachment-non-encrypted.mbox.html
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/mimetreeparser/autotests/data/hidden/openpgp-encrypted-no-text-attachment-non-encrypted.mbox.html b/mimetreeparser/autotests/data/hidden/openpgp-encrypted-no-text-attachment-non-encrypted.mbox.html
new file mode 100644
--- /dev/null
+++ b/mimetreeparser/autotests/data/hidden/openpgp-encrypted-no-text-attachment-non-encrypted.mbox.html
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/mimetreeparser/autotests/data/inlined/openpgp-encrypted-no-text-attachment-non-encrypted.mbox.html b/mimetreeparser/autotests/data/inlined/openpgp-encrypted-no-text-attachment-non-encrypted.mbox.html
new file mode 100644
--- /dev/null
+++ b/mimetreeparser/autotests/data/inlined/openpgp-encrypted-no-text-attachment-non-encrypted.mbox.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
nothing is encrypted here.
+
+
+
+
+
+
diff --git a/mimetreeparser/autotests/data/openpgp-encrypted-no-text-attachment-non-encrypted.mbox b/mimetreeparser/autotests/data/openpgp-encrypted-no-text-attachment-non-encrypted.mbox
new file mode 100644
--- /dev/null
+++ b/mimetreeparser/autotests/data/openpgp-encrypted-no-text-attachment-non-encrypted.mbox
@@ -0,0 +1,26 @@
+From unknown@example.org Tue Oct 03 10:05:19 2017
+Return-Path:
+To: konqi@example.org
+Subject: only an encrypted attachment
+X-PHP-Originating-Script: 1008:rcube.php
+MIME-Version: 1.0
+Content-Type: multipart/mixed;
+ boundary="=_XXXXXXXXXXXXXX"
+Date: Tue, 03 Oct 2017 12:13:14 +0000
+From: unknown@example.org
+Message-ID:
+X-Sender: unknown@example.org
+User-Agent: Roundcube Webmail/1.1.9
+
+
+--=_XXXXXXXXXXXXXX
+Content-Transfer-Encoding: 7bit
+Content-Type: text/PGP;
+ name=encrypted.txt.pgp
+Content-Disposition: attachment;
+ filename=encrypted.txt.pgp;
+ size=1402
+
+nothing is encrypted here.
+--=_XXXXXXXXXXXXXX--
+
diff --git a/mimetreeparser/autotests/data/openpgp-encrypted-no-text-attachment-non-encrypted.mbox.html b/mimetreeparser/autotests/data/openpgp-encrypted-no-text-attachment-non-encrypted.mbox.html
new file mode 100644
--- /dev/null
+++ b/mimetreeparser/autotests/data/openpgp-encrypted-no-text-attachment-non-encrypted.mbox.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
diff --git a/mimetreeparser/autotests/data/openpgp-encrypted-no-text-attachment-non-encrypted.mbox.tree b/mimetreeparser/autotests/data/openpgp-encrypted-no-text-attachment-non-encrypted.mbox.tree
new file mode 100644
--- /dev/null
+++ b/mimetreeparser/autotests/data/openpgp-encrypted-no-text-attachment-non-encrypted.mbox.tree
@@ -0,0 +1,4 @@
+ * MimeTreeParser::MessagePartList
+ * MimeTreeParser::MimeMessagePart
+ * MimeTreeParser::AttachmentMessagePart
+ * MimeTreeParser::MessagePart
diff --git a/mimetreeparser/autotests/data/openpgp-encrypted-no-text-attachment.mbox b/mimetreeparser/autotests/data/openpgp-encrypted-no-text-attachment.mbox
new file mode 100644
--- /dev/null
+++ b/mimetreeparser/autotests/data/openpgp-encrypted-no-text-attachment.mbox
@@ -0,0 +1,32 @@
+From unknown@example.org Tue Oct 03 10:05:19 2017
+Return-Path:
+To: konqi@example.org
+Subject: only an encrypted attachment
+X-PHP-Originating-Script: 1008:rcube.php
+MIME-Version: 1.0
+Content-Type: multipart/mixed;
+ boundary="=_XXXXXXXXXXXXXX"
+Date: Tue, 03 Oct 2017 12:13:14 +0000
+From: unknown@example.org
+Message-ID:
+X-Sender: unknown@example.org
+User-Agent: Roundcube Webmail/1.1.9
+
+
+--=_XXXXXXXXXXXXXX
+Content-Transfer-Encoding: base64
+Content-Type: text/PGP;
+ name=Brotzeiten.txt.pgp
+Content-Disposition: attachment;
+ filename=encrypted.txt.pgp;
+ size=1402
+
+hQEMAwzOQ1qnzNo7AQf/Z3qYebORMk5Z4R+Pmb6gBLA20G3yLRFyd0z+ygcEp+rc1jYE1ZqK1pFz
+Z6WLgPdMcyrKBLrDeDfsQRbKvimR7NaXLSuNkRHFtgqCmaFDyIUMcf9DobAoKvGvmBJhgMW7WPCA
+RUDaiJyqBp29nCQuOIqAiT5fm5LyyUmhRxUb9/CnulcxzW85EiITm0wMos30j1dU++3KDp5R6gcc
+9uUVbdCWdiF4j3ilE8flCWg9tARTRGinu4ENc9eIjcn1hCotFS+4ccWYIwf6ZkVDS4wNfU7dDg+9
+ZwNb+RkXuYXT/tFdir+ewV0Njaj0ZWTUrqZSk2ArmdGo9ou7xl/2mrK6YNJIAUKgVsQlWZ1Kx4PI
+0k0+TsJBgRzVNpIBHpmu0MI4CE03XHUslFhzdrjOG2Ts26U3EJw+jjssu0W4MVzYc20u3BgRnzHn
+/SFA
+--=_XXXXXXXXXXXXXX--
+
diff --git a/mimetreeparser/autotests/data/openpgp-encrypted-no-text-attachment.mbox.html b/mimetreeparser/autotests/data/openpgp-encrypted-no-text-attachment.mbox.html
new file mode 100644
--- /dev/null
+++ b/mimetreeparser/autotests/data/openpgp-encrypted-no-text-attachment.mbox.html
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The message is encrypted for the following keys: Hide Details
+ |
+
+
+
+
+ |
+
+
+ End of encrypted message |
+
+
+
+
+
+
+
diff --git a/mimetreeparser/autotests/data/openpgp-encrypted-no-text-attachment.mbox.tree b/mimetreeparser/autotests/data/openpgp-encrypted-no-text-attachment.mbox.tree
new file mode 100644
--- /dev/null
+++ b/mimetreeparser/autotests/data/openpgp-encrypted-no-text-attachment.mbox.tree
@@ -0,0 +1,5 @@
+ * MimeTreeParser::MessagePartList
+ * MimeTreeParser::MimeMessagePart
+ * MimeTreeParser::EncryptedMessagePart
+ * MimeTreeParser::TextMessagePart
+ * MimeTreeParser::MessagePart
diff --git a/mimetreeparser/src/CMakeLists.txt b/mimetreeparser/src/CMakeLists.txt
--- a/mimetreeparser/src/CMakeLists.txt
+++ b/mimetreeparser/src/CMakeLists.txt
@@ -11,6 +11,7 @@
set(libmimetreeparser_main_SRCS
bodyformatter/applicationpgpencrypted.cpp
bodyformatter/applicationpkcs7mime.cpp
+ bodyformatter/encrypted.cpp
bodyformatter/mailman.cpp
bodyformatter/multipartalternative.cpp
bodyformatter/multipartencrypted.cpp
diff --git a/mimetreeparser/src/bodyformatter/encrypted.h b/mimetreeparser/src/bodyformatter/encrypted.h
new file mode 100644
--- /dev/null
+++ b/mimetreeparser/src/bodyformatter/encrypted.h
@@ -0,0 +1,36 @@
+/*
+ Copyright (c) 2017 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.
+*/
+
+#ifndef __MIMETREEPARSER_BODYFORAMATTER_ENCRYPTED_H__
+#define __MIMETREEPARSER_BODYFORAMATTER_ENCRYPTED_H__
+
+#include "interfaces/bodypartformatter.h"
+#include "interfaces/bodypart.h"
+
+namespace MimeTreeParser {
+class EncryptedBodyPartFormatter : public Interface::BodyPartFormatter
+{
+ static const EncryptedBodyPartFormatter *self;
+public:
+ MessagePartPtr process(Interface::BodyPart &part) const override;
+ static const Interface::BodyPartFormatter *create();
+};
+}
+
+#endif
diff --git a/mimetreeparser/src/bodyformatter/encrypted.cpp b/mimetreeparser/src/bodyformatter/encrypted.cpp
new file mode 100644
--- /dev/null
+++ b/mimetreeparser/src/bodyformatter/encrypted.cpp
@@ -0,0 +1,105 @@
+/*
+ Copyright (c) 2017 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 "encrypted.h"
+
+#include "utils.h"
+
+#include "objecttreeparser.h"
+#include "messagepart.h"
+
+#include
+
+#include
+
+#include
+
+#include "mimetreeparser_debug.h"
+
+using namespace MimeTreeParser;
+
+const EncryptedBodyPartFormatter *EncryptedBodyPartFormatter::self;
+
+const Interface::BodyPartFormatter *EncryptedBodyPartFormatter::create()
+{
+ if (!self) {
+ self = new EncryptedBodyPartFormatter();
+ }
+ return self;
+}
+
+MessagePart::Ptr EncryptedBodyPartFormatter::process(Interface::BodyPart &part) const
+{
+ KMime::Content *node = part.content();
+
+ if (!node->contents().isEmpty()) {
+ Q_ASSERT(false);
+ return MessagePart::Ptr();
+ }
+
+ const QGpgME::Protocol *useThisCryptProto = nullptr;
+
+ useThisCryptProto = QGpgME::openpgp();
+
+ //TODO: Load correct crypto Proto
+
+ part.nodeHelper()->setEncryptionState(node, KMMsgFullyEncrypted);
+
+ EncryptedMessagePart::Ptr mp(new EncryptedMessagePart(part.objectTreeParser(),
+ node->decodedText(), useThisCryptProto,
+ part.nodeHelper()->fromAsString(node), node));
+ mp->setIsEncrypted(true);
+ mp->setDecryptMessage(part.source()->decryptMessage());
+ PartMetaData *messagePart(mp->partMetaData());
+ if (!part.source()->decryptMessage()) {
+ part.nodeHelper()->setNodeProcessed(node, false); // Set the data node to done to prevent it from being processed
+ } else if (KMime::Content *newNode = part.nodeHelper()->decryptedNodeForContent(node)) {
+ // if we already have a decrypted node for part.objectTreeParser() encrypted node, don't do the decryption again
+ return MessagePart::Ptr(new MimeMessagePart(part.objectTreeParser(), newNode, true));
+ } else {
+ const auto codec = QTextCodec::codecForName("utf-8");
+ mp->startDecryption(node->decodedContent(), codec);
+
+ qCDebug(MIMETREEPARSER_LOG) << "decrypted, signed?:" << messagePart->isSigned;
+
+ if (!messagePart->inProgress) {
+ if (!messagePart->isEncrypted) {
+ return nullptr;
+ }
+ auto tempNode = new KMime::Content();
+ qDebug() << part.nodeHelper()->codec(node)->name();
+ tempNode->contentType()->setCharset("utf-8");
+ tempNode->setBody(KMime::CRLFtoLF(part.nodeHelper()->codec(node)->fromUnicode(mp->text())));
+ tempNode->parse();
+
+ if (!tempNode->head().isEmpty()) {
+ tempNode->contentDescription()->from7BitString("encrypted data");
+ }
+ part.nodeHelper()->cleanExtraContent(node);
+ mp->clearSubParts();
+
+ part.nodeHelper()->attachExtraContent(node, tempNode);
+
+ mp->parseInternal(tempNode, false);
+
+ part.nodeHelper()->setNodeProcessed(node, false); // Set the data node to done to prevent it from being processed
+ }
+ }
+ return mp;
+}
diff --git a/mimetreeparser/src/bodypartformatter.cpp b/mimetreeparser/src/bodypartformatter.cpp
--- a/mimetreeparser/src/bodypartformatter.cpp
+++ b/mimetreeparser/src/bodypartformatter.cpp
@@ -33,6 +33,7 @@
#include "bodyformatter/applicationpgpencrypted.h"
#include "bodyformatter/applicationpkcs7mime.h"
+#include "bodyformatter/encrypted.h"
#include "bodyformatter/mailman.h"
#include "bodyformatter/multipartalternative.h"
#include "bodyformatter/multipartmixed.h"
@@ -166,6 +167,7 @@
insert(QStringLiteral("application/octet-stream"), ApplicationPkcs7MimeBodyPartFormatter::create());
insert(QStringLiteral("application/octet-stream"), AnyTypeBodyPartFormatter::create());
+ insert(QStringLiteral("text/pgp"), EncryptedBodyPartFormatter::create());
insert(QStringLiteral("text/html"), TextHtmlBodyPartFormatter::create());
insert(QStringLiteral("text/rtf"), AnyTypeBodyPartFormatter::create());
insert(QStringLiteral("text/plain"), MailmanBodyPartFormatter::create());
diff --git a/mimetreeparser/src/messagepart.h b/mimetreeparser/src/messagepart.h
--- a/mimetreeparser/src/messagepart.h
+++ b/mimetreeparser/src/messagepart.h
@@ -125,6 +125,7 @@
void appendSubPart(const MessagePart::Ptr &messagePart);
const QVector &subParts() const;
bool hasSubParts() const;
+ void clearSubParts();
Interface::ObjectTreeSource *source() const;
NodeHelper* nodeHelper() const;
@@ -375,6 +376,7 @@
std::vector> mDecryptRecipients;
friend class DefaultRendererPrivate;
+ friend class EncryptedBodyPartFormatter;
};
class MIMETREEPARSER_EXPORT SignedMessagePart : public MessagePart
diff --git a/mimetreeparser/src/messagepart.cpp b/mimetreeparser/src/messagepart.cpp
--- a/mimetreeparser/src/messagepart.cpp
+++ b/mimetreeparser/src/messagepart.cpp
@@ -242,6 +242,11 @@
return !d->mBlocks.isEmpty();
}
+void MessagePart::clearSubParts()
+{
+ d->mBlocks.clear();
+}
+
//-----MessagePartList----------------------
MessagePartList::MessagePartList(ObjectTreeParser *otp)
: MessagePart(otp, QString())
@@ -1221,7 +1226,16 @@
}
mDecryptRecipients.clear();
+ bDecryptionOk = !decryptResult.error();
+
+// std::stringstream ss;
+// ss << decryptResult << '\n' << verifyResult;
+// qCDebug(MIMETREEPARSER_LOG) << ss.str().c_str();
+
for (const auto &recipient : decryptResult.recipients()) {
+ if (!recipient.status()) {
+ bDecryptionOk = true;
+ }
GpgME::Key key;
QGpgME::KeyListJob *job = mCryptoProto->keyListJob(false, false, false); // local, no sigs
if (!job) {
@@ -1246,19 +1260,15 @@
}
mDecryptRecipients.push_back(std::make_pair(recipient, key));
}
- bDecryptionOk = !decryptResult.error();
-// std::stringstream ss;
-// ss << decryptResult << '\n' << verifyResult;
-// qCDebug(MIMETREEPARSER_LOG) << ss.str().c_str();
if (!bDecryptionOk && partMetaData()->isSigned) {
//Only a signed part
partMetaData()->isEncrypted = false;
bDecryptionOk = true;
mDecryptedData = plainText;
} else {
mPassphraseError = decryptResult.error().isCanceled() || decryptResult.error().code() == GPG_ERR_NO_SECKEY;
- partMetaData()->isEncrypted = decryptResult.error().code() != GPG_ERR_NO_DATA;
+ partMetaData()->isEncrypted = bDecryptionOk || decryptResult.error().code() != GPG_ERR_NO_DATA;
partMetaData()->errorText = QString::fromLocal8Bit(decryptResult.error().asString());
if (partMetaData()->isEncrypted && decryptResult.numRecipients() > 0) {
partMetaData()->keyId = decryptResult.recipient(0).keyID();
diff --git a/mimetreeparser/src/nodehelper.h b/mimetreeparser/src/nodehelper.h
--- a/mimetreeparser/src/nodehelper.h
+++ b/mimetreeparser/src/nodehelper.h
@@ -87,6 +87,8 @@
/** Attach an extra node to an existing node */
void attachExtraContent(KMime::Content *topLevelNode, KMime::Content *content);
+ void cleanExtraContent(KMime::Content *topLevelNode);
+
/** Get the extra nodes attached to the @param topLevelNode and all sub-nodes of @param topLevelNode */
QList extraContents(KMime::Content *topLevelNode) const;
diff --git a/mimetreeparser/src/nodehelper.cpp b/mimetreeparser/src/nodehelper.cpp
--- a/mimetreeparser/src/nodehelper.cpp
+++ b/mimetreeparser/src/nodehelper.cpp
@@ -815,6 +815,12 @@
mExtraContents[topLevelNode].append(content);
}
+void NodeHelper::cleanExtraContent(KMime::Content *topLevelNode)
+{
+ qCDebug(MIMETREEPARSER_LOG) << "remove all extraContents for" << topLevelNode;
+ mExtraContents[topLevelNode].clear();
+}
+
QList< KMime::Content * > NodeHelper::extraContents(KMime::Content *topLevelnode) const
{
return mExtraContents.value(topLevelnode);