File indexing completed on 2024-04-14 05:12:18
0001 /* 0002 SPDX-FileCopyrightText: 2006 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "contenttest.h" 0008 0009 #include <QDebug> 0010 #include <QTest> 0011 0012 #include "kmime_content.h" 0013 #include "kmime_headers.h" 0014 #include "kmime_message.h" 0015 using namespace KMime; 0016 0017 QTEST_MAIN(ContentTest) 0018 0019 void ContentTest::testGetHeaderInstance() 0020 { 0021 // stuff that looks trivial but breaks if you mess with virtual method signatures (see r534381) 0022 auto myfrom = new Headers::From(); 0023 QCOMPARE(myfrom->type(), "From"); 0024 Headers::Base *mybase = myfrom; 0025 QCOMPARE(mybase->type(), "From"); 0026 delete myfrom; 0027 0028 // getHeaderInstance() is protected, so we need to test it via KMime::Message 0029 auto c = new Message(); 0030 Headers::From *f1 = c->from(true); 0031 Headers::From *f2 = c->from(true); 0032 QCOMPARE(f1, f2); 0033 delete c; 0034 } 0035 0036 void ContentTest::testHeaderAddRemove() 0037 { 0038 // Add a Content-Description header to a content. 0039 auto c = new Content; 0040 QVERIFY(!c->contentDescription(false)); 0041 c->contentDescription()->from7BitString("description"); 0042 0043 // The content must now have the header. 0044 QVERIFY(c->contentDescription(false)); 0045 QCOMPARE(c->contentDescription()->as7BitString(false), QByteArray("description")); 0046 0047 // The content's head must also have the header. Save the head. 0048 c->assemble(); 0049 QByteArray head = c->head(); 0050 0051 // Clear the content. It must now forget the cached header. 0052 c->clear(); 0053 QVERIFY(c->head().isEmpty()); 0054 QVERIFY(!c->contentDescription(false)); 0055 0056 // Put the head back. It must now remember the header. 0057 c->setHead(head); 0058 QVERIFY(!c->contentDescription(false)); 0059 c->parse(); 0060 QVERIFY(c->contentDescription(false)); 0061 c->contentDescription()->from7BitString("description"); 0062 0063 // Now remove the header explicitly. 0064 bool ret = c->removeHeader("Content-Description"); 0065 QVERIFY(ret); 0066 0067 // The content must have forgotten the header now. 0068 QVERIFY(!c->contentDescription(false)); 0069 0070 // And after assembly the header should stay gone. 0071 c->assemble(); 0072 //QVERIFY(c->head().isEmpty()); 0073 QVERIFY(!c->contentDescription(false)); 0074 0075 delete c; 0076 0077 // test template versions 0078 Content c2; 0079 QVERIFY(!c2.hasHeader(KMime::Headers::Lines::staticType())); 0080 QVERIFY(!c2.header<KMime::Headers::Lines>(false)); 0081 QVERIFY(c2.header<KMime::Headers::Lines>(true)); 0082 QVERIFY(c2.hasHeader(KMime::Headers::Lines::staticType())); 0083 c2.removeHeader<KMime::Headers::Lines>(); 0084 QVERIFY(!c2.hasHeader(KMime::Headers::Lines::staticType())); 0085 } 0086 0087 void ContentTest::testHeaderAppend() 0088 { 0089 auto c = new Content; 0090 QByteArray d1("Resent-From: test1@example.com"); 0091 QByteArray d2("Resent-From: test2@example.com"); 0092 auto h1 = new Headers::Generic("Resent-From"); 0093 h1->from7BitString("test1@example.com"); 0094 auto h2 = new Headers::Generic("Resent-From"); 0095 h2->from7BitString("test2@example.com"); 0096 c->appendHeader(h1); 0097 c->appendHeader(h2); 0098 c->assemble(); 0099 QByteArray head = d1 + '\n' + d2 + '\n'; 0100 QCOMPARE(c->head(), head); 0101 0102 QByteArray d3("Resent-From: test3@example.com"); 0103 auto h3 = new Headers::Generic("Resent-From"); 0104 h3->from7BitString("test3@example.com"); 0105 c->appendHeader(h3); 0106 c->assemble(); 0107 head.append(d3 + '\n'); 0108 QCOMPARE(c->head(), head); 0109 delete c; 0110 } 0111 0112 void ContentTest::testExplicitMultipartGeneration() 0113 { 0114 auto c1 = new Content(); 0115 c1->contentType()->from7BitString("multipart/mixed"); 0116 0117 auto c2 = new Content(); 0118 c2->contentType()->from7BitString("text/plain"); 0119 c2->setBody("textpart"); 0120 0121 auto c3 = new Content(); 0122 c3->contentType()->from7BitString("text/html"); 0123 c3->setBody("htmlpart"); 0124 0125 c1->appendContent(c2); 0126 c1->appendContent(c3); 0127 0128 // c1 should not have been changed. 0129 QCOMPARE(c1->contentType()->mimeType(), QByteArray("multipart/mixed")); 0130 QVERIFY(c1->body().isEmpty()); 0131 0132 QCOMPARE(c1->contents().count(), 2); 0133 QCOMPARE(c1->contents().at(0), c2); 0134 QCOMPARE(c1->contents().at(1), c3); 0135 0136 c1->takeContent(c3); 0137 QCOMPARE(c1->contents().count(), 1); 0138 QCOMPARE(c1->contentType()->mimeType(), QByteArray("multipart/mixed")); 0139 QVERIFY(c1->body().isEmpty()); 0140 QCOMPARE(c1->contents().at(0), c2); 0141 QCOMPARE(c2->body(), QByteArray("textpart")); 0142 QCOMPARE(c3->parent(), nullptr); 0143 0144 // Clean up. 0145 delete c1; 0146 // c2 was deleted when c1 turned itself single-part. 0147 delete c3; 0148 } 0149 0150 void ContentTest::testSetContent() 0151 { 0152 auto c = new Content(); 0153 QVERIFY(!c->hasContent()); 0154 0155 // head and body present 0156 c->setContent("head1\nhead2\n\nbody1\n\nbody2\n"); 0157 QVERIFY(c->hasContent()); 0158 QCOMPARE(c->head(), QByteArray("head1\nhead2\n")); 0159 QCOMPARE(c->body(), QByteArray("body1\n\nbody2\n")); 0160 0161 // empty content 0162 c->setContent(QByteArray()); 0163 QVERIFY(!c->hasContent()); 0164 QVERIFY(c->head().isEmpty()); 0165 QVERIFY(c->body().isEmpty()); 0166 0167 // empty head 0168 c->setContent("\nbody1\n\nbody2\n"); 0169 QVERIFY(c->hasContent()); 0170 QVERIFY(c->head().isEmpty()); 0171 QCOMPARE(c->body(), QByteArray("body1\n\nbody2\n")); 0172 0173 // empty body 0174 c->setContent("head1\nhead2\n\n"); 0175 QVERIFY(c->hasContent()); 0176 QCOMPARE(c->head(), QByteArray("head1\nhead2\n")); 0177 QVERIFY(c->body().isEmpty()); 0178 0179 delete c; 0180 } 0181 0182 void ContentTest::testEncodedContent() 0183 { 0184 // Example taken from RFC 2046, section 5.1.1. 0185 // Removed "preamble" and "epilogue", which KMime loses. 0186 QByteArray data = 0187 "From: Nathaniel Borenstein <nsb@bellcore.com>\n" 0188 "To: Ned Freed <ned@innosoft.com>\n" 0189 "Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)\n" 0190 "Subject: Sample message\n" 0191 "MIME-Version: 1.0\n" 0192 "Content-type: multipart/mixed; boundary=\"simple boundary\"\n" 0193 "\n" 0194 "\n" 0195 "--simple boundary\n" 0196 "\n" 0197 "This is implicitly typed plain US-ASCII text.\n" 0198 "It does NOT end with a linebreak.\n" 0199 "--simple boundary\n" 0200 "Content-type: text/plain; charset=us-ascii\n" 0201 "\n" 0202 "This is explicitly typed plain US-ASCII text.\n" 0203 "It DOES end with a linebreak.\n" 0204 "\n" 0205 "--simple boundary--\n"; 0206 0207 auto msg = new Message; 0208 msg->setContent(data); 0209 msg->parse(); 0210 0211 // Test that multiple calls do not corrupt anything. 0212 //QByteArray encc = msg->encodedContent(); 0213 //qDebug() << "original data" << data; 0214 //qDebug() << "encodedContent" << encc; 0215 QCOMPARE(msg->encodedContent(), data); 0216 QCOMPARE(msg->encodedContent(), data); 0217 QCOMPARE(msg->encodedContent(), data); 0218 delete msg; 0219 0220 // RFC 2822 3.5: lines are limited to 1000 characters (998 + CRLF) 0221 // (bug #187345) 0222 msg = new Message(); 0223 data = 0224 "Subject:" 0225 "test test test test test test test test test test test test test test test test test test test test " 0226 "test test test test test test test test test test test test test test test test test test test test " 0227 "test test test test test test test test test test test test test test test test test test test test " 0228 "test test test test test test test test test test test test test test test test test test test test " 0229 "test test test test test test test test test test test test test test test test test test test test " 0230 "test test test test test test test test test test test test test test test test test test test test " 0231 "test test test test test test test test test test test test test test test test test test test test " 0232 "test test test test test test test test test test test test test test test test test test test test " 0233 "test test test test test test test test test test test test test test test test test test test test " 0234 "test test test test test test test test test test test test test test test test test test test test" 0235 "\n" 0236 "References: " 0237 "<test1@example.com> <test1@example.com> <test1@example.com> <test1@example.com> <test1@example.com> " 0238 "<test1@example.com> <test1@example.com> <test1@example.com> <test1@example.com> <test1@example.com> " 0239 "<test1@example.com> <test1@example.com> <test1@example.com> <test1@example.com> <test1@example.com> " 0240 "<test1@example.com> <test1@example.com> <test1@example.com> <test1@example.com> <test1@example.com> " 0241 "<test1@example.com> <test1@example.com> <test1@example.com> <test1@example.com> <test1@example.com> " 0242 "<test1@example.com> <test1@example.com> <test1@example.com> <test1@example.com> <test1@example.com> " 0243 "<test1@example.com> <test1@example.com> <test1@example.com> <test1@example.com> <test1@example.com> " 0244 "<test1@example.com> <test1@example.com> <test1@example.com> <test1@example.com> <test1@example.com> " 0245 "<test1@example.com> <test1@example.com> <test1@example.com> <test1@example.com> <test1@example.com> " 0246 "<test1@example.com> <test1@example.com> <test1@example.com> <test1@example.com> <test1@example.com>" 0247 "\n\n" 0248 "body\n"; 0249 msg->setContent(data); 0250 QByteArray content = msg->encodedContent(true /* use CRLF */); 0251 const QStringList lines = QString::fromLatin1(content).split(QStringLiteral("\r\n")); 0252 for (const QString &line : lines) { 0253 QEXPECT_FAIL("", "KMime does not fold lines longer than 998 characters", Continue); 0254 QVERIFY(line.length() < 998 && !line.isEmpty() && 0255 line != QLatin1StringView("body")); 0256 // The test should be (after the expected failure disappears): 0257 //QVERIFY( line.length() < 998 ); 0258 } 0259 delete msg; 0260 0261 } 0262 0263 void ContentTest::testDecodedContent() 0264 { 0265 auto c = new Content(); 0266 c->setBody("\0"); 0267 QVERIFY(c->decodedContent() == QByteArray()); 0268 c->setBody(QByteArray()); 0269 QVERIFY(c->decodedContent() == QByteArray()); 0270 c->setBody(" "); 0271 QVERIFY(c->decodedContent() == QByteArray(" ")); 0272 delete c; 0273 } 0274 0275 void ContentTest::testMultipleHeaderExtraction() 0276 { 0277 QByteArray data = 0278 "From: Nathaniel Borenstein <nsb@bellcore.com>\n" 0279 "To: Ned Freed <ned@innosoft.com>\n" 0280 "Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)\n" 0281 "Subject: Sample message\n" 0282 "Received: from ktown.kde.org ([192.168.100.1])\n" 0283 "Received: from dev1.kde.org ([192.168.100.2])\n" 0284 "\t by ktown.kde.org ([192.168.100.1])\n" 0285 "Received: from dev2.kde.org ([192.168.100.3])\n" 0286 " by ktown.kde.org ([192.168.100.1])\n"; 0287 0288 auto msg = new Message(); 0289 msg->setContent(data); 0290 // FAILS identically to ContentTest::testMultipartMixed 0291 // QCOMPARE( msg->encodedContent(), data ); 0292 msg->parse(); 0293 0294 auto result = msg->headersByType("Received"); 0295 QCOMPARE(result.count(), 3); 0296 QCOMPARE(result[0]->asUnicodeString(), QString::fromLatin1("from ktown.kde.org ([192.168.100.1])")); 0297 QCOMPARE(result[1]->asUnicodeString(), QString::fromLatin1("from dev1.kde.org ([192.168.100.2]) by ktown.kde.org ([192.168.100.1])")); 0298 QCOMPARE(result[2]->asUnicodeString(), QString::fromLatin1("from dev2.kde.org ([192.168.100.3]) by ktown.kde.org ([192.168.100.1])")); 0299 delete msg; 0300 } 0301 0302 void ContentTest::testMultipartMixed() 0303 { 0304 // example taken from RFC 2046, section 5.1.1. 0305 QByteArray data = 0306 "From: Nathaniel Borenstein <nsb@bellcore.com>\n" 0307 "To: Ned Freed <ned@innosoft.com>\n" 0308 "Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)\n" 0309 "Subject: Sample message\n" 0310 "MIME-Version: 1.0\n" 0311 "Content-type: multipart/mixed; boundary=\"simple boundary\"\n" 0312 "\n" 0313 "This is the preamble. It is to be ignored, though it\n" 0314 "is a handy place for composition agents to include an\n" 0315 "explanatory note to non-MIME conformant readers.\n" 0316 "\n" 0317 "--simple boundary\n" 0318 "\n" 0319 "This is implicitly typed plain US-ASCII text.\n" 0320 "It does NOT end with a linebreak.\n" 0321 "--simple boundary\n" 0322 "Content-type: text/plain; charset=us-ascii\n" 0323 "\n" 0324 "This is explicitly typed plain US-ASCII text.\n" 0325 "It DOES end with a linebreak.\n" 0326 "\n" 0327 "--simple boundary--\n" 0328 "\n" 0329 "This is the epilogue. It is also to be ignored.\n"; 0330 0331 QByteArray part1 = 0332 "This is implicitly typed plain US-ASCII text.\n" 0333 "It does NOT end with a linebreak."; 0334 0335 QByteArray part2 = 0336 "This is explicitly typed plain US-ASCII text.\n" 0337 "It DOES end with a linebreak.\n"; 0338 0339 // What we expect KMime to parse the above data into. 0340 QByteArray parsedWithPreambleAndEpilogue = 0341 "From: Nathaniel Borenstein <nsb@bellcore.com>\n" 0342 "To: Ned Freed <ned@innosoft.com>\n" 0343 "Date: Sun, 21 Mar 1993 23:56:48 -0800\n" 0344 "Subject: Sample message\n" 0345 "MIME-Version: 1.0\n" 0346 "Content-Type: multipart/mixed; boundary=\"simple boundary\"\n" 0347 "\n" 0348 "This is the preamble. It is to be ignored, though it\n" 0349 "is a handy place for composition agents to include an\n" 0350 "explanatory note to non-MIME conformant readers.\n" 0351 "\n" 0352 "--simple boundary\n" 0353 "Content-Type: text/plain; charset=\"us-ascii\"\n\n" 0354 "This is implicitly typed plain US-ASCII text.\n" 0355 "It does NOT end with a linebreak.\n" 0356 "--simple boundary\n" 0357 "Content-Type: text/plain; charset=\"us-ascii\"\n" 0358 "\n" 0359 "This is explicitly typed plain US-ASCII text.\n" 0360 "It DOES end with a linebreak.\n" 0361 "\n" 0362 "--simple boundary--\n" 0363 "\n" 0364 "This is the epilogue. It is also to be ignored.\n"; 0365 0366 // What we expect KMime to assemble the above data into. 0367 QByteArray assembled = 0368 "From: Nathaniel Borenstein <nsb@bellcore.com>\n" 0369 "To: Ned Freed <ned@innosoft.com>\n" 0370 "Date: Sun, 21 Mar 1993 23:56:48 -0800\n" 0371 "Subject: Sample message\n" 0372 "MIME-Version: 1.0\n" 0373 "Content-Type: multipart/mixed; boundary=\"simple boundary\"\n" 0374 "Content-Transfer-Encoding: 7Bit\n" 0375 "\n" 0376 "--simple boundary\n" 0377 "\n" 0378 "This is implicitly typed plain US-ASCII text.\n" 0379 "It does NOT end with a linebreak.\n" 0380 "--simple boundary\n" 0381 "Content-Type: text/plain; charset=\"us-ascii\"\n" 0382 "\n" 0383 "This is explicitly typed plain US-ASCII text.\n" 0384 "It DOES end with a linebreak.\n" 0385 "\n" 0386 "--simple boundary--\n"; 0387 0388 // test parsing 0389 auto msg = new Message(); 0390 msg->setContent(data); 0391 QCOMPARE(msg->encodedContent(), data); 0392 msg->parse(); 0393 QVERIFY(msg->contentType()->isMultipart()); 0394 0395 auto list = msg->contents(); 0396 QCOMPARE(list.count(), 2); 0397 Content *c = list.takeFirst(); 0398 QCOMPARE(c->body(), part1); 0399 c = list.takeFirst(); 0400 QCOMPARE(c->body(), part2); 0401 0402 // assemble again 0403 msg->assemble(); 0404 //qDebug() << "expected assembled content" << parsedWithPreambleAndEpilogue; 0405 //qDebug() << "actual new encoded content" << msg->encodedContent(); 0406 QCOMPARE(msg->encodedContent(), parsedWithPreambleAndEpilogue); 0407 delete msg; 0408 0409 // assembling from scratch 0410 // (The headers have to be in the same order, as we compare with the above assembled.) 0411 msg = new Message(); 0412 msg->from()->from7BitString("Nathaniel Borenstein <nsb@bellcore.com>"); 0413 msg->to()->from7BitString("Ned Freed <ned@innosoft.com>"); 0414 msg->date()->from7BitString("Sun, 21 Mar 1993 23:56:48 -0800 (PST)"); 0415 msg->subject()->from7BitString("Sample message"); 0416 // HACK to make MIME-Version appear before Content-Type, as in the expected message. 0417 auto header = new Headers::MIMEVersion; 0418 header->from7BitString("1.234"); 0419 msg->setHeader(header); 0420 msg->contentType()->from7BitString("multipart/mixed"); 0421 msg->contentTransferEncoding()->setEncoding(KMime::Headers::CE7Bit); 0422 0423 c = new Content(); 0424 c->setBody(part1); 0425 msg->appendContent(c); 0426 0427 c = new Content(); 0428 c->setBody(part2); 0429 c->contentType()->setMimeType("text/plain"); 0430 c->contentType()->setCharset("us-ascii"); 0431 msg->appendContent(c); 0432 msg->contentType()->setBoundary("simple boundary"); 0433 0434 list = msg->contents(); 0435 QCOMPARE(list.count(), 2); 0436 c = list.takeFirst(); 0437 QCOMPARE(c->body(), part1); 0438 c = list.takeFirst(); 0439 QCOMPARE(c->body(), part2); 0440 0441 msg->assemble(); 0442 //QByteArray encc = msg->encodedContent(); 0443 //qDebug().noquote() << "expected assembled content" << assembled; 0444 //qDebug().noquote() << "actual encoded content" << encc; 0445 QCOMPARE(msg->encodedContent(), assembled); 0446 delete msg; 0447 } 0448 0449 void ContentTest::testParsingUuencoded() 0450 { 0451 const QByteArray body = 0452 "This is a test message that should appears as a text/plain part\n" 0453 "once this message is parsed and convert to a MIME tree.\n" 0454 "\n" 0455 "\n"; 0456 0457 const QString imageName = QStringLiteral("Name of the encoded file (oxygen 22x22 kde.png)"); 0458 const QByteArray imageBase64 = 0459 "\n" 0460 "iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\n" 0461 "AAADdgAAA3YBfdWCzAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAU4SURB\n" 0462 "VBgZjcFbiF1XGcDx/7fW2pdznTOXNJlJc4WWVK3RqiC2FOyTiGCs+lKkohWTIl5QWrAp9ckLKpYi\n" 0463 "KFjwodgXoRDMk1VECj7UpkIqUZuCTUycyWXOzJxz9tnXtdfnxNqnvvj7iaryNhGxgPBOAh/gLa+y\n" 0464 "S3kn3dXyP6KqyEe+1Rm6tSc6nYVHO+loOXYR1hisFYRAIOBljtecyPaItEMkXeK4S2QTVAxVOZ1t\n" 0465 "TzaeG6//9fTWuR9MnOxyx7/xzaWjB548cvgAUeyJbGDYj9mzPGJl1GdpocOwlxCCMs1qtrKSrZ2c\n" 0466 "ze0Z126O2ZkWSJoO0rDylUabREROOsCoG3z58JEDrK4NIFQMBz0WBl2G3ZReGiNi+debO6gKC3sH\n" 0467 "DAcxNu6QpF1GiwtsTzMm04wrVyeY7upngEcdYIy4pSgVJtmMYb+HmBiVGE9Eo47ZdsHJj3eJnOHp\n" 0468 "M3P6exbIJxmffr/ibMK58zN+M4nwlGCTPmAMu8QYKasCFYd1CWoSgkT4YGmCoWggTRLiOKH0UFTK\n" 0469 "A8csdx0ZcnBfl/PXIuJ+j253gBED3CEGDluxVtqgGBcTJCKIZboxJq9bssozLxqiKMJZS1G3LIct\n" 0470 "7nvfAs5FvPDSjHlnEbER3f4AsUZYG1rD2t3GGIu4GIhosUSzCd9/5HZOvKtldnmd7evbRM7hnEOz\n" 0471 "CV/8xCrOWv52qeKVGx0CBpUIF3cwxsLwdmtYPGSMtaLW0WIIKuStIXLCh9+9wE++fgfWV4jwX489\n" 0472 "fJQkMswr5ee/26EMgaaFVoW6VsRaGXWWrFnqWyPWSV0rrULlA7M45dd/uEHZwOlfvMGW6yAiiAhr\n" 0473 "KwkgGIEiL8jrmryuqWpPWbWItYTlNWvauGeNs8xLT9W2FFXDdGPMwb0pz569wsUqpqgbQADhmecu\n" 0474 "IgK91HHqY7cxz0um85zxrKAVMNYSbGKNtqkIhtB6xptTvntiyJnv3MVH71niT3+fUHvQ1vC2F1+v\n" 0475 "efHPm9xy33sXubtXsj3NaJqKNjSA0KePEVsqKEE9dZWTOBCUtg1sZoamhrYFVQWUphV+dPYml67l\n" 0476 "3PLtz99Jr8zxdYn3NSJKRoYxhQZ2+aZCteWhZy7yydOvceHNOXeuWNRbQmMIIaCqGGJcOuL0s5fJ\n" 0477 "S8+gY3j8U4fQ2hPqEg0BqQnCsUcGg7XjNxZXV1MbJQx6I1ZW9vPge4QHPrjM47/cwXZ6VFmBaEsy\n" 0478 "6GPqgqEtqJqWsmq4OpmT+Sl1XTHdHIemeG3ZML3RBu+1rkp8mROahqiYceL+RQ7eZvnewwusyoRh\n" 0479 "f8hgtMywmfPUQ0Oe+sI+WlJ0tIrrJjR1SdMUBO/Z2fhn61g/68PRe7UqC4JraDo1h3oVsW1440rD\n" 0480 "718uOfXgiL1LEIKiOsI5IY0CT36uzxO/KvF1TV3MqX1D8F6Z/8U7QEPr1WCpyzlVVXJuo+WrP7xE\n" 0481 "ke5neeUA55+/ytNfSxAnPPazEnVdPntvweV/52R5oK4KqiqnqhtQr1y50jpAQ1PmvbTfG493mE62\n" 0482 "oYV/+CWGgzFN8EQm5vo4RxWmLKBty09/65nPC6bZDjuTLeZZhrMJWs8rdjkghOmlF3x57NTy4hrX\n" 0483 "b65T5zl1WVAWc7LuhDTpcvLHFcYY6E7xTUNZ5eT5jFm2w3S6RWRT9oz2cXX9lT8Cragqsv9DK93F\n" 0484 "48/3995zf7e/J41dhDMWawQkoNriTYbXnMj2ibRLJF3iuEtkE1SEfL7VXLv00qs3Xz/zpWp84YKo\n" 0485 "KreIiANGwH5AAOH/o7xlE7gOeN31H1IDp2dl3tAoAAAAAElFTkSuQmCC\n" 0486 ; 0487 0488 const QByteArray uuencodedMsg = 0489 "Path: news.example.net!not-for-mail\n" 0490 "From: Coin coin <meuh@example.net>\n" 0491 "Newsgroups: test.kmime.uuencoded\n" 0492 "Subject: Kmime test\n" 0493 "Date: Thu, 14 Apr 2005 20:12:47 -0700\n" 0494 "Message-ID: <xxxxxxxxxxxxxxxxxx@xxxxx.kmime.example.net>\n" 0495 "X-Newsreader: Forte Agent 2.0/32.640\n" 0496 "Lines: 1283\n" 0497 "Organization: Ament\n" 0498 "Xref: news.example.net test.kmime.uuencoded:4584\n" 0499 "\n" 0500 "This is a test message that should appears as a text/plain part\n" 0501 "once this message is parsed and convert to a MIME tree.\n" 0502 "\n" 0503 "begin 644 Name of the encoded file (oxygen 22x22 kde.png)\n" 0504 "MB5!.1PT*&@H````-24A$4@```!8````6\"`8```#$M&P[````!'-\"250(\"`@(\n" 0505 "M?`ADB`````EP2%ES```#=@```W8!?=6\"S````!ET15AT4V]F='=A<F4`=W=W\n" 0506 "M+FEN:W-C87!E+F]R9YON/!H```4X241!5!@9C<%;B%U7&<#Q_[?6VI=SG3.7\n" 0507 "M-)E)<X665*W1JB\"V%.R3B&\"L^E*DHA63(EY06K`I]<D+*I8B*%CPH=@7H1#,\n" 0508 "MDU5$\"C[4ID(J49N\"34R<R67.S)QS]MG7M=?GQ-JGOOC[B:KR-A&Q@/!.`A_@\n" 0509 "M+:^R2WDGW=7R/Z*JR$>^U1FZM2<ZG85'.^EH.781UABL%81`(.!ECM><R/:(\n" 0510 "MM$,D7>*X2V035`Q5.9UM3S:>&Z__]?36N1],G.QRQ[_QS:6C!YX\\<O@`4>R)\n" 0511 "M;C]FS/&)EU&=IH<.PEQ\"\",LUJMK*2K9V<S>T9UVZ.V9D62)H.TK#RE4:;\n" 0512 "M1$1..L\"H&WSY\\)$#K*X-(%0,!ST6!EV&W91>&B-B^=>;.Z@*\"WL'#`<Q-NZ0\n" 0513 "MI%U&BPML3S,FTXPK5R>8[NIG@$<=8(RXI2@5)MF,8;^'F!B5&$]$HX[9=L')\n" 0514 "MCW>)G.'I,W/Z>Q;()QF??K_B;,*Y\\S-^,XGPE&\"3/F`,N\\08*:L\"%8=U\"6H2\n" 0515 "M@D3X8&F\"H6@@31+B.*'T4%3*`\\<L=QT9<G!?E_/7(N)^CVYW@!$#W\"$&#ENQ\n" 0516 "M5MJ@&!<3)\"*(9;HQ)J];LLHS+QJB*,)92U&W+(<M[GO?`LY%O/#2C'EG$;$1\n" 0517 "MW?X`L498&UK#VMW&&(NX&(AHL42S\"=]_Y'9.O*ME=GF=[>O;1,[AG$.S\"5_\\\n" 0518 "MQ\"K.6OYVJ>*5&QT\"!I4(%W<PQL+P=FM8/&2,M:+6T6((*N2M(7+\"A]^]P$^^\n" 0519 "M?@?65XCP7X\\]?)0D,LPKY>>_VZ$,@::%5H6Z5L1:&766K%GJ6R/625TKK4+E\n" 0520 "M`[,XY==_N$'9P.E?O,&6ZR`BB`AK*PD@&($B+\\CKFKRNJ6I/6;6(M83E-6O:\n" 0521 "MN&>-L\\Q+3]6V%%7#=&/,P;TISYZ]PL4JIJ@;0`#AF><N(@*]U''J8[<QSTNF\n" 0522 "M\\YSQK*`5,-82;&*-MJD(AM!ZQIM3OGMBR)GOW,5'[UGB3W^?4'O0UO\"V%U^O\n" 0523 "M>?'/F]QRWWL7N;M7LCW-:)J*-C2`T*>/$5LJ*$$]=963.!\"4M@UL9H:FAK8%\n" 0524 "M5064IA5^=/8FEZ[EW/+MS]])K\\SQ=8GW-2)*1H8QA09V^:9\"M>6A9R[RR=.O\n" 0525 "M<>'-.7>N6-1;0F,((:\"J&&)<.N+TLY?)2\\^@8WC\\4X?0VA/J$@T!J0G\"L4<&\n" 0526 "M@[7C-Q975U,;)0QZ(U96]O/@>X0'/KC,X[_<P79Z5%F!:$LRZ&/J@J$MJ)J6\n" 0527 "MLFJX.IF3^2EU73'='(>F>&W9,+W1!N^UKDI\\F1.:AJB8<>+^10[>9OG>PPNL\n" 0528 "MRH1A?\\A@M,RPF?/40T.>^L(^6E)TM(KK)C1U2=,4!._9V?AGZU@_Z\\/1>[4J\n" 0529 "M\"X)K:#HUAWH5L6UXXTK#[U\\N.?7@B+U+$(*B.L(Y(8T\"3WZNSQ._*O%U35W,\n" 0530 "MJ7U#\\%Z9_\\4[0$/KU6\"IRSE557)NH^6K/[Q$D>YG>>4`YY^_RM-?2Q`G//:S\n" 0531 "M$G5=/GMOP>5_YV1YH*X*JBJGJAM0KURYTCI`0U/FO;3?&X]WF$ZVH85_^\"6&\n" 0532 "M@S%-\\$0FYOHX1Q6F+*!MRT]_ZYG/\"Z;9#CN3+>99AK,)6L\\K=CD@A.FE%WQY\n" 0533 "M[-3RXAK7;ZY3YSEU65`6<[+NA#3I<O+'%<88Z$[Q34-9Y>3YC%FVPW2Z1613\n" 0534 "M]HSV<77]E3\\\"K:@JLO]#*]W%X\\_W]]YS?[>_)XU=A#,6:P0DH-KB38;7G,CV\n" 0535 "MB;1+)%WBN$MD$U2$?+[57+OTTJLW7S_SI6I\\X8*H*K>(B`-&P'Y``.'_H[QE\n" 0536 ";$[@.>-WU'U(#IV=EWM`H`````$E%3D2N0F\"\"\n" 0537 "`\n" 0538 "end\n" 0539 "\n"; 0540 0541 auto msg = new Message(); 0542 msg->setContent(uuencodedMsg); 0543 msg->parse(); 0544 auto contents = msg->contents(); 0545 0546 // text + image 0547 QCOMPARE(contents.size(), 2); 0548 0549 Content *c = nullptr; 0550 0551 // Check the first text part 0552 c = contents.at(0); 0553 QVERIFY(c->contentType()->isPlainText()); 0554 QCOMPARE(c->body(), body); 0555 0556 // Check the image part 0557 c = contents.at(1); 0558 QVERIFY(!c->contentType()->isText()); 0559 QCOMPARE(c->contentType()->name(), imageName); 0560 // The uuencoded content as been recoded as base64 0561 QCOMPARE(c->encodedContent().data(), imageBase64.data()); 0562 0563 delete msg; 0564 } 0565 0566 void ContentTest::testParent() 0567 { 0568 auto c1 = new Content(); 0569 c1->contentType()->from7BitString("multipart/mixed"); 0570 0571 auto c2 = new Content(); 0572 c2->contentType()->from7BitString("text/plain"); 0573 c2->setBody("textpart"); 0574 0575 auto c3 = new Content(); 0576 c3->contentType()->from7BitString("text/html"); 0577 c3->setBody("htmlpart"); 0578 0579 auto c4 = new Content(); 0580 c4->contentType()->from7BitString("text/html"); 0581 c4->setBody("htmlpart2"); 0582 0583 auto c5 = new Content(); 0584 c5->contentType()->from7BitString("multipart/mixed"); 0585 0586 //c2 doesn't have a parent yet 0587 QCOMPARE(c2->parent(), (Content *)nullptr); 0588 0589 c1->appendContent(c2); 0590 c1->appendContent(c3); 0591 c1->appendContent(c4); 0592 QCOMPARE(c1->contents().size(), 3); 0593 0594 // c1 is the parent of those 0595 QCOMPARE(c2->parent(), c1); 0596 QCOMPARE(c3->parent(), c1); 0597 0598 //test removal 0599 c1->takeContent(c2); 0600 QCOMPARE(c2->parent(), (Content *)nullptr); 0601 QCOMPARE(c1->contents().at(0), c3); 0602 QCOMPARE(c1->contents().size(), 2); 0603 0604 //check if the content is moved correctly to another parent 0605 c5->appendContent(c4); 0606 QCOMPARE(c4->parent(), c5); 0607 QCOMPARE(c1->contents().size(), 1); 0608 QCOMPARE(c1->contents().at(0), c3); 0609 QCOMPARE(c5->contents().size(), 1); 0610 QCOMPARE(c5->contents().at(0), c4); 0611 0612 // example taken from RFC 2046, section 5.1.1. 0613 QByteArray data = 0614 "From: Nathaniel Borenstein <nsb@bellcore.com>\n" 0615 "To: Ned Freed <ned@innosoft.com>\n" 0616 "Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)\n" 0617 "Subject: Sample message\n" 0618 "MIME-Version: 1.0\n" 0619 "Content-type: multipart/mixed; boundary=\"simple boundary\"\n" 0620 "\n" 0621 "This is the preamble. It is to be ignored, though it\n" 0622 "is a handy place for composition agents to include an\n" 0623 "explanatory note to non-MIME conformant readers.\n" 0624 "\n" 0625 "--simple boundary\n" 0626 "\n" 0627 "This is implicitly typed plain US-ASCII text.\n" 0628 "It does NOT end with a linebreak.\n" 0629 "--simple boundary\n" 0630 "Content-type: text/plain; charset=us-ascii\n" 0631 "\n" 0632 "This is explicitly typed plain US-ASCII text.\n" 0633 "It DOES end with a linebreak.\n" 0634 "\n" 0635 "--simple boundary--\n" 0636 "\n" 0637 "This is the epilogue. It is also to be ignored.\n"; 0638 0639 // test parsing 0640 auto msg = new Message(); 0641 msg->setContent(data); 0642 msg->parse(); 0643 QCOMPARE(msg->parent(), (Content *)nullptr); 0644 QCOMPARE(msg->contents().at(0)->parent(), msg); 0645 QCOMPARE(msg->contents().at(1)->parent(), msg); 0646 delete msg; 0647 0648 delete c1; 0649 delete c2; 0650 delete c5; 0651 } 0652 0653 void ContentTest::testFreezing() 0654 { 0655 // Example taken from RFC 2046, section 5.1.1. 0656 QByteArray data = 0657 "From: Nathaniel Borenstein <nsb@bellcore.com>\n" 0658 "To: Ned Freed <ned@innosoft.com>\n" 0659 "Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)\n" 0660 "Subject: Sample message\n" 0661 "MIME-Version: 1.0\n" 0662 "Content-type: multipart/mixed; boundary=\"simple boundary\"\n" 0663 "\n" 0664 "This is the preamble. It is to be ignored, though it\n" 0665 "is a handy place for composition agents to include an\n" 0666 "explanatory note to non-MIME conformant readers.\n" 0667 "\n" 0668 "--simple boundary\n" 0669 "\n" 0670 "This is implicitly typed plain US-ASCII text.\n" 0671 "It does NOT end with a linebreak.\n" 0672 "--simple boundary\n" 0673 "Content-type: text/plain; charset=us-ascii\n" 0674 "\n" 0675 "This is explicitly typed plain US-ASCII text.\n" 0676 "It DOES end with a linebreak.\n" 0677 "\n" 0678 "--simple boundary--\n" 0679 "\n" 0680 "This is the epilogue. It is also to be ignored.\n"; 0681 0682 auto msg = new Message; 0683 msg->setContent(data); 0684 msg->setFrozen(true); 0685 0686 // The data should be untouched before parsing. 0687 //qDebug() << "original data" << data; 0688 //qDebug() << "data from message" << msg->encodedContent(); 0689 QCOMPARE(msg->encodedContent(), data); 0690 0691 // The data should remain untouched after parsing. 0692 msg->parse(); 0693 QVERIFY(msg->contentType()->isMultipart()); 0694 QCOMPARE(msg->contents().count(), 2); 0695 QCOMPARE(msg->encodedContent(), data); 0696 0697 // Calling assemble() should not alter the data. 0698 msg->assemble(); 0699 QCOMPARE(msg->encodedContent(), data); 0700 delete msg; 0701 } 0702 0703 void ContentTest::testContentTypeMimetype_data() 0704 { 0705 QTest::addColumn<QByteArray>("data"); 0706 QTest::addColumn<QByteArray>("mimetype"); 0707 QTest::addColumn<int>("contentCount"); 0708 QTest::addColumn<QList<QByteArray> >("contentMimeType"); 0709 QByteArray data = 0710 "From: Nathaniel Borenstein <nsb@bellcore.com>\n" 0711 "To: Ned Freed <ned@innosoft.com>\n" 0712 "Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)\n" 0713 "Subject: Sample message\n" 0714 "MIME-Version: 1.0\n" 0715 "Content-type: multipart/mixed; boundary=\"simple boundary\"\n" 0716 "\n" 0717 "This is the preamble. It is to be ignored, though it\n" 0718 "is a handy place for composition agents to include an\n" 0719 "explanatory note to non-MIME conformant readers.\n" 0720 "\n" 0721 "--simple boundary\n" 0722 "\n" 0723 "This is implicitly typed plain US-ASCII text.\n" 0724 "It does NOT end with a linebreak.\n" 0725 "--simple boundary\n" 0726 "Content-type: text/plain; charset=us-ascii\n" 0727 "\n" 0728 "This is explicitly typed plain US-ASCII text.\n" 0729 "It DOES end with a linebreak.\n" 0730 "\n" 0731 "--simple boundary--\n" 0732 "\n" 0733 "This is the epilogue. It is also to be ignored.\n"; 0734 0735 QList<QByteArray> contentMimes = { "text/plain", "text/plain"}; 0736 QTest::newRow("multipart") << data << QByteArrayLiteral("multipart/mixed") << 2 << contentMimes; 0737 0738 data = 0739 "From: Montel Laurent <null@kde.org>\n" 0740 "To: kde-commits@kde.org\n" 0741 "Content-Type: text/plain; charset=\"utf-8\"\n" 0742 "MIME-Version: 1.0\n" 0743 "Content-Transfer-Encoding: quoted-printable\n" 0744 "Subject: [libksieve] src/ksieveui: coding style\n" 0745 "Date: Tue, 30 May 2017 19:25:59 +0000\n" 0746 "\n" 0747 "Git commit 5410a2b3b6eef29ba32d0ac5e363fd38a56f535b by Montel Laurent.\n" 0748 "Committed on 30/05/2017 at 19:25.\n"; 0749 QTest::newRow("text/plain") << data << QByteArrayLiteral("text/plain") << 0 << QList<QByteArray>(); 0750 0751 data = 0752 "From: Montel Laurent <null@kde.org>\n" 0753 "To: kde-commits@kde.org\n" 0754 "Content-Type: %22%22%22%22%22%22%22%22%22%22%22%22%22%22%22%22=?windows-1252?q?ap%22/pdf;\n" 0755 "name=\"file.pdf\"\n" 0756 "MIME-Version: 1.0\n" 0757 "Content-Transfer-Encoding: quoted-printable\n" 0758 "Subject: [libksieve] src/ksieveui: coding style\n" 0759 "Date: Tue, 30 May 2017 19:25:59 +0000\n" 0760 "\n" 0761 "Git commit 5410a2b3b6eef29ba32d0ac5e363fd38a56f535b by Montel Laurent.\n" 0762 "Committed on 30/05/2017 at 19:25.\n"; 0763 QTest::newRow("broken") << data << QByteArrayLiteral("text/plain") << 0 << QList<QByteArray>(); 0764 0765 data = 0766 "From: Montel Laurent <null@kde.org>\n" 0767 "To: kde-commits@kde.org\n" 0768 "Content-Type: application/pdf;\n" 0769 "name=\"file.pdf\"\n" 0770 "MIME-Version: 1.0\n" 0771 "Content-Transfer-Encoding: quoted-printable\n" 0772 "Subject: [libksieve] src/ksieveui: coding style\n" 0773 "Date: Tue, 30 May 2017 19:25:59 +0000\n" 0774 "\n" 0775 "Git commit 5410a2b3b6eef29ba32d0ac5e363fd38a56f535b by Montel Laurent.\n" 0776 "Committed on 30/05/2017 at 19:25.\n"; 0777 QTest::newRow("not broken") << data << QByteArrayLiteral("application/pdf") << 0 << QList<QByteArray>(); 0778 0779 data = 0780 "From kde@kde.org Fri Jan 29 19:19:26 2010\n" 0781 "Return-Path: <kde@kde.org>\n" 0782 "Delivered-To: kde@kde.org\n" 0783 "Received: from localhost (localhost [127.0.0.1])\n" 0784 " by mail.kde.org (Postfix) with ESMTP id 8A6FF2B23D\n" 0785 " for <kde@kde.org>; Fri, 29 Jan 2010 19:19:27 +0100 (CET)\n" 0786 "From: KDE <kde@kde.org>\n" 0787 "To: kde@kde.org\n" 0788 "Subject: Attachment test Outlook\n" 0789 "Date: Fri, 29 Jan 2010 19:19:26 +0100\n" 0790 "User-Agent: KMail/1.13.0 (Linux/2.6.32-gentoo-r1; KDE/4.3.95; x86_64; ; )\n" 0791 "MIME-Version: 1.0\n" 0792 "Content-Type: Multipart/Mixed;\n" 0793 " boundary=\"Boundary-00=_uayYLfn6pjD7iFW\"\n" 0794 "Message-Id: <201001291919.26518.kde@kde.org>\n" 0795 "X-Length: 10467\n" 0796 "X-UID: 17\n" 0797 "\n" 0798 "--Boundary-00=_uayYLfn6pjD7iFW\n" 0799 "Content-Type: Text/Plain;\n" 0800 " charset=\"us-ascii\"\n" 0801 "Content-Transfer-Encoding: 7bit\n" 0802 "\n" 0803 "Attachment test Outlook\n" 0804 "\n" 0805 "--Boundary-00=_uayYLfn6pjD7iFW\n" 0806 "Content-Type: text/x-patch;\n" 0807 " charset=\"UTF-8\";\n" 0808 " name*=UTF-8''%C3%A5%2Ediff\n" 0809 "Content-Transfer-Encoding: 7bit\n" 0810 "Content-Disposition: attachment;\n" 0811 " filename=\"=?iso-8859-1?q?=E5=2Ediff?=\"\n" 0812 "\n" 0813 "Index: kmime/kmime_headers_p.h\n" 0814 "===================================================================\n" 0815 "--- kmime/kmime_headers_p.h (revision 1068282)\n" 0816 "+++ kmime/kmime_headers_p.h (working copy)\n" 0817 "@@ -170,6 +170,7 @@\n" 0818 " int lines;\n" 0819 " };\n" 0820 "\n" 0821 "+kmime_mk_empty_private( ContentID, Generics::SingleIdent )\n" 0822 " }\n" 0823 "\n" 0824 " }\n" 0825 "\n" 0826 "--Boundary-00=_uayYLfn6pjD7iFW--"; 0827 contentMimes = { "text/plain", "text/x-patch"}; 0828 QTest::newRow("example1") << data << QByteArrayLiteral("multipart/mixed") << 2 << contentMimes; 0829 } 0830 0831 0832 void ContentTest::testContentTypeMimetype() 0833 { 0834 QFETCH(QByteArray, data); 0835 QFETCH(QByteArray, mimetype); 0836 QFETCH(int, contentCount); 0837 QFETCH(QList<QByteArray> , contentMimeType); 0838 0839 // test parsing 0840 Message msg; 0841 msg.setContent(data); 0842 msg.parse(); 0843 //QEXPECT_FAIL("broken", "Problem with content type", Continue); 0844 QCOMPARE(msg.contentType(false)->mimeType(), mimetype); 0845 QCOMPARE(msg.contents().count(), contentCount); 0846 for (int i = 0; i < msg.contents().count(); ++i) { 0847 QVERIFY(msg.contents().at(i)->contentType(false)); 0848 QCOMPARE(contentMimeType.count(), contentCount); 0849 QCOMPARE(msg.contents().at(i)->contentType(false)->mimeType(), contentMimeType.at(i)); 0850 } 0851 } 0852 0853 #include "moc_contenttest.cpp"