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