File indexing completed on 2024-04-21 05:18:09
0001 /* 0002 SPDX-FileCopyrightText: 2007 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "messagetest.h" 0008 #include <QTest> 0009 #include <QDebug> 0010 #include <QFile> 0011 #include <kmime_codecs.cpp> 0012 0013 using namespace KMime; 0014 0015 QTEST_MAIN(MessageTest) 0016 0017 void MessageTest::testMainBodyPart() 0018 { 0019 auto msg = new Message(); 0020 auto msg2 = new Message(); 0021 auto text = new Content(); 0022 text->contentType()->setMimeType("text/plain"); 0023 auto html = new Content(); 0024 html->contentType()->setMimeType("text/html"); 0025 0026 // empty message 0027 QCOMPARE(msg->mainBodyPart(), msg); 0028 QCOMPARE(msg->mainBodyPart("text/plain"), (Content *)nullptr); 0029 0030 // non-multipart 0031 msg->contentType()->setMimeType("text/html"); 0032 0033 QCOMPARE(msg->mainBodyPart(), msg); 0034 QCOMPARE(msg->mainBodyPart("text/plain"), (Content *)nullptr); 0035 QCOMPARE(msg->mainBodyPart("text/html"), msg); 0036 0037 // multipart/mixed 0038 msg2->contentType()->setMimeType("multipart/mixed"); 0039 msg2->appendContent(text); 0040 msg2->appendContent(html); 0041 0042 QCOMPARE(msg2->mainBodyPart(), text); 0043 QCOMPARE(msg2->mainBodyPart("text/plain"), text); 0044 QCOMPARE(msg2->mainBodyPart("text/html"), (Content *)nullptr); 0045 0046 // Careful with removing content here. If we remove one of the two contents 0047 // (by adding it to another message), the multipart will automatically be 0048 // converted to a single-part, deleting the other content! 0049 msg2->clearContents(false); 0050 0051 // multipart/alternative 0052 msg->contentType()->setMimeType("multipart/alternative"); 0053 msg->appendContent(html); 0054 msg->appendContent(text); 0055 0056 QCOMPARE(msg->mainBodyPart(), html); 0057 QCOMPARE(msg->mainBodyPart("text/plain"), text); 0058 QCOMPARE(msg->mainBodyPart("text/html"), html); 0059 0060 // multipart/alternative inside multipart/mixed 0061 auto msg3 = new Message(); 0062 msg3->contentType()->setMimeType("multipart/mixed"); 0063 msg3->appendContent(msg); 0064 auto attach = new Content(); 0065 attach->contentType()->setMimeType("text/plain"); 0066 0067 QCOMPARE(msg3->mainBodyPart(), html); 0068 QCOMPARE(msg3->mainBodyPart("text/plain"), text); 0069 QCOMPARE(msg3->mainBodyPart("text/html"), html); 0070 0071 delete msg2; 0072 delete msg3; 0073 delete attach; 0074 } 0075 0076 void MessageTest::testBrunosMultiAssembleBug() 0077 { 0078 QByteArray data = 0079 "From: Sender <sender@test.org>\n" 0080 "Subject: Sample message\n" 0081 "To: Receiver <receiver@test.org>\n" 0082 "Date: Sat, 04 Aug 2007 12:44:00 +0200\n" 0083 "MIME-Version: 1.0\n" 0084 "Content-Type: text/plain\n" 0085 "X-Foo: bla\n" 0086 "X-Bla: foo\n" 0087 "\n" 0088 "body"; 0089 0090 auto msg = new Message; 0091 msg->setContent(data); 0092 msg->parse(); 0093 msg->assemble(); 0094 QCOMPARE(msg->encodedContent(), data); 0095 0096 msg->inReplyTo(); 0097 msg->assemble(); 0098 QCOMPARE(msg->encodedContent(), data); 0099 0100 delete msg; 0101 } 0102 0103 void MessageTest::testWillsAndTillsCrash() 0104 { 0105 QByteArray deadlyMail = "From: censored@yahoogroups.com\n" 0106 "To: censored@yahoogroups.com\n" 0107 "Sender: censored@yahoogroups.com\n" 0108 "MIME-Version: 1.0\n" 0109 "Date: 29 Jan 2006 23:58:21 -0000\n" 0110 "Subject: [censored] Birthday Reminder\n" 0111 "Reply-To: censored@yahoogroups.com\n" 0112 "Content-Type: multipart/alternative;\n boundary=\"YCalReminder=cNM4SNTGA4Cg1MVLaPpqNF1138579098\"\n" 0113 "X-Length: 9594\n" 0114 "X-UID: 6161\n" 0115 "Status: RO\n" 0116 "X-Status: OC\n" 0117 "X-KMail-EncryptionState:\n" 0118 "X-KMail-SignatureState:\n" 0119 "X-KMail-MDN-Sent:\n\n"; 0120 0121 auto msg = new KMime::Message; 0122 msg->setContent(deadlyMail); 0123 msg->parse(); 0124 QVERIFY(!msg->date()->isEmpty()); 0125 QCOMPARE(msg->subject()->as7BitString(false), QByteArray("[censored] Birthday Reminder")); 0126 QCOMPARE(msg->from()->mailboxes().count(), 1); 0127 QCOMPARE(msg->sender()->mailboxes().count(), 1); 0128 QCOMPARE(msg->replyTo()->mailboxes().count(), 1); 0129 QCOMPARE(msg->to()->mailboxes().count(), 1); 0130 QCOMPARE(msg->cc()->mailboxes().count(), 0); 0131 QCOMPARE(msg->bcc()->mailboxes().count(), 0); 0132 QCOMPARE(msg->inReplyTo()->identifiers().count(), 0); 0133 QCOMPARE(msg->messageID()->identifiers().count(), 0); 0134 delete msg; 0135 } 0136 0137 void MessageTest::testDavidsParseCrash() 0138 { 0139 KMime::Message::Ptr mail = readAndParseMail(QStringLiteral("dfaure-crash.mbox")); 0140 QCOMPARE(mail->to()->asUnicodeString().toLatin1().data(), "frank@domain.com"); 0141 } 0142 0143 void MessageTest::testHeaderFieldWithoutSpace() 0144 { 0145 // Headers without a space, like the CC header here, are allowed according to 0146 // the examples in RFC2822, Appendix A5 0147 const QString mail = QStringLiteral("From:\n" 0148 "To: heinz@test.de\n" 0149 "Cc:moritz@test.de\n" 0150 "Subject: Test\n" 0151 "X-Mailer:"); 0152 KMime::Message msg; 0153 msg.setContent(mail.toLatin1()); 0154 msg.parse(); 0155 0156 QCOMPARE(msg.to()->asUnicodeString(), QLatin1StringView("heinz@test.de")); 0157 QCOMPARE(msg.from()->asUnicodeString(), QString()); 0158 QCOMPARE(msg.cc()->asUnicodeString(), QLatin1StringView("moritz@test.de")); 0159 QCOMPARE(msg.subject()->asUnicodeString(), QLatin1StringView("Test")); 0160 QVERIFY(msg.hasHeader("X-Mailer")); 0161 QVERIFY(msg.headerByType("X-Mailer")->asUnicodeString().isEmpty()); 0162 } 0163 0164 void MessageTest::testWronglyFoldedHeaders() 0165 { 0166 // The first subject line here doesn't contain anything. This is invalid, 0167 // however there are some mailers out there that produce those messages. 0168 const QString mail = QStringLiteral("Subject:\n" 0169 " Hello\n" 0170 " World\n" 0171 "To: \n" 0172 " test@test.de\n\n" 0173 "<Body>"); 0174 KMime::Message msg; 0175 msg.setContent(mail.toLatin1()); 0176 msg.parse(); 0177 0178 QCOMPARE(msg.subject()->asUnicodeString(), 0179 QLatin1StringView("Hello World")); 0180 QCOMPARE(msg.body().data(), "<Body>"); 0181 QCOMPARE(msg.to()->asUnicodeString(), QLatin1StringView("test@test.de")); 0182 } 0183 0184 void MessageTest::missingHeadersTest() 0185 { 0186 // Test that the message body is OK even though some headers are missing 0187 KMime::Message msg; 0188 const QString body = QStringLiteral("Hi Donald, look at those nice pictures I found!\n"); 0189 const QString content = 0190 QLatin1StringView("From: georgebush@whitehouse.org\n" 0191 "To: donaldrumsfeld@whitehouse.org\n" 0192 "Subject: Cute Kittens\n" 0193 "\n") + 0194 body; 0195 msg.setContent(content.toLatin1()); 0196 msg.parse(); 0197 msg.assemble(); 0198 0199 QCOMPARE(body, QString::fromLatin1(msg.body())); 0200 0201 // Now create a new message, based on the content of the first one. 0202 // The body of the new message should still be the same. 0203 // (there was a bug that caused missing mandatory headers to be 0204 // added as a empty newline, which caused parts of the header to 0205 // leak into the body) 0206 KMime::Message msg2; 0207 msg2.setContent(msg.encodedContent()); 0208 msg2.parse(); 0209 msg2.assemble(); 0210 0211 QCOMPARE(body, QString::fromLatin1(msg2.body())); 0212 } 0213 0214 void MessageTest::testBug219749() 0215 { 0216 // Test that the message body is OK even though some headers are missing 0217 KMime::Message msg; 0218 const QString content = QStringLiteral( 0219 "Content-Type: MULTIPART/MIXED;\n" 0220 " BOUNDARY=\"0-1804289383-1260384639=:52580\"\n" 0221 "\n" 0222 "--0-1804289383-1260384639=:52580\n" 0223 "Content-Type: TEXT/plain; CHARSET=UTF-8\n" 0224 "\n" 0225 "--0-1804289383-1260384639=:52580\n" 0226 "Content-Type: APPLICATION/octet-stream\n" 0227 "Content-Transfer-Encoding: BASE64\n" 0228 "Content-ID: <jaselka1.docx4AECA1F9@9230725.3CDBB752>\n" 0229 "Content-Disposition: ATTACHMENT; FILENAME=\"jaselka 1.docx\"\n" 0230 "\n" 0231 "UEsDBBQABgAIAAAAIQDd/JU3ZgEAACAFAAATAAgCW0NvbnRlbnRfVHlwZXNd\n" 0232 "SUwAAAAA\n" 0233 "\n" 0234 "--0-1804289383-1260384639=:52580--\n"); 0235 0236 msg.setContent(content.toLatin1()); 0237 msg.parse(); 0238 0239 QCOMPARE(msg.contents().size(), 2); 0240 KMime::Content *attachment = msg.contents()[1]; 0241 QCOMPARE(attachment->contentType(false)->mediaType().data(), "application"); 0242 QCOMPARE(attachment->contentType(false)->subType().data(), "octet-stream"); 0243 QCOMPARE(attachment->contentID()->identifier().data(), "jaselka1.docx4AECA1F9@9230725.3CDBB752"); 0244 QCOMPARE(attachment->contentID()->as7BitString(false).data(), "<jaselka1.docx4AECA1F9@9230725.3CDBB752>"); 0245 Headers::ContentDisposition *cd = attachment->contentDisposition(false); 0246 QVERIFY(cd); 0247 QCOMPARE(cd->filename(), QLatin1StringView("jaselka 1.docx")); 0248 } 0249 0250 void MessageTest::testBidiSpoofing() 0251 { 0252 const QString RLO(QChar(0x202E)); 0253 //const QString PDF( QChar( 0x202C ) ); 0254 0255 const QByteArray senderAndRLO = 0256 encodeRFC2047String(QString(QLatin1StringView("Sender") + RLO + 0257 QLatin1StringView(" <sender@test.org>")), 0258 "utf-8"); 0259 0260 // The display name of the "From" has an RLO, make sure the KMime parser balances it 0261 QByteArray data = 0262 "From: " + senderAndRLO + "\n" 0263 "\n" 0264 "Body"; 0265 0266 KMime::Message msg; 0267 msg.setContent(data); 0268 msg.parse(); 0269 0270 // Test adjusted for taking into account that KMIME now removes bidi control chars 0271 // instead of adding PDF chars, because of broken KHTML. 0272 //const QString expectedDisplayName = "\"Sender" + RLO + PDF + "\""; 0273 const QString expectedDisplayName = QStringLiteral("Sender"); 0274 const QString expectedMailbox = 0275 expectedDisplayName + QLatin1StringView(" <sender@test.org>"); 0276 QCOMPARE(msg.from()->addresses().count(), 1); 0277 QCOMPARE(msg.from()->asUnicodeString(), expectedMailbox); 0278 QCOMPARE(msg.from()->displayNames().first(), expectedDisplayName); 0279 QCOMPARE(msg.from()->mailboxes().first().name(), expectedDisplayName); 0280 QCOMPARE(msg.from()->mailboxes().first().address().data(), "sender@test.org"); 0281 } 0282 0283 // Test to see if header fields of mails with an UTF-16 body are properly read 0284 // and written. 0285 // See also https://issues.kolab.org/issue3707 0286 void MessageTest::testUtf16() 0287 { 0288 QByteArray data = 0289 "From: foo@bar.com\n" 0290 "Subject: UTF-16 Test\n" 0291 "MIME-Version: 1.0\n" 0292 "Content-Type: Text/Plain;\n" 0293 " charset=\"utf-16\"\n" 0294 "Content-Transfer-Encoding: base64\n" 0295 "\n" 0296 "//5UAGgAaQBzACAAaQBzACAAVQBUAEYALQAxADYAIABUAGUAeAB0AC4ACgAKAAo"; 0297 0298 KMime::Message msg; 0299 msg.setContent(data); 0300 msg.parse(); 0301 0302 QCOMPARE(msg.from()->asUnicodeString(), QLatin1StringView("foo@bar.com")); 0303 QCOMPARE(msg.subject()->asUnicodeString(), 0304 QLatin1StringView("UTF-16 Test")); 0305 QCOMPARE(msg.decodedText(false, true), 0306 QLatin1StringView("This is UTF-16 Text.")); 0307 0308 // Add a new To header, for testings 0309 auto to = new KMime::Headers::To; 0310 KMime::Types::Mailbox address; 0311 address.setAddress("test@test.de"); 0312 address.setName(QStringLiteral("Fränz Töster")); 0313 to->addAddress(address); 0314 to->setRFC2047Charset("ISO-8859-1"); // default changed to UTF-8 in KF6, which is fine, but breaks the test 0315 msg.appendHeader(to); 0316 msg.assemble(); 0317 0318 QByteArray newData = 0319 "From: foo@bar.com\n" 0320 "Subject: UTF-16 Test\n" 0321 "MIME-Version: 1.0\n" 0322 "Content-Type: text/plain; charset=\"utf-16\"\n" 0323 "Content-Transfer-Encoding: base64\n" 0324 "To: =?ISO-8859-1?Q?Fr=E4nz_T=F6ster?= <test@test.de>\n" 0325 "\n" 0326 "//5UAGgAaQBzACAAaQBzACAAVQBUAEYALQAxADYAIABUAGUAeAB0AC4ACgAKAAo=\n" 0327 "\n"; 0328 0329 QCOMPARE(msg.encodedContent().data(), newData.data()); 0330 } 0331 0332 void MessageTest::testDecodedText() 0333 { 0334 QByteArray data = 0335 "Subject: Test\n" 0336 "\n" 0337 "Testing Whitespace \n \n \n\n\n"; 0338 0339 KMime::Message msg; 0340 msg.setContent(data); 0341 msg.parse(); 0342 0343 QCOMPARE(msg.decodedText(true, false), 0344 QLatin1StringView("Testing Whitespace")); 0345 QCOMPARE(msg.decodedText(true, true), 0346 QLatin1StringView("Testing Whitespace")); 0347 QCOMPARE(msg.decodedText(false, true), 0348 QLatin1StringView("Testing Whitespace \n \n ")); 0349 0350 QByteArray data2 = 0351 "Subject: Test\n" 0352 "\n" 0353 "Testing Whitespace \n \n \n\n\n "; 0354 0355 KMime::Message msg2; 0356 msg2.setContent(data2); 0357 msg2.parse(); 0358 0359 QCOMPARE(msg2.decodedText(true, false), 0360 QLatin1StringView("Testing Whitespace")); 0361 QCOMPARE(msg2.decodedText(true, true), 0362 QLatin1StringView("Testing Whitespace")); 0363 QCOMPARE(msg2.decodedText(false, true), 0364 QLatin1StringView("Testing Whitespace \n \n \n\n\n ")); 0365 } 0366 0367 void MessageTest::testInlineImages() 0368 { 0369 const QByteArray data = 0370 "From: <kde@kde.org>\n" 0371 "To: kde@kde.org\n" 0372 "Subject: Inline Image (unsigned)\n" 0373 "Date: Wed, 23 Dec 2009 14:00:59 +0100\n" 0374 "MIME-Version: 1.0\n" 0375 "Content-Type: multipart/related;\n" 0376 " boundary=\"Boundary-02=_LShMLJyjC7zqmVP\"\n" 0377 "Content-Transfer-Encoding: 7bit\n" 0378 "\n" 0379 "\n" 0380 "--Boundary-02=_LShMLJyjC7zqmVP\n" 0381 "Content-Type: multipart/alternative;\n" 0382 " boundary=\"Boundary-01=_LShMLzAUPqE38S8\"\n" 0383 "Content-Transfer-Encoding: 7bit\n" 0384 "Content-Disposition: inline\n" 0385 "\n" 0386 "--Boundary-01=_LShMLzAUPqE38S8\n" 0387 "Content-Type: text/plain;\n" 0388 " charset=\"us-ascii\"\n" 0389 "Content-Transfer-Encoding: 7bit\n" 0390 "\n" 0391 "First line\n" 0392 "\n" 0393 "\n" 0394 "Image above\n" 0395 "\n" 0396 "Last line\n" 0397 "\n" 0398 "--Boundary-01=_LShMLzAUPqE38S8\n" 0399 "Content-Type: text/html;\n" 0400 " charset=\"us-ascii\"\n" 0401 "Content-Transfer-Encoding: 7bit\n" 0402 "\n" 0403 "Line 1\n" 0404 "--Boundary-01=_LShMLzAUPqE38S8--\n" 0405 "\n" 0406 "--Boundary-02=_LShMLJyjC7zqmVP\n" 0407 "Content-Type: image/png;\n" 0408 " name=\"inlineimage.png\"\n" 0409 "Content-Transfer-Encoding: base64\n" 0410 "Content-Id: <740439759>\n" 0411 "\n" 0412 "jxrG/ha/VB+rODav6/d5i1US6Za/YEMvtm2SgJC/CXVFiD3UFSH2UFeE2ENdEWIPdUWIPdQVIfZQ\n" 0413 "V4TYQ10RYg91RYg91BUh9lBXhNhDXRFiD3VFiD3UFSH2UFeE2ENdEWIPdUWIPdQVIfZQV4TYQ10R\n" 0414 "Yg91RYg91BUh9lBX5E+Tz6Vty1HSx+NR++UuCOqKEHv+Ax0Y5U59+AHBAAAAAElFTkSuQmCC\n" 0415 "\n" 0416 "--Boundary-02=_LShMLJyjC7zqmVP--"; 0417 0418 KMime::Message msg; 0419 msg.setContent(data); 0420 msg.parse(); 0421 0422 QCOMPARE(msg.contents().size(), 2); 0423 QCOMPARE(msg.contents()[0]->contentType()->isMultipart(), true); 0424 QCOMPARE(msg.contents()[0]->contentType()->subType().data(), "alternative"); 0425 0426 QCOMPARE(msg.contents()[1]->contentType()->isImage(), true); 0427 QCOMPARE(msg.contents()[1]->contentType()->name(), 0428 QLatin1StringView("inlineimage.png")); 0429 QCOMPARE(msg.contents()[1]->contentID()->identifier().data(), "740439759"); 0430 QCOMPARE(msg.contents()[1]->contentID()->as7BitString(false).data(), "<740439759>"); 0431 } 0432 0433 void MessageTest::testIssue3908() 0434 { 0435 KMime::Message::Ptr msg = readAndParseMail(QStringLiteral("issue3908.mbox")); 0436 QCOMPARE(msg->contents().size(), 2); 0437 KMime::Content *attachment = msg->contents().at(1); 0438 QVERIFY(attachment); 0439 QVERIFY(attachment->contentDescription(false)); 0440 QCOMPARE(attachment->contentDescription()->asUnicodeString(), QString::fromUtf8( 0441 "Kontact oder auch KDE-PIM ist der Groupware-Client aus der KDE Software Compilation 4.Eine der Besonderheiten von Kontact " 0442 "gegenüber anderen Groupware-Clients ist, dass die Teil-Programme auch weiterhin unabhängig von Kontact gestartet werden " 0443 "können. So spielt es zum Beispiel keine Rolle für das Arbeiten mit KMail, ob es mal allein oder mal im Rahmen von Kontact " 0444 "gestartet wird: Die Mails und die persönlichen Einstellungen bleiben stets erhalten.Auch sieht Kontact eine modulare " 0445 "Anbindung der Programme vor, wodurch sich auch in Zukunft weitere Module entwickeln und anfügen lassen, ohne Kontact " 0446 "dafür zu ändern. Dies bietet die Möglichkeit, auch privat entwickelte Module einzubinden und so die Groupware grundlegend " 0447 "eigenen Bedürfnissen anzupassen.")); 0448 } 0449 0450 void MessageTest::testIssue3914() 0451 { 0452 // This loads a mail which has a content-disposition of which the filename parameter is empty. 0453 // Check that the parser doesn't choke on this. 0454 KMime::Message::Ptr msg = readAndParseMail(QStringLiteral("broken-content-disposition.mbox")); 0455 0456 QCOMPARE(msg->subject()->as7BitString().data(), "Subject: Fwd: test broken mail"); 0457 QCOMPARE(msg->contents().size(), 2); 0458 KMime::Content *attachedMail = msg->contents().at(1); 0459 QCOMPARE(attachedMail->contentType()->mimeType().data(), "message/rfc822"); 0460 QVERIFY(attachedMail->contentDisposition(false)); 0461 QVERIFY(attachedMail->contentDisposition()->hasParameter( 0462 QLatin1StringView("filename"))); 0463 QVERIFY(attachedMail->contentDisposition() 0464 ->parameter(QLatin1StringView("filename")) 0465 .isEmpty()); 0466 } 0467 0468 void MessageTest::testBug223509() 0469 { 0470 KMime::Message::Ptr msg = readAndParseMail(QStringLiteral("encoding-crash.mbox")); 0471 0472 QCOMPARE(msg->subject()->as7BitString().data(), "Subject: Blub"); 0473 QCOMPARE(msg->contents().size(), 0); 0474 QCOMPARE(msg->contentTransferEncoding()->encoding(), KMime::Headers::CEbinary); 0475 QCOMPARE(msg->decodedText().toLatin1().data(), "Bla Bla Bla"); 0476 QCOMPARE(msg->encodedBody().data(), "Bla Bla Bla\n"); 0477 0478 // encodedContent() was crashing in this bug because of an invalid assert 0479 QVERIFY(!msg->encodedContent().isEmpty()); 0480 0481 // Make sure that the encodedContent() is sane, by parsing it again. 0482 KMime::Message msg2; 0483 msg2.setContent(msg->encodedContent()); 0484 msg2.parse(); 0485 QCOMPARE(msg2.subject()->as7BitString().data(), "Subject: Blub"); 0486 QCOMPARE(msg2.contents().size(), 0); 0487 QCOMPARE(msg2.contentTransferEncoding()->encoding(), KMime::Headers::CEbinary); 0488 0489 QCOMPARE(msg2.decodedText().toLatin1().data(), "Bla Bla Bla"); 0490 QCOMPARE(msg2.decodedText(true, true /* remove newlines at end */).toLatin1().data(), 0491 "Bla Bla Bla"); 0492 } 0493 0494 void MessageTest::testEncapsulatedMessages() 0495 { 0496 // 0497 // First, test some basic properties to check that the parsing was correct 0498 // 0499 KMime::Message::Ptr msg = readAndParseMail(QStringLiteral("simple-encapsulated.mbox")); 0500 QCOMPARE(msg->contentType()->mimeType().data(), "multipart/mixed"); 0501 QCOMPARE(msg->contents().size(), 2); 0502 QVERIFY(msg->isTopLevel()); 0503 0504 KMime::Content *const textContent = msg->contents().at(0); 0505 QCOMPARE(textContent->contentType()->mimeType().data(), "text/plain"); 0506 QVERIFY(textContent->contents().isEmpty()); 0507 QVERIFY(!textContent->bodyIsMessage()); 0508 QVERIFY(!textContent->bodyAsMessage()); 0509 QVERIFY(!textContent->isTopLevel()); 0510 QCOMPARE( 0511 textContent->decodedText(true, true), 0512 QLatin1StringView( 0513 "Hi Hans!\nLook at this interesting mail I forwarded to you!")); 0514 QCOMPARE(textContent->index().toString().toLatin1().data(), "1"); 0515 0516 KMime::Content *messageContent = msg->contents().at(1); 0517 QCOMPARE(messageContent->contentType()->mimeType().data(), "message/rfc822"); 0518 QVERIFY(messageContent->body().isEmpty()); 0519 QCOMPARE(messageContent->contents().count(), 1); 0520 QVERIFY(messageContent->bodyIsMessage()); 0521 QVERIFY(messageContent->bodyAsMessage().data()); 0522 QVERIFY(!messageContent->isTopLevel()); 0523 QCOMPARE(messageContent->index().toString().toLatin1().data(), "2"); 0524 0525 KMime::Message::Ptr encapsulated = messageContent->bodyAsMessage(); 0526 QCOMPARE(encapsulated->contents().size(), 0); 0527 QCOMPARE(encapsulated->contentType()->mimeType().data(), "text/plain"); 0528 QVERIFY(!encapsulated->bodyIsMessage()); 0529 QVERIFY(!encapsulated->bodyAsMessage()); 0530 QCOMPARE(encapsulated->subject()->as7BitString(false).data(), "Foo"); 0531 QCOMPARE(encapsulated->decodedText(false, false), 0532 QLatin1StringView("This is the encapsulated message body.")); 0533 QCOMPARE(encapsulated.data(), messageContent->bodyAsMessage().data()); 0534 QCOMPARE(encapsulated.data(), messageContent->contents().constFirst()); 0535 QCOMPARE(encapsulated->parent(), messageContent); 0536 QVERIFY(!encapsulated->isTopLevel()); 0537 QCOMPARE(encapsulated->topLevel(), msg.data()); 0538 QCOMPARE(encapsulated->index().toString().toLatin1().data(), "2.1"); 0539 0540 // Now test some misc functions 0541 QCOMPARE(msg->storageSize(), msg->head().size() + textContent->storageSize() + 0542 messageContent->storageSize()); 0543 QCOMPARE(messageContent->storageSize(), messageContent->head().size() + 0544 encapsulated->storageSize()); 0545 0546 // Now change some properties on the encapsulated message 0547 encapsulated->subject()->fromUnicodeString(QStringLiteral("New subject"), "us-ascii"); 0548 encapsulated->fromUnicodeString(QStringLiteral("New body string.")); 0549 0550 // Since we didn't assemble the encapsulated message yet, it should still have the old headers 0551 QVERIFY(encapsulated->encodedContent().contains("Foo")); 0552 QVERIFY(!encapsulated->encodedContent().contains("New subject")); 0553 0554 // Now assemble the container message 0555 msg->assemble(); 0556 0557 // Assembling the container message should have assembled the encapsulated message as well. 0558 QVERIFY(!encapsulated->encodedContent().contains("Foo")); 0559 QVERIFY(encapsulated->encodedContent().contains("New subject")); 0560 QCOMPARE(encapsulated->body().data(), "New body string."); 0561 QVERIFY(msg->encodedContent().contains(encapsulated->body())); 0562 QCOMPARE(msg->contentType()->mimeType().data(), "multipart/mixed"); 0563 QCOMPARE(msg->contents().size(), 2); 0564 messageContent = msg->contents().at(1); 0565 QCOMPARE(messageContent->contentType()->mimeType().data(), "message/rfc822"); 0566 QVERIFY(encapsulated.data() == messageContent->bodyAsMessage().data()); 0567 0568 // Setting a new body and then parsing it should discard the encapsulated message 0569 messageContent->contentType()->setMimeType("text/plain"); 0570 messageContent->assemble(); 0571 messageContent->setBody("Some new body"); 0572 messageContent->parse(); 0573 QVERIFY(!messageContent->bodyIsMessage()); 0574 QVERIFY(!messageContent->bodyAsMessage()); 0575 QCOMPARE(messageContent->contents().size(), 0); 0576 } 0577 0578 void MessageTest::testOutlookAttachmentNaming() 0579 { 0580 // Try and decode 0581 KMime::Message::Ptr msg = readAndParseMail(QStringLiteral("outlook-attachment.mbox")); 0582 QVERIFY(msg->attachments().count() == 1); 0583 0584 KMime::Content *attachment = msg->contents()[1]; 0585 QCOMPARE(attachment->contentType(false)->mediaType().data(), "text"); 0586 QCOMPARE(attachment->contentType(false)->subType().data(), "x-patch"); 0587 0588 Headers::ContentDisposition *cd = attachment->contentDisposition(false); 0589 QVERIFY(cd); 0590 QCOMPARE(cd->filename(), QString::fromUtf8("å.diff")); 0591 0592 // Try and encode 0593 attachment->clear();// = new Content(); 0594 attachment->contentDisposition()->setDisposition(Headers::CDattachment); 0595 attachment->contentDisposition()->setFilename(QStringLiteral("å.diff")); 0596 attachment->contentDisposition()->setRFC2047Charset("ISO-8859-1"); // default changed to UTF-8 in KF6, which is fine, but breaks the test 0597 attachment->assemble(); 0598 qDebug() << "got:" << attachment->contentDisposition()->as7BitString(false); 0599 QCOMPARE(attachment->contentDisposition()->as7BitString(false), QByteArray("attachment; filename*=ISO-8859-1''%E5%2Ediff")); 0600 } 0601 0602 void MessageTest::testEncryptedMails() 0603 { 0604 KMime::Message::Ptr msg = readAndParseMail(QStringLiteral("x-pkcs7.mbox")); 0605 QVERIFY(msg->contents().size() == 0); 0606 QVERIFY(msg->attachments().count() == 0); 0607 QVERIFY(KMime::isEncrypted(msg.data()) == true); 0608 QVERIFY(KMime::isInvitation(msg.data()) == false); 0609 QVERIFY(KMime::isSigned(msg.data()) == false); 0610 } 0611 0612 void MessageTest::testReturnSameMail() 0613 { 0614 KMime::Message::Ptr msg = readAndParseMail(QStringLiteral("dontchangemail.mbox")); 0615 QFile file(QLatin1StringView(TEST_DATA_DIR) + 0616 QLatin1StringView("/mails/dontchangemail.mbox")); 0617 QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text)); 0618 QByteArray fileContent = file.readAll(); 0619 QCOMPARE(msg->encodedContent(), fileContent); 0620 QCOMPARE(msg->decodedText(), QLatin1StringView("")); 0621 KMime::Message msg2; 0622 msg2.setContent(msg->encodedContent()); 0623 msg2.parse(); 0624 QCOMPARE(msg2.encodedContent(), fileContent); 0625 } 0626 0627 void MessageTest::testEmptySubject() 0628 { 0629 auto msg = readAndParseMail(QStringLiteral("empty-subject.mbox")); 0630 QVERIFY(msg); // was crashing for Andre 0631 QVERIFY(msg->hasHeader("Subject")); 0632 QVERIFY(msg->subject()->asUnicodeString().isEmpty()); 0633 } 0634 0635 void MessageTest::testReplyHeader() 0636 { 0637 auto msg = readAndParseMail(QStringLiteral("reply-header.mbox")); 0638 QVERIFY(msg); 0639 QVERIFY(!msg->replyTo(false)); 0640 QCOMPARE(msg->hasHeader("Reply-To"), false); 0641 QCOMPARE(msg->hasHeader("Reply"), true); 0642 QVERIFY(msg->headerByType("Reply")); 0643 } 0644 0645 KMime::Message::Ptr MessageTest::readAndParseMail(const QString &mailFile) const 0646 { 0647 QFile file(QLatin1StringView(TEST_DATA_DIR) + QLatin1StringView("/mails/") + 0648 mailFile); 0649 const bool ok = file.open(QIODevice::ReadOnly); 0650 if (!ok) { 0651 qWarning() << file.fileName() << "not found"; 0652 } 0653 Q_ASSERT(ok); 0654 const QByteArray data = KMime::CRLFtoLF(file.readAll()); 0655 Q_ASSERT(!data.isEmpty()); 0656 KMime::Message::Ptr msg(new KMime::Message); 0657 msg->setContent(data); 0658 msg->parse(); 0659 return msg; 0660 } 0661 0662 void MessageTest::testBug392239() 0663 { 0664 auto msg = readAndParseMail(QStringLiteral("bug392239.mbox")); 0665 0666 QCOMPARE(msg->subject()->as7BitString().data(), "Subject: "); 0667 QCOMPARE(msg->contents().size(), 0); 0668 QCOMPARE(msg->contentTransferEncoding()->encoding(), KMime::Headers::CEbase64); 0669 QCOMPARE(msg->decodedText().toUtf8().data(), "Following this paragraph there is a double line break which should result in vertical spacing.\r\rPreceding this paragraph there is a double line break which should result in vertical spacing.\r"); 0670 } 0671 0672 void MessageTest::testBugAttachment387423() 0673 { 0674 auto msg = readAndParseMail(QStringLiteral("kmail-attachmentstatus.mbox")); 0675 0676 QCOMPARE(msg->subject()->as7BitString().data(), "Subject: XXXXXXXXXXXXXXXXXXXXX"); 0677 QEXPECT_FAIL("", "Problem with searching attachment", Continue); 0678 QCOMPARE(msg->attachments().count(), 1); 0679 QCOMPARE(msg->contents().count(), 2); 0680 0681 KMime::Content *attachment = msg->contents()[1]; 0682 QCOMPARE(attachment->contentType(false)->mediaType().data(), "image"); 0683 QCOMPARE(attachment->contentType(false)->subType().data(), "gif"); 0684 QCOMPARE(attachment->contentType(false)->subType().data(), "gif"); 0685 QCOMPARE(attachment->contentDisposition(false)->filename(), QStringLiteral("new.gif")); 0686 QCOMPARE(attachment->contentDisposition(false)->disposition(), Headers::CDattachment); 0687 } 0688 0689 void MessageTest::testCrashReplyInvalidEmail() 0690 { 0691 KMime::Message::Ptr msg = readAndParseMail(QStringLiteral("crash-invalid-email-reply.mbox")); 0692 QCOMPARE(msg->subject()->as7BitString().data(), "Subject: Re: Authorization required to post to gmane.network.wireguard (b96565298414a43aabcf9fbedf5e7e27)"); 0693 QCOMPARE(msg->contentType()->mimeType().data(), "text/plain"); 0694 QCOMPARE(msg->contentType()->charset().data(), "us-ascii"); 0695 QVERIFY(msg->isTopLevel()); 0696 } 0697 0698 0699 #include "moc_messagetest.cpp"