File indexing completed on 2024-06-23 05:20:28
0001 /* 0002 Copyright (c) 2016 Sandro Knauß <knauss@kolabsystems.com> 0003 0004 This library is free software; you can redistribute it and/or modify it 0005 under the terms of the GNU Library General Public License as published by 0006 the Free Software Foundation; either version 2 of the License, or (at your 0007 option) any later version. 0008 0009 This library is distributed in the hope that it will be useful, but WITHOUT 0010 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0011 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 0012 License for more details. 0013 0014 You should have received a copy of the GNU Library General Public License 0015 along with this library; see the file COPYING.LIB. If not, write to the 0016 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 0017 02110-1301, USA. 0018 */ 0019 #include <objecttreeparser.h> 0020 0021 #include <QTest> 0022 #include <QDebug> 0023 #include <QTimeZone> 0024 0025 QByteArray readMailFromFile(const QString &mailFile) 0026 { 0027 QFile file(QLatin1String(MAIL_DATA_DIR) + QLatin1Char('/') + mailFile); 0028 file.open(QIODevice::ReadOnly); 0029 Q_ASSERT(file.isOpen()); 0030 return file.readAll(); 0031 } 0032 0033 class MimeTreeParserTest : public QObject 0034 { 0035 Q_OBJECT 0036 private slots: 0037 void testTextMail() 0038 { 0039 const auto expectedText = QStringLiteral("If you can see this text it means that your email client couldn't display our newsletter properly.\nPlease visit this link to view the newsletter on our website: http://www.gog.com/newsletter/"); 0040 MimeTreeParser::ObjectTreeParser otp; 0041 otp.parseObjectTree(readMailFromFile("plaintext.mbox")); 0042 auto partList = otp.collectContentParts(); 0043 QCOMPARE(partList.size(), 1); 0044 auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0045 QCOMPARE(part->text(), expectedText); 0046 QCOMPARE(part->charset(), QStringLiteral("utf-8").toLocal8Bit()); 0047 0048 QCOMPARE(part->encryptions().size(), 0); 0049 QCOMPARE(part->signatures().size(), 0); 0050 0051 QCOMPARE(otp.collectAttachmentParts().size(), 0); 0052 0053 QCOMPARE(otp.plainTextContent(), expectedText); 0054 QVERIFY(otp.htmlContent().isEmpty()); 0055 } 0056 0057 void testAlternative() 0058 { 0059 MimeTreeParser::ObjectTreeParser otp; 0060 otp.parseObjectTree(readMailFromFile("alternative.mbox")); 0061 auto partList = otp.collectContentParts(); 0062 QCOMPARE(partList.size(), 1); 0063 auto part = partList[0].dynamicCast<MimeTreeParser::AlternativeMessagePart>(); 0064 QVERIFY(bool(part)); 0065 QCOMPARE(part->plaintextContent(), QStringLiteral("If you can see this text it means that your email client couldn't display our newsletter properly.\nPlease visit this link to view the newsletter on our website: http://www.gog.com/newsletter/\n")); 0066 QCOMPARE(part->charset(), QStringLiteral("us-ascii").toLocal8Bit()); 0067 QCOMPARE(part->htmlContent(), QStringLiteral("<html><body><p><span>HTML</span> text</p></body></html>\n\n")); 0068 QCOMPARE(otp.collectAttachmentParts().size(), 0); 0069 QCOMPARE(part->encryptions().size(), 0); 0070 QCOMPARE(part->signatures().size(), 0); 0071 } 0072 0073 void testTextHtml() 0074 { 0075 auto expectedText = QStringLiteral("<html><body><p><span>HTML</span> text</p></body></html>"); 0076 MimeTreeParser::ObjectTreeParser otp; 0077 otp.parseObjectTree(readMailFromFile("html.mbox")); 0078 otp.print(); 0079 auto partList = otp.collectContentParts(); 0080 QCOMPARE(partList.size(), 1); 0081 auto part = partList[0].dynamicCast<MimeTreeParser::HtmlMessagePart>(); 0082 QVERIFY(bool(part)); 0083 QCOMPARE(part->htmlContent(), expectedText); 0084 QCOMPARE(part->charset(), QStringLiteral("windows-1252").toLocal8Bit()); 0085 QCOMPARE(part->encryptions().size(), 0); 0086 QCOMPARE(part->signatures().size(), 0); 0087 auto contentAttachmentList = otp.collectAttachmentParts(); 0088 QCOMPARE(contentAttachmentList.size(), 0); 0089 0090 QCOMPARE(otp.htmlContent(), expectedText); 0091 QVERIFY(otp.plainTextContent().isEmpty()); 0092 } 0093 0094 void testSMimeEncrypted() 0095 { 0096 MimeTreeParser::ObjectTreeParser otp; 0097 otp.parseObjectTree(readMailFromFile("smime-encrypted.mbox")); 0098 otp.print(); 0099 otp.decryptParts(); 0100 otp.print(); 0101 auto partList = otp.collectContentParts(); 0102 QCOMPARE(partList.size(), 1); 0103 auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0104 QVERIFY(bool(part)); 0105 QCOMPARE(part->text(), QStringLiteral("The quick brown fox jumped over the lazy dog.")); 0106 QCOMPARE(part->charset(), QStringLiteral("us-ascii").toLocal8Bit()); 0107 QCOMPARE(part->encryptions().size(), 1); 0108 QCOMPARE(part->signatures().size(), 0); 0109 auto contentAttachmentList = otp.collectAttachmentParts(); 0110 QCOMPARE(contentAttachmentList.size(), 0); 0111 } 0112 0113 void testOpenPGPEncryptedAttachment() 0114 { 0115 MimeTreeParser::ObjectTreeParser otp; 0116 otp.parseObjectTree(readMailFromFile("openpgp-encrypted-attachment-and-non-encrypted-attachment.mbox")); 0117 otp.print(); 0118 otp.decryptParts(); 0119 otp.print(); 0120 auto partList = otp.collectContentParts(); 0121 QCOMPARE(partList.size(), 1); 0122 auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0123 QVERIFY(bool(part)); 0124 QCOMPARE(part->text(), QStringLiteral("test text")); 0125 QCOMPARE(part->charset(), QStringLiteral("us-ascii").toLocal8Bit()); 0126 QCOMPARE(part->encryptions().size(), 1); 0127 QCOMPARE(part->signatures().size(), 1); 0128 QCOMPARE(part->encryptionState(), MimeTreeParser::KMMsgFullyEncrypted); 0129 QCOMPARE(part->signatureState(), MimeTreeParser::KMMsgFullySigned); 0130 auto contentAttachmentList = otp.collectAttachmentParts(); 0131 QCOMPARE(contentAttachmentList.size(), 2); 0132 // QCOMPARE(contentAttachmentList[0]->availableContents(), QVector<QByteArray>() << "text/plain"); 0133 // QCOMPARE(contentAttachmentList[0]->content().size(), 1); 0134 QCOMPARE(contentAttachmentList[0]->encryptions().size(), 1); 0135 QCOMPARE(contentAttachmentList[0]->signatures().size(), 1); 0136 QCOMPARE(contentAttachmentList[0]->encryptionState(), MimeTreeParser::KMMsgFullyEncrypted); 0137 QCOMPARE(contentAttachmentList[0]->signatureState(), MimeTreeParser::KMMsgFullySigned); 0138 // QCOMPARE(contentAttachmentList[1]->availableContents(), QVector<QByteArray>() << "image/png"); 0139 // QCOMPARE(contentAttachmentList[1]->content().size(), 1); 0140 QCOMPARE(contentAttachmentList[1]->encryptions().size(), 0); 0141 QCOMPARE(contentAttachmentList[1]->signatures().size(), 0); 0142 QCOMPARE(contentAttachmentList[1]->encryptionState(), MimeTreeParser::KMMsgNotEncrypted); 0143 QCOMPARE(contentAttachmentList[1]->signatureState(), MimeTreeParser::KMMsgNotSigned); 0144 } 0145 0146 void testOpenPGPInline() 0147 { 0148 MimeTreeParser::ObjectTreeParser otp; 0149 otp.parseObjectTree(readMailFromFile("openpgp-inline-charset-encrypted.mbox")); 0150 otp.print(); 0151 otp.decryptParts(); 0152 otp.print(); 0153 auto partList = otp.collectContentParts(); 0154 QCOMPARE(partList.size(), 1); 0155 auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0156 QVERIFY(bool(part)); 0157 QCOMPARE(part->charset(), QStringLiteral("ISO-8859-15").toLocal8Bit()); 0158 QCOMPARE(part->text(), QString::fromUtf8("asdasd asd asd asdf sadf sdaf sadf öäü")); 0159 0160 QCOMPARE(part->encryptions().size(), 1); 0161 QCOMPARE(part->signatures().size(), 1); 0162 QCOMPARE(otp.collectAttachmentParts().size(), 0); 0163 } 0164 0165 void testOpenPPGInlineWithNonEncText() 0166 { 0167 MimeTreeParser::ObjectTreeParser otp; 0168 otp.parseObjectTree(readMailFromFile("openpgp-inline-encrypted+nonenc.mbox")); 0169 otp.print(); 0170 otp.decryptParts(); 0171 otp.print(); 0172 auto partList = otp.collectContentParts(); 0173 QCOMPARE(partList.size(), 1); 0174 auto part1 = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0175 QVERIFY(bool(part1)); 0176 QCOMPARE(part1->text(), QStringLiteral("Not encrypted not signed :(\n\nsome random text")); 0177 //TODO test if we get the proper subparts with the appropriate encryptions 0178 QCOMPARE(part1->charset(), QStringLiteral("us-ascii").toLocal8Bit()); 0179 0180 QCOMPARE(part1->encryptionState(), MimeTreeParser::KMMsgPartiallyEncrypted); 0181 QCOMPARE(part1->signatureState(), MimeTreeParser::KMMsgNotSigned); 0182 0183 // QCOMPARE(part1->text(), QStringLiteral("Not encrypted not signed :(\n\n")); 0184 // QCOMPARE(part1->charset(), QStringLiteral("us-ascii").toLocal8Bit()); 0185 // QCOMPARE(contentList[1]->content(), QStringLiteral("some random text").toLocal8Bit()); 0186 // QCOMPARE(contentList[1]->charset(), QStringLiteral("us-ascii").toLocal8Bit()); 0187 // QCOMPARE(contentList[1]->encryptions().size(), 1); 0188 // QCOMPARE(contentList[1]->signatures().size(), 0); 0189 QCOMPARE(otp.collectAttachmentParts().size(), 0); 0190 } 0191 0192 void testEncryptionBlock() 0193 { 0194 MimeTreeParser::ObjectTreeParser otp; 0195 otp.parseObjectTree(readMailFromFile("openpgp-encrypted-attachment-and-non-encrypted-attachment.mbox")); 0196 otp.print(); 0197 otp.decryptParts(); 0198 otp.print(); 0199 auto partList = otp.collectContentParts(); 0200 QCOMPARE(partList.size(), 1); 0201 auto part1 = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0202 QVERIFY(bool(part1)); 0203 QCOMPARE(part1->encryptions().size(), 1); 0204 // auto enc = contentList[0]->encryptions()[0]; 0205 // QCOMPARE((int) enc->recipients().size(), 2); 0206 0207 // auto r = enc->recipients()[0]; 0208 // QCOMPARE(r->keyid(),QStringLiteral("14B79E26050467AA")); 0209 // QCOMPARE(r->name(),QStringLiteral("kdetest")); 0210 // QCOMPARE(r->email(),QStringLiteral("you@you.com")); 0211 // QCOMPARE(r->comment(),QStringLiteral("")); 0212 0213 // r = enc->recipients()[1]; 0214 // QCOMPARE(r->keyid(),QStringLiteral("8D9860C58F246DE6")); 0215 // QCOMPARE(r->name(),QStringLiteral("unittest key")); 0216 // QCOMPARE(r->email(),QStringLiteral("test@kolab.org")); 0217 // QCOMPARE(r->comment(),QStringLiteral("no password")); 0218 auto attachmentList = otp.collectAttachmentParts(); 0219 QCOMPARE(attachmentList.size(), 2); 0220 auto attachment1 = attachmentList[0]; 0221 QVERIFY(attachment1->node()); 0222 QCOMPARE(attachment1->filename(), QStringLiteral("file.txt")); 0223 auto attachment2 = attachmentList[1]; 0224 QVERIFY(attachment2->node()); 0225 QCOMPARE(attachment2->filename(), QStringLiteral("image.png")); 0226 } 0227 0228 void testSignatureBlock() 0229 { 0230 MimeTreeParser::ObjectTreeParser otp; 0231 otp.parseObjectTree(readMailFromFile("openpgp-encrypted-attachment-and-non-encrypted-attachment.mbox")); 0232 otp.print(); 0233 otp.decryptParts(); 0234 otp.print(); 0235 auto partList = otp.collectContentParts(); 0236 QCOMPARE(partList.size(), 1); 0237 auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0238 QVERIFY(bool(part)); 0239 0240 // QCOMPARE(contentList[0]->signatures().size(), 1); 0241 // auto sig = contentList[0]->signatures()[0]; 0242 // QCOMPARE(sig->creationDateTime(), QDateTime(QDate(2015,05,01),QTime(15,12,47))); 0243 // QCOMPARE(sig->expirationDateTime(), QDateTime()); 0244 // QCOMPARE(sig->neverExpires(), true); 0245 0246 // auto key = sig->key(); 0247 // QCOMPARE(key->keyid(),QStringLiteral("8D9860C58F246DE6")); 0248 // QCOMPARE(key->name(),QStringLiteral("unittest key")); 0249 // QCOMPARE(key->email(),QStringLiteral("test@kolab.org")); 0250 // QCOMPARE(key->comment(),QStringLiteral("no password")); 0251 } 0252 0253 void testRelatedAlternative() 0254 { 0255 MimeTreeParser::ObjectTreeParser otp; 0256 otp.parseObjectTree(readMailFromFile("cid-links.mbox")); 0257 otp.print(); 0258 auto partList = otp.collectContentParts(); 0259 QCOMPARE(partList.size(), 1); 0260 auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0261 QVERIFY(bool(part)); 0262 QCOMPARE(part->encryptions().size(), 0); 0263 QCOMPARE(part->signatures().size(), 0); 0264 QCOMPARE(otp.collectAttachmentParts().size(), 1); 0265 } 0266 0267 void testAttachmentPart() 0268 { 0269 MimeTreeParser::ObjectTreeParser otp; 0270 otp.parseObjectTree(readMailFromFile("attachment.mbox")); 0271 otp.print(); 0272 auto partList = otp.collectAttachmentParts(); 0273 QCOMPARE(partList.size(), 1); 0274 auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0275 QVERIFY(bool(part)); 0276 QCOMPARE(part->mimeType(), QByteArray("image/jpeg")); 0277 QCOMPARE(part->filename(), QByteArray("aqnaozisxya.jpeg")); 0278 } 0279 0280 0281 void testAttachment2Part() 0282 { 0283 MimeTreeParser::ObjectTreeParser otp; 0284 otp.parseObjectTree(readMailFromFile("attachment2.mbox")); 0285 otp.print(); 0286 auto partList = otp.collectAttachmentParts(); 0287 QCOMPARE(partList.size(), 1); 0288 auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0289 QVERIFY(bool(part)); 0290 QCOMPARE(part->mimeType(), QByteArray("image/jpeg")); 0291 QCOMPARE(part->filename(), QByteArray("aqnaozisxya.jpeg")); 0292 } 0293 0294 void testCidLink() 0295 { 0296 MimeTreeParser::ObjectTreeParser otp; 0297 otp.parseObjectTree(readMailFromFile("cid-links.mbox")); 0298 otp.print(); 0299 auto partList = otp.collectContentParts(); 0300 QCOMPARE(partList.size(), 1); 0301 auto part = partList[0].dynamicCast<MimeTreeParser::AlternativeMessagePart>(); 0302 QVERIFY(bool(part)); 0303 auto resolvedContent = otp.resolveCidLinks(part->htmlContent()); 0304 QVERIFY(!resolvedContent.contains("cid:")); 0305 } 0306 0307 void testCidLinkInForwardedInline() 0308 { 0309 MimeTreeParser::ObjectTreeParser otp; 0310 otp.parseObjectTree(readMailFromFile("cid-links-forwarded-inline.mbox")); 0311 otp.print(); 0312 auto partList = otp.collectContentParts(); 0313 QCOMPARE(partList.size(), 1); 0314 auto part = partList[0].dynamicCast<MimeTreeParser::AlternativeMessagePart>(); 0315 QVERIFY(bool(part)); 0316 auto resolvedContent = otp.resolveCidLinks(part->htmlContent()); 0317 QVERIFY(!resolvedContent.contains("cid:")); 0318 } 0319 0320 void testOpenPGPInlineError() 0321 { 0322 MimeTreeParser::ObjectTreeParser otp; 0323 otp.parseObjectTree(readMailFromFile("inlinepgpgencrypted-error.mbox")); 0324 otp.print(); 0325 otp.decryptParts(); 0326 otp.print(); 0327 auto partList = otp.collectContentParts(); 0328 QCOMPARE(partList.size(), 1); 0329 auto part = partList[0].dynamicCast<MimeTreeParser::EncryptedMessagePart>(); 0330 QVERIFY(bool(part)); 0331 QVERIFY(part->error()); 0332 } 0333 0334 void testEncapsulated() 0335 { 0336 MimeTreeParser::ObjectTreeParser otp; 0337 otp.parseObjectTree(readMailFromFile("encapsulated-with-attachment.mbox")); 0338 otp.decryptParts(); 0339 auto partList = otp.collectContentParts(); 0340 QCOMPARE(partList.size(), 2); 0341 auto part = partList[1].dynamicCast<MimeTreeParser::EncapsulatedRfc822MessagePart>(); 0342 QVERIFY(bool(part)); 0343 QCOMPARE(part->from(), QLatin1String("Thomas McGuire <dontspamme@gmx.net>")); 0344 QCOMPARE(part->date().toString(), QLatin1String("Wed Aug 5 10:57:58 2009 GMT+0200")); 0345 auto subPartList = otp.collectContentParts(part); 0346 QCOMPARE(subPartList.size(), 1); 0347 qWarning() << subPartList[0]->metaObject()->className(); 0348 auto subPart = subPartList[0].dynamicCast<MimeTreeParser::TextMessagePart>(); 0349 QVERIFY(bool(subPart)); 0350 } 0351 0352 void test8bitEncodedInPlaintext() 0353 { 0354 MimeTreeParser::ObjectTreeParser otp; 0355 otp.parseObjectTree(readMailFromFile("8bitencoded.mbox")); 0356 QVERIFY(otp.plainTextContent().contains(QString::fromUtf8("Why Pisa’s Tower"))); 0357 QVERIFY(otp.htmlContent().contains(QString::fromUtf8("Why Pisa’s Tower"))); 0358 } 0359 0360 void testInlineSigned() 0361 { 0362 MimeTreeParser::ObjectTreeParser otp; 0363 otp.parseObjectTree(readMailFromFile("openpgp-inline-signed.mbox")); 0364 otp.decryptParts(); 0365 auto partList = otp.collectContentParts(); 0366 QCOMPARE(partList.size(), 1); 0367 auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0368 QCOMPARE(part->signatures().size(), 1); 0369 QCOMPARE(part->encryptionState(), MimeTreeParser::KMMsgNotEncrypted); 0370 QCOMPARE(part->signatureState(), MimeTreeParser::KMMsgFullySigned); 0371 QCOMPARE(part->text(), QString::fromUtf8("ohno öäü\n")); 0372 0373 QVERIFY(otp.plainTextContent().contains(QString::fromUtf8("ohno öäü"))); 0374 0375 auto signaturePart = part->signatures().first(); 0376 QCOMPARE(signaturePart->partMetaData()->isGoodSignature, true); 0377 QCOMPARE(signaturePart->partMetaData()->keyIsTrusted, true); 0378 QCOMPARE(signaturePart->partMetaData()->keyMissing, false); 0379 QCOMPARE(signaturePart->partMetaData()->keyExpired, false); 0380 QCOMPARE(signaturePart->partMetaData()->keyRevoked, false); 0381 QCOMPARE(signaturePart->partMetaData()->sigExpired, false); 0382 QCOMPARE(signaturePart->partMetaData()->crlMissing, false); 0383 QCOMPARE(signaturePart->partMetaData()->crlTooOld, false); 0384 QCOMPARE(signaturePart->partMetaData()->keyId, QByteArray{"8D9860C58F246DE6"}); 0385 QCOMPARE(signaturePart->partMetaData()->signer, QLatin1String{"unittest key (no password) <test@kolab.org>"}); 0386 QCOMPARE(signaturePart->partMetaData()->signerMailAddresses, QStringList{{"test@kolab.org"}}); 0387 } 0388 0389 void testEncryptedAndSigned() 0390 { 0391 MimeTreeParser::ObjectTreeParser otp; 0392 otp.parseObjectTree(readMailFromFile("openpgp-encrypted+signed.mbox")); 0393 otp.decryptParts(); 0394 auto partList = otp.collectContentParts(); 0395 QCOMPARE(partList.size(), 1); 0396 auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0397 QCOMPARE(part->signatures().size(), 1); 0398 QCOMPARE(part->encryptions().size(), 1); 0399 QCOMPARE(part->encryptionState(), MimeTreeParser::KMMsgFullyEncrypted); 0400 QCOMPARE(part->signatureState(), MimeTreeParser::KMMsgFullySigned); 0401 QVERIFY(otp.plainTextContent().contains(QString::fromUtf8("encrypted message text"))); 0402 0403 auto signaturePart = part->signatures().first(); 0404 QCOMPARE(signaturePart->partMetaData()->keyId, QByteArray{"8D9860C58F246DE6"}); 0405 QCOMPARE(signaturePart->partMetaData()->isGoodSignature, true); 0406 } 0407 0408 void testOpenpgpMultipartEmbedded() 0409 { 0410 MimeTreeParser::ObjectTreeParser otp; 0411 otp.parseObjectTree(readMailFromFile("openpgp-multipart-embedded.mbox")); 0412 otp.print(); 0413 otp.decryptParts(); 0414 otp.print(); 0415 auto partList = otp.collectContentParts(); 0416 QCOMPARE(partList.size(), 1); 0417 auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0418 QCOMPARE(part->encryptions().size(), 1); 0419 QCOMPARE(part->encryptionState(), MimeTreeParser::KMMsgFullyEncrypted); 0420 QCOMPARE(otp.plainTextContent(), QString::fromUtf8("sdflskjsdf\n\n-- \nThis is a HTML signature.\n")); 0421 } 0422 0423 void testOpenpgpMultipartEmbeddedSigned() 0424 { 0425 MimeTreeParser::ObjectTreeParser otp; 0426 otp.parseObjectTree(readMailFromFile("openpgp-multipart-embedded-signed.mbox")); 0427 otp.decryptParts(); 0428 auto partList = otp.collectContentParts(); 0429 QCOMPARE(partList.size(), 1); 0430 auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0431 QCOMPARE(part->encryptions().size(), 1); 0432 QCOMPARE(part->signatures().size(), 1); 0433 QCOMPARE(part->encryptionState(), MimeTreeParser::KMMsgFullyEncrypted); 0434 QCOMPARE(part->signatureState(), MimeTreeParser::KMMsgFullySigned); 0435 QCOMPARE(otp.plainTextContent(), QString::fromUtf8("test\n\n-- \nThis is a HTML signature.\n")); 0436 0437 auto signaturePart = part->signatures().first(); 0438 QVERIFY(signaturePart->partMetaData()->keyId.endsWith(QByteArray{"2E3B7787B1B75920"})); 0439 //We lack the public key for this message 0440 QCOMPARE(signaturePart->partMetaData()->isGoodSignature, false); 0441 QCOMPARE(signaturePart->partMetaData()->keyMissing, true); 0442 } 0443 0444 void testAppleHtmlWithAttachments() 0445 { 0446 MimeTreeParser::ObjectTreeParser otp; 0447 otp.parseObjectTree(readMailFromFile("applehtmlwithattachments.mbox")); 0448 otp.decryptParts(); 0449 auto partList = otp.collectContentParts(); 0450 QCOMPARE(partList.size(), 1); 0451 auto part = partList[0].dynamicCast<MimeTreeParser::AlternativeMessagePart>(); 0452 QVERIFY(part); 0453 QCOMPARE(part->encryptions().size(), 0); 0454 QCOMPARE(part->signatures().size(), 0); 0455 QVERIFY(part->isHtml()); 0456 QCOMPARE(otp.plainTextContent(), QString::fromUtf8("Hi,\n\nThis is an HTML message with attachments.\n\nCheers,\nChristian")); 0457 QCOMPARE(otp.htmlContent(), QString::fromUtf8("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=us-ascii\"></head><body style=\"word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;\" class=\"\"><meta http-equiv=\"Content-Type\" content=\"text/html; charset=us-ascii\" class=\"\"><div style=\"word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;\" class=\"\">Hi,<div class=\"\"><br class=\"\"></div><blockquote style=\"margin: 0 0 0 40px; border: none; padding: 0px;\" class=\"\"><div class=\"\">This is an <b class=\"\">HTML</b> message with attachments.</div></blockquote><div class=\"\"><br class=\"\"></div><div class=\"\">Cheers,</div><div class=\"\">Christian<img apple-inline=\"yes\" id=\"B9EE68A9-83CA-41CD-A3E4-E5BA301F797A\" class=\"\" src=\"cid:F5B62D1D-E4EC-4C59-AA5A-708525C2AC3C\"></div></div></body></html>")); 0458 0459 auto attachments = otp.collectAttachmentParts(); 0460 QCOMPARE(attachments.size(), 1); 0461 } 0462 0463 void testAppleHtmlWithAttachmentsMixed() 0464 { 0465 MimeTreeParser::ObjectTreeParser otp; 0466 otp.parseObjectTree(readMailFromFile("applehtmlwithattachmentsmixed.mbox")); 0467 otp.decryptParts(); 0468 otp.print(); 0469 auto partList = otp.collectContentParts(); 0470 QCOMPARE(partList.size(), 1); 0471 auto part = partList[0].dynamicCast<MimeTreeParser::AlternativeMessagePart>(); 0472 QVERIFY(part); 0473 QCOMPARE(part->encryptions().size(), 0); 0474 QCOMPARE(part->signatures().size(), 0); 0475 QVERIFY(part->isHtml()); 0476 QCOMPARE(otp.plainTextContent(), QString::fromUtf8("Hello\n\n\n\nRegards\n\nFsdfsdf")); 0477 QCOMPARE(otp.htmlContent(), QString::fromUtf8("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=us-ascii\"></head><body style=\"word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;\" class=\"\"><strike class=\"\">Hello</strike><div class=\"\"><br class=\"\"></div><div class=\"\"></div></body></html><html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=us-ascii\"></head><body style=\"word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;\" class=\"\"><div class=\"\"></div><div class=\"\"><br class=\"\"></div><div class=\"\"><b class=\"\">Regards</b></div><div class=\"\"><b class=\"\"><br class=\"\"></b></div><div class=\"\">Fsdfsdf</div></body></html>")); 0478 0479 auto attachments = otp.collectAttachmentParts(); 0480 QCOMPARE(attachments.size(), 1); 0481 } 0482 0483 void testInvitation() 0484 { 0485 MimeTreeParser::ObjectTreeParser otp; 0486 otp.parseObjectTree(readMailFromFile("invitation.mbox")); 0487 otp.decryptParts(); 0488 otp.print(); 0489 auto partList = otp.collectContentParts(); 0490 QCOMPARE(partList.size(), 1); 0491 auto part = partList[0].dynamicCast<MimeTreeParser::AlternativeMessagePart>(); 0492 QVERIFY(part); 0493 QCOMPARE(part->encryptions().size(), 0); 0494 QCOMPARE(part->signatures().size(), 0); 0495 QVERIFY(!part->isHtml()); 0496 QVERIFY(part->availableModes().contains(MimeTreeParser::AlternativeMessagePart::MultipartIcal)); 0497 0498 auto attachments = otp.collectAttachmentParts(); 0499 QCOMPARE(attachments.size(), 0); 0500 } 0501 0502 void testGmailInvitation() 0503 { 0504 MimeTreeParser::ObjectTreeParser otp; 0505 otp.parseObjectTree(readMailFromFile("gmail-invitation.mbox")); 0506 otp.decryptParts(); 0507 otp.print(); 0508 auto partList = otp.collectContentParts(); 0509 QCOMPARE(partList.size(), 1); 0510 auto part = partList[0].dynamicCast<MimeTreeParser::AlternativeMessagePart>(); 0511 QVERIFY(part); 0512 QCOMPARE(part->encryptions().size(), 0); 0513 QCOMPARE(part->signatures().size(), 0); 0514 QVERIFY(part->isHtml()); 0515 QVERIFY(part->availableModes().contains(MimeTreeParser::AlternativeMessagePart::MultipartIcal)); 0516 0517 auto attachments = otp.collectAttachmentParts(); 0518 QCOMPARE(attachments.size(), 1); 0519 } 0520 0521 void testMemoryHole() 0522 { 0523 MimeTreeParser::ObjectTreeParser otp; 0524 otp.parseObjectTree(readMailFromFile("openpgp-encrypted-memoryhole.mbox")); 0525 otp.decryptParts(); 0526 otp.print(); 0527 0528 auto partList = otp.collectContentParts(); 0529 QCOMPARE(partList.size(), 1); 0530 auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0531 QVERIFY(bool(part)); 0532 0533 QCOMPARE(part->text(), QStringLiteral("very secret mesage\n")); 0534 0535 QCOMPARE(part->header("subject")->asUnicodeString(), QStringLiteral("hidden subject")); 0536 QCOMPARE(part->header("from")->asUnicodeString(), QStringLiteral("you@example.com")); 0537 QCOMPARE(part->header("to")->asUnicodeString(), QStringLiteral("me@example.com")); 0538 QCOMPARE(part->header("cc")->asUnicodeString(), QStringLiteral("cc@example.com")); 0539 QCOMPARE(part->header("message-id")->asUnicodeString(), QStringLiteral("<myhiddenreference@me>")); 0540 QCOMPARE(part->header("references")->asUnicodeString(), QStringLiteral("<hiddenreference@hidden>")); 0541 QCOMPARE(part->header("in-reply-to")->asUnicodeString(), QStringLiteral("<hiddenreference@hidden>")); 0542 QCOMPARE(static_cast<const KMime::Headers::Date *>(part->header("date"))->dateTime(), QDateTime(QDate(2018, 1, 2), QTime(3,4,5), QTimeZone::utc())); 0543 } 0544 0545 /** 0546 * Required special handling because the list replaces the toplevel part. 0547 */ 0548 void testMemoryHoleWithList() 0549 { 0550 MimeTreeParser::ObjectTreeParser otp; 0551 otp.parseObjectTree(readMailFromFile("cid-links-forwarded-inline.mbox")); 0552 auto part = otp.collectContentParts()[0]; 0553 QVERIFY(part->header("references")); 0554 QCOMPARE(part->header("references")->asUnicodeString(), QStringLiteral("<a1777ec781546ccc5dcd4918a5e4e03d@info>")); 0555 } 0556 0557 void testMemoryHoleMultipartMixed() 0558 { 0559 MimeTreeParser::ObjectTreeParser otp; 0560 otp.parseObjectTree(readMailFromFile("openpgp-encrypted-memoryhole2.mbox")); 0561 otp.decryptParts(); 0562 otp.print(); 0563 0564 auto partList = otp.collectContentParts(); 0565 QCOMPARE(partList.size(), 1); 0566 auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0567 QVERIFY(bool(part)); 0568 0569 QCOMPARE(part->text(), QStringLiteral("\n\n Fsdflkjdslfj\n\n\nHappy Monday!\n\nBelow you will find a quick overview of the current on-goings. Remember\n")); 0570 0571 QCOMPARE(part->header("subject")->asUnicodeString(), QStringLiteral("This is the subject")); 0572 } 0573 0574 void testMIMESignature() 0575 { 0576 MimeTreeParser::ObjectTreeParser otp; 0577 otp.parseObjectTree(readMailFromFile("text+html-maillinglist.mbox")); 0578 otp.decryptParts(); 0579 otp.print(); 0580 0581 auto partList = otp.collectContentParts(); 0582 for (const auto &part : partList) { 0583 qWarning() << "found part " << part->metaObject()->className(); 0584 } 0585 QCOMPARE(partList.size(), 2); 0586 //The actual content 0587 { 0588 auto part = partList[0].dynamicCast<MimeTreeParser::AlternativeMessagePart>(); 0589 QVERIFY(bool(part)); 0590 } 0591 0592 //The signature 0593 { 0594 auto part = partList[1].dynamicCast<MimeTreeParser::TextMessagePart>(); 0595 QVERIFY(bool(part)); 0596 QVERIFY(part->text().contains(QStringLiteral("bugzilla mailing list"))); 0597 } 0598 } 0599 0600 void testCRLFEncryptedWithSignature() 0601 { 0602 MimeTreeParser::ObjectTreeParser otp; 0603 otp.parseObjectTree(readMailFromFile("crlf-encrypted-with-signature.mbox")); 0604 otp.decryptParts(); 0605 otp.print(); 0606 0607 QCOMPARE(otp.plainTextContent(), "CRLF file\n\n-- \nThis is a signature\nWith two lines\n\nAand another line\n"); 0608 } 0609 0610 void testCRLFEncryptedWithSignatureMultipart() 0611 { 0612 MimeTreeParser::ObjectTreeParser otp; 0613 otp.parseObjectTree(readMailFromFile("crlf-encrypted-with-signature-multipart.mbox")); 0614 otp.decryptParts(); 0615 otp.print(); 0616 0617 QEXPECT_FAIL("", "because MessagePart::parseInternal uses \n\n to detect encapsulated messages (so 'CRLF file' ends up as header)", Continue); 0618 QCOMPARE(otp.plainTextContent(), "CRLF file\n\n-- \nThis is a signature\nWith two lines\n\nAand another line\n"); 0619 QVERIFY(!otp.htmlContent().contains("\r\n")); 0620 } 0621 0622 void testCRLFOutlook() 0623 { 0624 MimeTreeParser::ObjectTreeParser otp; 0625 otp.parseObjectTree(readMailFromFile("outlook.mbox")); 0626 otp.decryptParts(); 0627 otp.print(); 0628 0629 qWarning() << otp.plainTextContent(); 0630 QVERIFY(otp.plainTextContent().startsWith("Hi Christian,\n\nhabs gerade getestet:\n\n\u00ABThis is a test")); 0631 QVERIFY(!otp.htmlContent().contains("\r\n")); 0632 } 0633 0634 void testOpenPGPEncryptedSignedThunderbird() 0635 { 0636 MimeTreeParser::ObjectTreeParser otp; 0637 otp.parseObjectTree(readMailFromFile("openpgp-encrypted-signed-thunderbird.mbox")); 0638 otp.print(); 0639 otp.decryptParts(); 0640 otp.print(); 0641 auto partList = otp.collectContentParts(); 0642 QCOMPARE(partList.size(), 1); 0643 auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0644 QVERIFY(bool(part)); 0645 QCOMPARE(part->text(), QStringLiteral("sdfsdf\n")); 0646 QCOMPARE(part->charset(), QStringLiteral("utf-8").toLocal8Bit()); 0647 QCOMPARE(part->encryptions().size(), 1); 0648 QCOMPARE(part->signatures().size(), 1); 0649 QCOMPARE(part->signatures()[0]->partMetaData()->isGoodSignature, true); 0650 QCOMPARE(part->encryptionState(), MimeTreeParser::KMMsgFullyEncrypted); 0651 QCOMPARE(part->signatureState(), MimeTreeParser::KMMsgFullySigned); 0652 auto contentAttachmentList = otp.collectAttachmentParts(); 0653 QCOMPARE(contentAttachmentList.size(), 1); 0654 // QCOMPARE(contentAttachmentList[0]->content().size(), 1); 0655 QCOMPARE(contentAttachmentList[0]->encryptions().size(), 1); 0656 QCOMPARE(contentAttachmentList[0]->signatures().size(), 1); 0657 QCOMPARE(contentAttachmentList[0]->encryptionState(), MimeTreeParser::KMMsgFullyEncrypted); 0658 QCOMPARE(contentAttachmentList[0]->signatureState(), MimeTreeParser::KMMsgFullySigned); 0659 } 0660 0661 void testSignedForwardOpenpgpSignedEncrypted() 0662 { 0663 MimeTreeParser::ObjectTreeParser otp; 0664 otp.parseObjectTree(readMailFromFile("signed-forward-openpgp-signed-encrypted.mbox")); 0665 otp.print(); 0666 otp.decryptParts(); 0667 otp.print(); 0668 auto partList = otp.collectContentParts(); 0669 QCOMPARE(partList.size(), 2); 0670 auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0671 QVERIFY(bool(part)); 0672 QCOMPARE(part->text(), QStringLiteral("bla bla bla")); 0673 0674 part = partList[1].dynamicCast<MimeTreeParser::MessagePart>(); 0675 QVERIFY(bool(part)); 0676 QCOMPARE(part->text(), QStringLiteral("")); 0677 QCOMPARE(part->charset(), QStringLiteral("ISO-8859-1").toLocal8Bit()); 0678 QCOMPARE(part->signatures().size(), 1); 0679 QCOMPARE(part->signatures()[0]->partMetaData()->isGoodSignature, true); 0680 auto contentAttachmentList = otp.collectAttachmentParts(); 0681 QCOMPARE(contentAttachmentList.size(), 1); 0682 } 0683 0684 void testSmimeOpaqueSign() 0685 { 0686 MimeTreeParser::ObjectTreeParser otp; 0687 otp.parseObjectTree(readMailFromFile("smime-opaque-sign.mbox")); 0688 otp.print(); 0689 otp.decryptParts(); 0690 otp.print(); 0691 auto partList = otp.collectContentParts(); 0692 QCOMPARE(partList.size(), 1); 0693 auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0694 QVERIFY(bool(part)); 0695 QCOMPARE(part->text(), QStringLiteral("A simple signed only test.")); 0696 } 0697 0698 void testSmimeEncrypted() 0699 { 0700 MimeTreeParser::ObjectTreeParser otp; 0701 otp.parseObjectTree(readMailFromFile("smime-encrypted.mbox")); 0702 otp.print(); 0703 otp.decryptParts(); 0704 otp.print(); 0705 auto partList = otp.collectContentParts(); 0706 QCOMPARE(partList.size(), 1); 0707 auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0708 QVERIFY(bool(part)); 0709 QCOMPARE(part->text(), QStringLiteral("The quick brown fox jumped over the lazy dog.")); 0710 } 0711 0712 void testSmimeSignedApple() 0713 { 0714 MimeTreeParser::ObjectTreeParser otp; 0715 otp.parseObjectTree(readMailFromFile("smime-signed-apple.mbox")); 0716 otp.print(); 0717 otp.decryptParts(); 0718 otp.print(); 0719 auto partList = otp.collectContentParts(); 0720 QCOMPARE(partList.size(), 1); 0721 auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0722 QVERIFY(bool(part)); 0723 // QCOMPARE(part->text(), QStringLiteral("A simple signed only test.")); 0724 } 0725 0726 void testSmimeEncryptedOctetStream() 0727 { 0728 MimeTreeParser::ObjectTreeParser otp; 0729 otp.parseObjectTree(readMailFromFile("smime-encrypted-octet-stream.mbox")); 0730 otp.print(); 0731 otp.decryptParts(); 0732 otp.print(); 0733 auto partList = otp.collectContentParts(); 0734 QCOMPARE(partList.size(), 1); 0735 auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0736 QVERIFY(bool(part)); 0737 QCOMPARE(part->text(), QStringLiteral("The quick brown fox jumped over the lazy dog.")); 0738 } 0739 0740 void testSmimeOpaqueSignedEncryptedAttachment() 0741 { 0742 MimeTreeParser::ObjectTreeParser otp; 0743 otp.parseObjectTree(readMailFromFile("smime-opaque-signed-encrypted-attachment.mbox")); 0744 otp.print(); 0745 otp.decryptParts(); 0746 otp.print(); 0747 auto partList = otp.collectContentParts(); 0748 QCOMPARE(partList.size(), 1); 0749 auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0750 QVERIFY(bool(part)); 0751 QCOMPARE(part->text(), QStringLiteral("This is an Opaque S/MIME encrypted and signed message with attachment")); 0752 } 0753 0754 void testSmimeOpaqueEncSign() 0755 { 0756 MimeTreeParser::ObjectTreeParser otp; 0757 otp.parseObjectTree(readMailFromFile("smime-opaque-enc+sign.mbox")); 0758 otp.print(); 0759 otp.decryptParts(); 0760 otp.print(); 0761 auto partList = otp.collectContentParts(); 0762 QCOMPARE(partList.size(), 1); 0763 auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>(); 0764 QVERIFY(bool(part)); 0765 QCOMPARE(part->text(), QStringLiteral("Encrypted and signed mail.")); 0766 } 0767 0768 }; 0769 0770 QTEST_GUILESS_MAIN(MimeTreeParserTest) 0771 #include "mimetreeparsertest.moc"