diff --git a/messageviewer/src/messagepartthemes/default/autotests/objecttreeparsertest.cpp b/messageviewer/src/messagepartthemes/default/autotests/objecttreeparsertest.cpp index 5ce0479a..c876d721 100644 --- a/messageviewer/src/messagepartthemes/default/autotests/objecttreeparsertest.cpp +++ b/messageviewer/src/messagepartthemes/default/autotests/objecttreeparsertest.cpp @@ -1,385 +1,174 @@ /* Copyright 2009 Thomas McGuire This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "objecttreeparsertest.h" #include "util.h" #include "setupenv.h" #include #include #include using namespace MessageViewer; using namespace MimeTreeParser; QTEST_MAIN(ObjectTreeParserTester) void ObjectTreeParserTester::initTestCase() { Test::setupEnv(); } -void ObjectTreeParserTester::test_parsePlainMessage() -{ - KMime::Message::Ptr msg(new KMime::Message()); - QByteArray content( - "From: Thomas McGuire \n" - "Subject: Plain Message Test\n" - "Date: Wed, 5 Aug 2009 10:58:27 +0200\n" - "MIME-Version: 1.0\n" - "Content-Type: text/plain;\n" - " charset=\"iso-8859-15\"\n" - "\n" - "This is the message text.\n"); - msg->setContent(content); - msg->parse(); - - QCOMPARE(msg->subject()->as7BitString(false).constData(), "Plain Message Test"); - QCOMPARE(msg->contents().size(), 0); - - // Parse the message - Test::ObjectTreeSource emptySource(nullptr, nullptr); - ObjectTreeParser otp(&emptySource); - otp.parseObjectTree(msg.data()); - - // Check that the textual content and the charset have the expected values - QCOMPARE(otp.plainTextContent(), QStringLiteral("This is the message text.\n")); - QVERIFY(otp.htmlContent().isEmpty()); - QCOMPARE(otp.plainTextContentCharset().toLower(), QByteArray("iso-8859-15")); - - // Check that the message was not modified in any way - QCOMPARE(msg->encodedContent().constData(), content.constData()); - - // Test that the charset of messages without an explicit charset declaration - // is correct - content - = "From: Thomas McGuire \n" - "Subject: Plain Message Test\n" - "Date: Wed, 5 Aug 2009 10:58:27 +0200\n" - "MIME-Version: 1.0\n" - "Content-Type: text/plain;\n" - "\n" - "This is the message text.\n"; - msg->setContent(content); - msg->parse(); - ObjectTreeParser otp2(&emptySource); - otp2.parseObjectTree(msg.data()); - QCOMPARE(otp2.plainTextContentCharset().constData(), msg->defaultCharset().constData()); -} - -void ObjectTreeParserTester::test_parseEncapsulatedMessage() -{ - KMime::Message::Ptr msg - = Test::readAndParseMail(QStringLiteral("encapsulated-with-attachment.mbox")); - QCOMPARE(msg->subject()->as7BitString(false).constData(), "Fwd: Test with attachment"); - QCOMPARE(msg->contents().size(), 2); - - // Parse the message - BufferedHtmlWriter testWriter; - testWriter.begin(); - Test::CSSHelper testCSSHelper; - NodeHelper nodeHelper; - Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); - ObjectTreeParser otp(&emptySource, &nodeHelper); - otp.parseObjectTree(msg.data()); - testWriter.end(); - - // Check that the OTP didn't modify the message in weird ways - QCOMPARE(msg->contents().size(), 2); - QCOMPARE(msg->contents().at(0)->contents().size(), 0); - QCOMPARE(msg->contents().at(1)->contents().size(), 1); - QCOMPARE(msg->contents().at(1)->contents().first()->contents().size(), 2); - QCOMPARE(msg->contents().at(1)->contents().first()->contents().at(0)->contents().size(), 0); - QCOMPARE(msg->contents().at(1)->contents().first()->contents().at(1)->contents().size(), 0); - - // Check that the textual content and the charset have the expected values - QCOMPARE(otp.plainTextContent(), QStringLiteral("This is the first encapsulating message.\n")); - QCOMPARE(otp.plainTextContentCharset().toLower(), QByteArray("iso-8859-15")); - QVERIFY(otp.htmlContent().isEmpty()); - - // Check that the objecttreeparser did process the encapsulated message - KMime::Message::Ptr encapsulated = msg->contents().at(1)->bodyAsMessage(); - QVERIFY(encapsulated.data()); - QVERIFY(nodeHelper.nodeProcessed(encapsulated.data())); - QVERIFY(nodeHelper.nodeProcessed(encapsulated->contents().at(0))); - QVERIFY(nodeHelper.nodeProcessed(encapsulated->contents().at(1))); - QVERIFY(nodeHelper.partMetaData(msg->contents().at(1)).isEncapsulatedRfc822Message); -} - -void ObjectTreeParserTester::test_missingContentTypeHeader() -{ - KMime::Message::Ptr msg = Test::readAndParseMail(QStringLiteral("no-content-type.mbox")); - QCOMPARE(msg->subject()->as7BitString( - false).constData(), "Simple Mail Without Content-Type Header"); - QCOMPARE(msg->contents().size(), 0); - - BufferedHtmlWriter testWriter; - testWriter.begin(); - Test::CSSHelper testCSSHelper; - NodeHelper nodeHelper; - Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); - ObjectTreeParser otp(&emptySource, &nodeHelper); - otp.parseObjectTree(msg.data()); - testWriter.end(); - - QCOMPARE(otp.plainTextContent().toLatin1().data(), "asdfasdf"); - QVERIFY(otp.htmlContent().isEmpty()); -} - -void ObjectTreeParserTester::test_inlinePGPDecryption() -{ - KMime::Message::Ptr msg = Test::readAndParseMail(QStringLiteral("inlinepgpencrypted.mbox")); - - QCOMPARE(msg->subject()->as7BitString(false).constData(), "inlinepgpencrypted"); - QCOMPARE(msg->contents().size(), 0); - - BufferedHtmlWriter testWriter; - testWriter.begin(); - Test::CSSHelper testCSSHelper; - NodeHelper nodeHelper; - Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); - ObjectTreeParser otp(&emptySource, &nodeHelper); - - emptySource.setAllowDecryption(true); - otp.parseObjectTree(msg.data()); - testWriter.end(); - - QCOMPARE(otp.plainTextContent().toLatin1().data(), "some random text"); - - // This test is only a workaround, till we can set the memento to the proper node of the mail. - KMime::Content *content = new KMime::Content; - QVERIFY(nodeHelper.bodyPartMemento(content, "decryptverify-attachment:?place=0")); - - QVERIFY(otp.htmlContent().isEmpty()); -} - -void ObjectTreeParserTester::test_inlinePGPSigned() -{ - KMime::Message::Ptr msg = Test::readAndParseMail(QStringLiteral("openpgp-inline-signed.mbox")); - - QCOMPARE(msg->subject()->as7BitString(false).constData(), "test"); - QCOMPARE(msg->contents().size(), 0); - - BufferedHtmlWriter testWriter; - testWriter.begin(); - Test::CSSHelper testCSSHelper; - NodeHelper nodeHelper; - Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); - ObjectTreeParser otp(&emptySource, &nodeHelper); - - emptySource.setAllowDecryption(true); - otp.parseObjectTree(msg.data()); - testWriter.end(); - - // This test is only a workaround, till we can set the memento to the proper node of the mail. - QVERIFY(nodeHelper.bodyPartMemento(nullptr, "verification-attachment:?place=0")); -} - -void ObjectTreeParserTester::test_HTML() -{ - KMime::Message::Ptr msg = Test::readAndParseMail(QStringLiteral("html.mbox")); - - QCOMPARE(msg->subject()->as7BitString(false).constData(), "HTML test"); - QCOMPARE(msg->contents().size(), 2); - - Test::ObjectTreeSource emptySource(nullptr, nullptr); - ObjectTreeParser otp(&emptySource); - - otp.parseObjectTree(msg.data()); - - QCOMPARE(otp.plainTextContent().toLatin1().data(), "Some HTML text"); - QVERIFY(otp.htmlContent().contains(QLatin1String( - "Some HTML text"))); - QCOMPARE(otp.htmlContentCharset().data(), "windows-1252"); -} - -void ObjectTreeParserTester::test_HTMLasText() -{ - KMime::Message::Ptr msg = Test::readAndParseMail(QStringLiteral("html.mbox")); - - QCOMPARE(msg->subject()->as7BitString(false).constData(), "HTML test"); - QCOMPARE(msg->contents().size(), 2); - - BufferedHtmlWriter testWriter; - testWriter.begin(); - Test::CSSHelper testCSSHelper; - Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); - ObjectTreeParser otp(&emptySource); - emptySource.setPreferredMode(MimeTreeParser::Util::MultipartPlain); - otp.parseObjectTree(msg.data()); - testWriter.end(); - - QCOMPARE(otp.htmlContent().toLatin1().constData(), ""); - QCOMPARE(otp.htmlContentCharset().constData(), ""); - QCOMPARE(otp.plainTextContent().toLatin1().constData(), "Some HTML text"); - QCOMPARE(otp.plainTextContentCharset().constData(), "windows-1252"); -} - -void ObjectTreeParserTester::test_HTMLOnly() -{ - KMime::Message::Ptr msg = Test::readAndParseMail(QStringLiteral("htmlonly.mbox")); - - QCOMPARE(msg->subject()->as7BitString(false).constData(), "HTML test"); - QCOMPARE(msg->contents().size(), 0); - - Test::ObjectTreeSource emptySource(nullptr, nullptr); - ObjectTreeParser otp(&emptySource); - - otp.parseObjectTree(msg.data()); - - QVERIFY(otp.plainTextContent().isEmpty()); - QVERIFY(otp.htmlContent().contains(QLatin1String("SOME HTML text."))); -} void ObjectTreeParserTester::test_HTMLOnlyText() { KMime::Message::Ptr msg = Test::readAndParseMail(QStringLiteral("htmlonly.mbox")); QCOMPARE(msg->subject()->as7BitString(false).constData(), "HTML test"); QCOMPARE(msg->contents().size(), 0); BufferedHtmlWriter testWriter; testWriter.begin(); Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource); emptySource.setPreferredMode(MimeTreeParser::Util::MultipartPlain); otp.parseObjectTree(msg.data()); testWriter.end(); QVERIFY(otp.plainTextContent().isEmpty()); QVERIFY(otp.htmlContent().contains(QLatin1String("SOME HTML text."))); QVERIFY(testWriter.data().contains("This is an HTML message. For security reasons, only the raw HTML code is shown.")); QVERIFY(testWriter.data().contains("SOME* HTML text.
")); } void ObjectTreeParserTester::test_HTMLExternal() { KMime::Message::Ptr msg = Test::readAndParseMail(QStringLiteral("htmlonlyexternal.mbox")); QCOMPARE(msg->subject()->as7BitString(false).constData(), "HTML test"); QCOMPARE(msg->contents().size(), 0); { BufferedHtmlWriter testWriter; testWriter.begin(); Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource); otp.parseObjectTree(msg.data()); testWriter.end(); QVERIFY(otp.plainTextContent().isEmpty()); QVERIFY(otp.htmlContent().contains(QLatin1String("SOME HTML text."))); QVERIFY(testWriter.data().contains("SOME HTML text.")); QVERIFY(testWriter.data().contains("This HTML message may contain external references to images etc. For security/privacy reasons external references are not loaded.")); } { BufferedHtmlWriter testWriter; testWriter.begin(); Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource); emptySource.setHtmlLoadExternal(true); otp.parseObjectTree(msg.data()); testWriter.end(); QVERIFY(otp.htmlContent().contains(QLatin1String("SOME HTML text."))); QVERIFY(testWriter.data().contains("SOME HTML text.")); QVERIFY(!testWriter.data().contains("This HTML message may contain external references to images etc. For security/privacy reasons external references are not loaded.")); } } void ObjectTreeParserTester::test_Alternative() { KMime::Message::Ptr msg = Test::readAndParseMail(QStringLiteral("alternative.mbox")); QCOMPARE(msg->contents().size(), 2); { BufferedHtmlWriter testWriter; testWriter.begin(); Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource); emptySource.setPreferredMode(MimeTreeParser::Util::MultipartPlain); otp.parseObjectTree(msg.data()); testWriter.end(); QVERIFY(otp.htmlContent().isEmpty()); QVERIFY(otp.plainTextContent().contains(QLatin1String( "If you can see this text it means that your email client couldn't display our newsletter properly."))); QVERIFY(testWriter.data().contains("If you can see this text it means that your email client couldn't display our newsletter properly.")); } { BufferedHtmlWriter testWriter; testWriter.begin(); Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource); emptySource.setPreferredMode(MimeTreeParser::Util::MultipartHtml); otp.parseObjectTree(msg.data()); testWriter.end(); QVERIFY(otp.plainTextContent().contains(QLatin1String( "If you can see this text it means that your email client couldn't display our newsletter properly."))); QVERIFY(otp.htmlContent().contains(QLatin1String( "Some HTML text

"))); QVERIFY(testWriter.data().contains("Some HTML text

")); } msg = Test::readAndParseMail(QStringLiteral("alternative-notext.mbox")); QCOMPARE(msg->contents().size(), 1); { BufferedHtmlWriter testWriter; testWriter.begin(); Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource); emptySource.setPreferredMode(MimeTreeParser::Util::MultipartPlain); otp.parseObjectTree(msg.data()); testWriter.end(); QVERIFY(otp.plainTextContent().isEmpty()); QVERIFY(otp.htmlContent().isEmpty()); QVERIFY(testWriter.data().contains("Some *HTML* text")); } { BufferedHtmlWriter testWriter; testWriter.begin(); Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource); emptySource.setPreferredMode(MimeTreeParser::Util::MultipartHtml); otp.parseObjectTree(msg.data()); testWriter.end(); QVERIFY(otp.plainTextContent().isEmpty()); QVERIFY(otp.htmlContent().contains(QLatin1String( "Some HTML text

"))); QVERIFY(testWriter.data().contains("Some HTML text

")); } } diff --git a/messageviewer/src/messagepartthemes/default/autotests/objecttreeparsertest.h b/messageviewer/src/messagepartthemes/default/autotests/objecttreeparsertest.h index bda2cfa8..9f6cb1b6 100644 --- a/messageviewer/src/messagepartthemes/default/autotests/objecttreeparsertest.h +++ b/messageviewer/src/messagepartthemes/default/autotests/objecttreeparsertest.h @@ -1,45 +1,37 @@ /* Copyright 2009 Thomas McGuire This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef OBJECTTREEPARSERTEST_H #define OBJECTTREEPARSERTEST_H #include class ObjectTreeParserTester : public QObject { Q_OBJECT public Q_SLOTS: void initTestCase(); private Q_SLOTS: - void test_parseEncapsulatedMessage(); - void test_parsePlainMessage(); - void test_missingContentTypeHeader(); - void test_inlinePGPDecryption(); - void test_inlinePGPSigned(); - void test_HTML(); - void test_HTMLasText(); - void test_HTMLOnly(); void test_HTMLOnlyText(); void test_HTMLExternal(); void test_Alternative(); }; #endif diff --git a/mimetreeparser/autotests/basicobjecttreeparsertest.cpp b/mimetreeparser/autotests/basicobjecttreeparsertest.cpp index 8cee073b..d7c60b7d 100644 --- a/mimetreeparser/autotests/basicobjecttreeparsertest.cpp +++ b/mimetreeparser/autotests/basicobjecttreeparsertest.cpp @@ -1,401 +1,595 @@ /* Copyright (c) 2010 Thomas McGuire Copyright (c) 2019 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 "basicobjecttreeparsertest.h" #include "util.h" #include "setupenv.h" #include #include #include #include #include #include #include using namespace MimeTreeParser; QTEST_MAIN(ObjectTreeParserTest) void ObjectTreeParserTest::initTestCase() { Test::setupEnv(); } QString stringifyMessagePartTree(const MimeTreeParser::MessagePart::Ptr &messagePart, QString indent) { const QString line = QStringLiteral("%1 * %3\n").arg(indent, QString::fromUtf8(messagePart->metaObject()->className())); QString ret = line; indent += QLatin1Char(' '); foreach (const auto &subPart, messagePart->subParts()) { ret += stringifyMessagePartTree(subPart, indent); } return ret; } void testMessagePartTree(const MessagePart::Ptr &messagePart, const QString &mailFileName) { QString renderedTree = stringifyMessagePartTree(messagePart, QString()); const QString treeFileName = QLatin1String(MAIL_DATA_DIR) + QLatin1Char('/') + mailFileName + QStringLiteral(".tree"); const QString outTreeFileName = mailFileName + QStringLiteral(".tree"); { QFile f(outTreeFileName); f.open(QIODevice::WriteOnly); f.write(renderedTree.toUtf8()); f.close(); } // compare to reference file const QStringList args = QStringList() << QStringLiteral("-u") << treeFileName << outTreeFileName; QProcess proc; proc.setProcessChannelMode(QProcess::ForwardedChannels); proc.start(QStringLiteral("diff"), args); QVERIFY(proc.waitForFinished()); QCOMPARE(proc.exitCode(), 0); } void ObjectTreeParserTest::testMailWithoutEncryption() { KMime::Message::Ptr originalMessage = readAndParseMail(QStringLiteral("encapsulated-with-attachment.mbox")); NodeHelper nodeHelper; SimpleObjectTreeSource testSource; ObjectTreeParser otp(&testSource, &nodeHelper); otp.parseObjectTree(originalMessage.data()); QVERIFY(!nodeHelper.unencryptedMessage(originalMessage)); } void ObjectTreeParserTest::testSignedForwardedOpenPGPSignedEncrypted() { KMime::Message::Ptr originalMessage = readAndParseMail(QStringLiteral("signed-forward-openpgp-signed-encrypted.mbox")); NodeHelper nodeHelper; SimpleObjectTreeSource testSource; ObjectTreeParser otp(&testSource, &nodeHelper); otp.parseObjectTree(originalMessage.data()); QCOMPARE(otp.plainTextContent().toLatin1().data(), "bla bla bla"); // The textual content doesn't include the encrypted encapsulated message by design QCOMPARE(nodeHelper.overallEncryptionState( originalMessage.data()), KMMsgPartiallyEncrypted); QCOMPARE(nodeHelper.overallSignatureState( originalMessage.data()), KMMsgFullySigned); KMime::Message::Ptr unencryptedMessage = nodeHelper.unencryptedMessage(originalMessage); QVERIFY(!unencryptedMessage); // We must not invalidate the outer signature } void ObjectTreeParserTest::testForwardedOpenPGPSignedEncrypted() { KMime::Message::Ptr originalMessage = readAndParseMail(QStringLiteral("forward-openpgp-signed-encrypted.mbox")); NodeHelper nodeHelper; SimpleObjectTreeSource testSource; ObjectTreeParser otp(&testSource, &nodeHelper); testSource.setDecryptMessage(true); otp.parseObjectTree(originalMessage.data()); QCOMPARE(otp.plainTextContent().toLatin1().data(), "bla bla bla"); // The textual content doesn't include the encrypted encapsulated message by design QCOMPARE(nodeHelper.overallEncryptionState( originalMessage.data()), KMMsgPartiallyEncrypted); QCOMPARE(nodeHelper.overallSignatureState( originalMessage.data()), KMMsgPartiallySigned); // Now, test that the unencrypted message is generated correctly KMime::Message::Ptr unencryptedMessage = nodeHelper.unencryptedMessage(originalMessage); QVERIFY(unencryptedMessage.data()); QCOMPARE(unencryptedMessage->contentType()->mimeType().data(), "multipart/mixed"); QCOMPARE(unencryptedMessage->contents().size(), 2); QCOMPARE(unencryptedMessage->contents().first()->contentType()->mimeType().data(), "text/plain"); QCOMPARE(unencryptedMessage->contents().first()->decodedContent().data(), "bla bla bla"); QCOMPARE(unencryptedMessage->contents().at( 1)->contentType()->mimeType().data(), "message/rfc822"); KMime::Message::Ptr encapsulated = unencryptedMessage->contents().at(1)->bodyAsMessage(); QCOMPARE(encapsulated->contentType()->mimeType().data(), "multipart/signed"); QCOMPARE(encapsulated->contents().size(), 2); QCOMPARE(encapsulated->contents().first()->contentType()->mimeType().data(), "text/plain"); QCOMPARE(encapsulated->contents().at( 1)->contentType()->mimeType().data(), "application/pgp-signature"); QCOMPARE(encapsulated->contents().first()->decodedContent().data(), "encrypted message text"); // TODO: Check that the signature is valid } void ObjectTreeParserTest::testSMIMESignedEncrypted() { KMime::Message::Ptr originalMessage = readAndParseMail(QStringLiteral("smime-signed-encrypted.mbox")); NodeHelper nodeHelper; SimpleObjectTreeSource testSource; ObjectTreeParser otp(&testSource, &nodeHelper); testSource.setDecryptMessage(true); otp.parseObjectTree(originalMessage.data()); QCOMPARE(otp.plainTextContent().toLatin1().data(), "encrypted message text"); QCOMPARE(nodeHelper.overallEncryptionState( originalMessage.data()), KMMsgFullyEncrypted); QCOMPARE(nodeHelper.overallSignatureState( originalMessage.data()), KMMsgFullySigned); // Now, test that the unencrypted message is generated correctly KMime::Message::Ptr unencryptedMessage = nodeHelper.unencryptedMessage(originalMessage); QCOMPARE(unencryptedMessage->contentType()->mimeType().data(), "multipart/signed"); QCOMPARE(unencryptedMessage->contents().size(), 2); QCOMPARE(unencryptedMessage->contents().first()->contentType()->mimeType().data(), "text/plain"); QCOMPARE(unencryptedMessage->contents().at( 1)->contentType()->mimeType().data(), "application/pkcs7-signature"); QCOMPARE( unencryptedMessage->contents().first()->decodedContent().data(), "encrypted message text"); // TODO: Check that the signature is valid } void ObjectTreeParserTest::testOpenPGPSignedEncrypted() { KMime::Message::Ptr originalMessage = readAndParseMail(QStringLiteral("openpgp-signed-encrypted.mbox")); NodeHelper nodeHelper; SimpleObjectTreeSource testSource; ObjectTreeParser otp(&testSource, &nodeHelper); testSource.setDecryptMessage(true); otp.parseObjectTree(originalMessage.data()); QCOMPARE(otp.plainTextContent().toLatin1().data(), "encrypted message text"); QCOMPARE(nodeHelper.overallEncryptionState( originalMessage.data()), KMMsgFullyEncrypted); QCOMPARE(nodeHelper.overallSignatureState( originalMessage.data()), KMMsgFullySigned); // Now, test that the unencrypted message is generated correctly KMime::Message::Ptr unencryptedMessage = nodeHelper.unencryptedMessage(originalMessage); QCOMPARE(unencryptedMessage->contentType()->mimeType().data(), "multipart/signed"); QCOMPARE(unencryptedMessage->contents().size(), 2); QCOMPARE(unencryptedMessage->contents().first()->contentType()->mimeType().data(), "text/plain"); QCOMPARE(unencryptedMessage->contents().at( 1)->contentType()->mimeType().data(), "application/pgp-signature"); QCOMPARE( unencryptedMessage->contents().first()->decodedContent().data(), "encrypted message text"); // TODO: Check that the signature is valid } void ObjectTreeParserTest::testOpenPGPEncryptedAndSigned() { KMime::Message::Ptr originalMessage = readAndParseMail(QStringLiteral("openpgp-encrypted+signed.mbox")); NodeHelper nodeHelper; SimpleObjectTreeSource testSource; ObjectTreeParser otp(&testSource, &nodeHelper); testSource.setDecryptMessage(true); otp.parseObjectTree(originalMessage.data()); QCOMPARE(otp.plainTextContent().toLatin1().data(), "encrypted message text"); QCOMPARE(nodeHelper.overallEncryptionState( originalMessage.data()), KMMsgFullyEncrypted); QCOMPARE(nodeHelper.overallSignatureState( originalMessage.data()), KMMsgFullySigned); // Now, test that the unencrypted message is generated correctly KMime::Message::Ptr unencryptedMessage = nodeHelper.unencryptedMessage(originalMessage); QCOMPARE(unencryptedMessage->contentType()->mimeType().data(), "text/plain"); QCOMPARE(unencryptedMessage->contents().size(), 0); QCOMPARE(unencryptedMessage->decodedContent().data(), "encrypted message text"); // TODO: Check that the signature is valid } void ObjectTreeParserTest::testOpenPGPEncrypted() { KMime::Message::Ptr originalMessage = readAndParseMail(QStringLiteral("openpgp-encrypted.mbox")); NodeHelper nodeHelper; SimpleObjectTreeSource testSource; ObjectTreeParser otp(&testSource, &nodeHelper); testSource.setDecryptMessage(true); otp.parseObjectTree(originalMessage.data()); QCOMPARE(otp.plainTextContent().toLatin1().data(), "encrypted message text"); QCOMPARE(nodeHelper.overallEncryptionState( originalMessage.data()), KMMsgFullyEncrypted); // Now, test that the unencrypted message is generated correctly KMime::Message::Ptr unencryptedMessage = nodeHelper.unencryptedMessage(originalMessage); QCOMPARE(unencryptedMessage->contentType()->mimeType().data(), "text/plain"); QCOMPARE(unencryptedMessage->decodedContent().data(), "encrypted message text"); QCOMPARE(unencryptedMessage->contents().size(), 0); } void ObjectTreeParserTest::testOpenPGPEncryptedNotDecrypted() { KMime::Message::Ptr originalMessage = readAndParseMail(QStringLiteral("openpgp-encrypted.mbox")); NodeHelper nodeHelper; SimpleObjectTreeSource testSource; ObjectTreeParser otp(&testSource, &nodeHelper); otp.parseObjectTree(originalMessage.data()); QCOMPARE(nodeHelper.overallEncryptionState( originalMessage.data()), KMMsgFullyEncrypted); QCOMPARE(otp.plainTextContent().toLatin1().data(), ""); KMime::Message::Ptr unencryptedMessage = nodeHelper.unencryptedMessage(originalMessage); QVERIFY(!unencryptedMessage); } void ObjectTreeParserTest::testAsync_data() { QTest::addColumn("mailFileName"); QTest::addColumn("output"); QTest::newRow("openpgp-encrypt") << QStringLiteral("openpgp-encrypted.mbox") << QStringLiteral( "encrypted message text"); QTest::newRow("smime-opaque-sign") << QStringLiteral("smime-opaque-sign.mbox") << QStringLiteral("A simple signed only test."); QTest::newRow("smime-encrypt") << QStringLiteral("smime-encrypted.mbox") << QStringLiteral( "The quick brown fox jumped over the lazy dog."); QTest::newRow("openpgp-inline-encrypt") << QStringLiteral( "openpgp-inline-charset-encrypted.mbox") << QStringLiteral( "asdasd asd asd asdf sadf sdaf sadf \u00F6\u00E4\u00FC"); } void ObjectTreeParserTest::testAsync() { QFETCH(QString, mailFileName); QFETCH(QString, output); KMime::Message::Ptr originalMessage = readAndParseMail(mailFileName); NodeHelper nodeHelper; SimpleObjectTreeSource testSource; testSource.setDecryptMessage(true); { QEventLoop loop; ObjectTreeParser otp(&testSource, &nodeHelper); connect(&nodeHelper, &NodeHelper::update, &loop, &QEventLoop::quit); otp.setAllowAsync(true); otp.parseObjectTree(originalMessage.data()); loop.exec(); } // Job ended { ObjectTreeParser otp(&testSource, &nodeHelper); otp.setAllowAsync(true); otp.parseObjectTree(originalMessage.data()); QCOMPARE(otp.plainTextContent(), output); } } void ObjectTreeParserTest::testHtmlContent_data() { QTest::addColumn("mailFileName"); QTest::addColumn("output"); QTest::newRow("html-attachments1") << QStringLiteral("html-attachment1.mbox") << QStringLiteral( "

A Body Text

"); QTest::newRow("html-attachments2") << QStringLiteral("html-attachment2.mbox") << QStringLiteral("HTML Text"); } void ObjectTreeParserTest::testHtmlContent() { QFETCH(QString, mailFileName); QFETCH(QString, output); KMime::Message::Ptr originalMessage = readAndParseMail(mailFileName); NodeHelper nodeHelper; SimpleObjectTreeSource testSource; ObjectTreeParser otp(&testSource, &nodeHelper); testSource.setDecryptMessage(true); otp.parseObjectTree(originalMessage.data()); QVERIFY(otp.plainTextContent().isEmpty()); QCOMPARE(otp.htmlContent(), output); } void ObjectTreeParserTest::testMemoryHole() { const QString fileName = QStringLiteral("openpgp-encrypted-memoryhole.mbox"); KMime::Message::Ptr originalMessage = readAndParseMail(fileName); NodeHelper nodeHelper; SimpleObjectTreeSource testSource; ObjectTreeParser otp(&testSource, &nodeHelper); testSource.setDecryptMessage(true); otp.parseObjectTree(originalMessage.data()); QCOMPARE(nodeHelper.mailHeaderAsBase("from", originalMessage.data())->asUnicodeString(), QStringLiteral("you@example.com")); QCOMPARE(nodeHelper.mailHeaderAsBase("to", originalMessage.data())->asUnicodeString(), QStringLiteral("me@example.com")); QCOMPARE(nodeHelper.mailHeaderAsBase("subject", originalMessage.data())->asUnicodeString(), QStringLiteral("hidden subject")); QCOMPARE(nodeHelper.mailHeaderAsBase("cc", originalMessage.data())->asUnicodeString(), QStringLiteral("cc@example.com")); QCOMPARE(nodeHelper.mailHeaderAsBase("message-id", originalMessage.data())->asUnicodeString(), QStringLiteral("")); QCOMPARE(nodeHelper.mailHeaderAsBase("references", originalMessage.data())->asUnicodeString(), QStringLiteral("")); QCOMPARE(nodeHelper.mailHeaderAsBase("in-reply-to", originalMessage.data())->asUnicodeString(), QStringLiteral("")); QCOMPARE(nodeHelper.dateHeader(originalMessage.data()), QDateTime(QDate(2018, 1, 2), QTime(3,4,5))); } void ObjectTreeParserTest::testRenderedTree_data() { QTest::addColumn("mailFileName"); QDir dir(QStringLiteral(MAIL_DATA_DIR)); const auto l = dir.entryList(QStringList(QStringLiteral("*.mbox")), QDir::Files | QDir::Readable | QDir::NoSymLinks); for (const QString &file : l) { if (!QFile::exists(dir.path() + QLatin1Char('/') + file + QStringLiteral(".tree"))) { continue; } QTest::newRow(file.toLatin1().constData()) << file; } } void ObjectTreeParserTest::testRenderedTree() { QFETCH(QString, mailFileName); KMime::Message::Ptr originalMessage = readAndParseMail(mailFileName); NodeHelper nodeHelper; SimpleObjectTreeSource testSource; ObjectTreeParser otp(&testSource, &nodeHelper); testSource.setDecryptMessage(true); otp.parseObjectTree(originalMessage.data()); + testMessagePartTree(otp.parsedPart(), mailFileName); } + +void ObjectTreeParserTest::testParsePlainMessage() +{ + KMime::Message::Ptr msg(new KMime::Message()); + QByteArray content( + "From: Thomas McGuire \n" + "Subject: Plain Message Test\n" + "Date: Wed, 5 Aug 2009 10:58:27 +0200\n" + "MIME-Version: 1.0\n" + "Content-Type: text/plain;\n" + " charset=\"iso-8859-15\"\n" + "\n" + "This is the message text.\n"); + msg->setContent(content); + msg->parse(); + + QCOMPARE(msg->subject()->as7BitString(false).constData(), "Plain Message Test"); + QCOMPARE(msg->contents().size(), 0); + + // Parse the message + SimpleObjectTreeSource testSource; + ObjectTreeParser otp(&testSource); + otp.parseObjectTree(msg.data()); + + // Check that the textual content and the charset have the expected values + QCOMPARE(otp.plainTextContent(), QStringLiteral("This is the message text.\n")); + QVERIFY(otp.htmlContent().isEmpty()); + QCOMPARE(otp.plainTextContentCharset().toLower(), QByteArray("iso-8859-15")); + + // Check that the message was not modified in any way + QCOMPARE(msg->encodedContent().constData(), content.constData()); + + // Test that the charset of messages without an explicit charset declaration + // is correct + content + = "From: Thomas McGuire \n" + "Subject: Plain Message Test\n" + "Date: Wed, 5 Aug 2009 10:58:27 +0200\n" + "MIME-Version: 1.0\n" + "Content-Type: text/plain;\n" + "\n" + "This is the message text.\n"; + msg->setContent(content); + msg->parse(); + ObjectTreeParser otp2(&testSource); + otp2.parseObjectTree(msg.data()); + QCOMPARE(otp2.plainTextContentCharset().constData(), msg->defaultCharset().constData()); +} + +void ObjectTreeParserTest::testParseEncapsulatedMessage() +{ + KMime::Message::Ptr msg + = readAndParseMail(QStringLiteral("encapsulated-with-attachment.mbox")); + QCOMPARE(msg->subject()->as7BitString(false).constData(), "Fwd: Test with attachment"); + QCOMPARE(msg->contents().size(), 2); + + // Parse the message + SimpleObjectTreeSource testSource; + NodeHelper nodeHelper; + ObjectTreeParser otp(&testSource, &nodeHelper); + otp.parseObjectTree(msg.data()); + + // Check that the OTP didn't modify the message in weird ways + QCOMPARE(msg->contents().size(), 2); + QCOMPARE(msg->contents().at(0)->contents().size(), 0); + QCOMPARE(msg->contents().at(1)->contents().size(), 1); + QCOMPARE(msg->contents().at(1)->contents().first()->contents().size(), 2); + QCOMPARE(msg->contents().at(1)->contents().first()->contents().at(0)->contents().size(), 0); + QCOMPARE(msg->contents().at(1)->contents().first()->contents().at(1)->contents().size(), 0); + + // Check that the textual content and the charset have the expected values + QCOMPARE(otp.plainTextContent(), QStringLiteral("This is the first encapsulating message.\n")); + QCOMPARE(otp.plainTextContentCharset().toLower(), QByteArray("iso-8859-15")); + QVERIFY(otp.htmlContent().isEmpty()); + + // Check that the objecttreeparser did process the encapsulated message + KMime::Message::Ptr encapsulated = msg->contents().at(1)->bodyAsMessage(); + QVERIFY(encapsulated.data()); + QVERIFY(nodeHelper.nodeProcessed(encapsulated.data())); + QVERIFY(nodeHelper.nodeProcessed(encapsulated->contents().at(0))); + QVERIFY(nodeHelper.nodeProcessed(encapsulated->contents().at(1))); + QVERIFY(nodeHelper.partMetaData(msg->contents().at(1)).isEncapsulatedRfc822Message); +} + +void ObjectTreeParserTest::testMissingContentTypeHeader() +{ + KMime::Message::Ptr msg = readAndParseMail(QStringLiteral("no-content-type.mbox")); + QCOMPARE(msg->subject()->as7BitString( + false).constData(), "Simple Mail Without Content-Type Header"); + QCOMPARE(msg->contents().size(), 0); + + NodeHelper nodeHelper; + SimpleObjectTreeSource testSource; + ObjectTreeParser otp(&testSource, &nodeHelper); + otp.parseObjectTree(msg.data()); + + QCOMPARE(otp.plainTextContent().toLatin1().data(), "asdfasdf"); + QVERIFY(otp.htmlContent().isEmpty()); +} + +void ObjectTreeParserTest::testInlinePGPDecryption() +{ + KMime::Message::Ptr msg = readAndParseMail(QStringLiteral("inlinepgpencrypted.mbox")); + + QCOMPARE(msg->subject()->as7BitString(false).constData(), "inlinepgpencrypted"); + QCOMPARE(msg->contents().size(), 0); + + NodeHelper nodeHelper; + SimpleObjectTreeSource testSource; + ObjectTreeParser otp(&testSource, &nodeHelper); + + testSource.setDecryptMessage(true); + otp.parseObjectTree(msg.data()); + + QCOMPARE(otp.plainTextContent().toLatin1().data(), "some random text"); + + // This test is only a workaround, till we can set the memento to the proper node of the mail. + KMime::Content *content = new KMime::Content; + QVERIFY(nodeHelper.bodyPartMemento(content, "decryptverify-attachment:?place=0")); + + QVERIFY(otp.htmlContent().isEmpty()); +} + +void ObjectTreeParserTest::testInlinePGPSigned() +{ + KMime::Message::Ptr msg = readAndParseMail(QStringLiteral("openpgp-inline-signed.mbox")); + + QCOMPARE(msg->subject()->as7BitString(false).constData(), "test"); + QCOMPARE(msg->contents().size(), 0); + + NodeHelper nodeHelper; + SimpleObjectTreeSource testSource; + ObjectTreeParser otp(&testSource, &nodeHelper); + + testSource.setDecryptMessage(true); + otp.parseObjectTree(msg.data()); + + // This test is only a workaround, till we can set the memento to the proper node of the mail. + QVERIFY(nodeHelper.bodyPartMemento(nullptr, "verification-attachment:?place=0")); +} + +void ObjectTreeParserTest::testHTML() +{ + KMime::Message::Ptr msg = readAndParseMail(QStringLiteral("html.mbox")); + + QCOMPARE(msg->subject()->as7BitString(false).constData(), "HTML test"); + QCOMPARE(msg->contents().size(), 2); + + SimpleObjectTreeSource testSource; + ObjectTreeParser otp(&testSource); + + otp.parseObjectTree(msg.data()); + + QCOMPARE(otp.plainTextContent().toLatin1().data(), "Some HTML text"); + QVERIFY(otp.htmlContent().contains(QLatin1String( + "Some HTML text"))); + QCOMPARE(otp.htmlContentCharset().data(), "windows-1252"); +} + +void ObjectTreeParserTest::testHTMLasText() +{ + KMime::Message::Ptr msg = readAndParseMail(QStringLiteral("html.mbox")); + + QCOMPARE(msg->subject()->as7BitString(false).constData(), "HTML test"); + QCOMPARE(msg->contents().size(), 2); + + SimpleObjectTreeSource testSource; + ObjectTreeParser otp(&testSource); + + testSource.setPreferredMode(MimeTreeParser::Util::MultipartPlain); + otp.parseObjectTree(msg.data()); + + QCOMPARE(otp.htmlContent().toLatin1().constData(), ""); + QCOMPARE(otp.htmlContentCharset().constData(), ""); + QCOMPARE(otp.plainTextContent().toLatin1().constData(), "Some HTML text"); + QCOMPARE(otp.plainTextContentCharset().constData(), "windows-1252"); +} + +void ObjectTreeParserTest::testHTMLOnly() +{ + KMime::Message::Ptr msg = readAndParseMail(QStringLiteral("htmlonly.mbox")); + + QCOMPARE(msg->subject()->as7BitString(false).constData(), "HTML test"); + QCOMPARE(msg->contents().size(), 0); + + SimpleObjectTreeSource testSource; + ObjectTreeParser otp(&testSource); + + otp.parseObjectTree(msg.data()); + + QVERIFY(otp.plainTextContent().isEmpty()); + QVERIFY(otp.htmlContent().contains(QLatin1String("SOME HTML text."))); +} diff --git a/mimetreeparser/autotests/basicobjecttreeparsertest.h b/mimetreeparser/autotests/basicobjecttreeparsertest.h index 6ff0c130..12426f55 100644 --- a/mimetreeparser/autotests/basicobjecttreeparsertest.h +++ b/mimetreeparser/autotests/basicobjecttreeparsertest.h @@ -1,48 +1,56 @@ /* Copyright (c) 2010 Thomas McGuire Copyright (c) 2019 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_TESTS_OBJECTTREEPARSERTEST_H #define MIMETREEPARSER_TESTS_OBJECTTREEPARSERTEST_H #include class ObjectTreeParserTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void testMailWithoutEncryption(); void testSMIMESignedEncrypted(); void testOpenPGPSignedEncrypted(); void testOpenPGPEncryptedAndSigned(); void testForwardedOpenPGPSignedEncrypted(); void testSignedForwardedOpenPGPSignedEncrypted(); void testOpenPGPEncrypted(); void testOpenPGPEncryptedNotDecrypted(); void testAsync_data(); void testAsync(); void testHtmlContent_data(); void testHtmlContent(); void testMemoryHole(); void testRenderedTree(); void testRenderedTree_data(); + void testParsePlainMessage(); + void testParseEncapsulatedMessage(); + void testMissingContentTypeHeader(); + void testInlinePGPDecryption(); + void testInlinePGPSigned(); + void testHTML(); + void testHTMLasText(); + void testHTMLOnly(); }; #endif // MIMETREEPARSER_TESTS_OBJECTTREEPARSERTEST_H diff --git a/mimetreeparser/src/simpleobjecttreesource.cpp b/mimetreeparser/src/simpleobjecttreesource.cpp index d402a4bc..f0ec6f8f 100644 --- a/mimetreeparser/src/simpleobjecttreesource.cpp +++ b/mimetreeparser/src/simpleobjecttreesource.cpp @@ -1,82 +1,89 @@ /* Copyright (C) 2017 Sandro Kanuß This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "simpleobjecttreesource.h" #include #include #include using namespace MimeTreeParser; namespace MimeTreeParser { class SimpleObjectTreeSourcePrivate { public: bool mDecryptMessage = false; + Util::HtmlMode mPreferredMode = Util::Html; }; } SimpleObjectTreeSource::SimpleObjectTreeSource() : d(new SimpleObjectTreeSourcePrivate) { } SimpleObjectTreeSource::~SimpleObjectTreeSource() = default; bool SimpleObjectTreeSource::autoImportKeys() const { return true; } const BodyPartFormatterFactory *SimpleObjectTreeSource::bodyPartFormatterFactory() { return BodyPartFormatterFactory::instance(); } bool SimpleObjectTreeSource::decryptMessage() const { return d->mDecryptMessage; } void SimpleObjectTreeSource::setDecryptMessage(bool decryptMessage) { d->mDecryptMessage = decryptMessage; } +void SimpleObjectTreeSource::setPreferredMode(MimeTreeParser::Util::HtmlMode mode) +{ + d->mPreferredMode = mode; +} + + MimeTreeParser::Util::HtmlMode SimpleObjectTreeSource::preferredMode() const { - return Util::Html; + return d->mPreferredMode; } const QTextCodec *SimpleObjectTreeSource::overrideCodec() { return nullptr; } void SimpleObjectTreeSource::setHtmlMode(MimeTreeParser::Util::HtmlMode mode, const QList &availableModes) { Q_UNUSED(mode); Q_UNUSED(availableModes); } void SimpleObjectTreeSource::render(const MessagePart::Ptr &msgPart, bool showOnlyOneMimePart) { Q_UNUSED(msgPart); Q_UNUSED(showOnlyOneMimePart); } diff --git a/mimetreeparser/src/simpleobjecttreesource.h b/mimetreeparser/src/simpleobjecttreesource.h index 4c93c90b..e016d658 100644 --- a/mimetreeparser/src/simpleobjecttreesource.h +++ b/mimetreeparser/src/simpleobjecttreesource.h @@ -1,57 +1,59 @@ /* Copyright (C) 2017 Sandro Kanuß 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_SIMPLEOBJECTTREESOURCE_H #define MIMETREEPARSER_SIMPLEOBJECTTREESOURCE_H #include "mimetreeparser/objecttreesource.h" #include namespace MimeTreeParser { class SimpleObjectTreeSourcePrivate; /** * A very simple ObjectTreeSource. * mostly used in tests and outside the read redering */ class MIMETREEPARSER_EXPORT SimpleObjectTreeSource : public Interface::ObjectTreeSource { public: SimpleObjectTreeSource(); ~SimpleObjectTreeSource() override; bool autoImportKeys() const override; const BodyPartFormatterFactory *bodyPartFormatterFactory() override; bool decryptMessage() const override; void setDecryptMessage(bool decryptMessage); void setHtmlMode(MimeTreeParser::Util::HtmlMode mode, const QList &availableModes) override; + + void setPreferredMode(MimeTreeParser::Util::HtmlMode mode); MimeTreeParser::Util::HtmlMode preferredMode() const override; const QTextCodec *overrideCodec() override; void render(const MessagePartPtr &msgPart, bool showOnlyOneMimePart) override; private: std::unique_ptr d; }; } #endif