File indexing completed on 2024-04-28 09:12:06
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() && line != QLatin1String("body")); 0255 // The test should be (after the expected failure disappears): 0256 //QVERIFY( line.length() < 998 ); 0257 } 0258 delete msg; 0259 0260 } 0261 0262 void ContentTest::testDecodedContent() 0263 { 0264 auto c = new Content(); 0265 c->setBody("\0"); 0266 QVERIFY(c->decodedContent() == QByteArray()); 0267 c->setBody(QByteArray()); 0268 QVERIFY(c->decodedContent() == QByteArray()); 0269 c->setBody(" "); 0270 QVERIFY(c->decodedContent() == QByteArray(" ")); 0271 delete c; 0272 } 0273 0274 void ContentTest::testMultipleHeaderExtraction() 0275 { 0276 QByteArray data = 0277 "From: Nathaniel Borenstein <nsb@bellcore.com>\n" 0278 "To: Ned Freed <ned@innosoft.com>\n" 0279 "Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)\n" 0280 "Subject: Sample message\n" 0281 "Received: from ktown.kde.org ([192.168.100.1])\n" 0282 "Received: from dev1.kde.org ([192.168.100.2])\n" 0283 "\t by ktown.kde.org ([192.168.100.1])\n" 0284 "Received: from dev2.kde.org ([192.168.100.3])\n" 0285 " by ktown.kde.org ([192.168.100.1])\n"; 0286 0287 auto msg = new Message(); 0288 msg->setContent(data); 0289 // FAILS identically to ContentTest::testMultipartMixed 0290 // QCOMPARE( msg->encodedContent(), data ); 0291 msg->parse(); 0292 0293 auto result = msg->headersByType("Received"); 0294 QCOMPARE(result.count(), 3); 0295 QCOMPARE(result[0]->asUnicodeString(), QString::fromLatin1("from ktown.kde.org ([192.168.100.1])")); 0296 QCOMPARE(result[1]->asUnicodeString(), QString::fromLatin1("from dev1.kde.org ([192.168.100.2]) by ktown.kde.org ([192.168.100.1])")); 0297 QCOMPARE(result[2]->asUnicodeString(), QString::fromLatin1("from dev2.kde.org ([192.168.100.3]) by ktown.kde.org ([192.168.100.1])")); 0298 delete msg; 0299 } 0300 0301 void ContentTest::testMultipartMixed() 0302 { 0303 // example taken from RFC 2046, section 5.1.1. 0304 QByteArray data = 0305 "From: Nathaniel Borenstein <nsb@bellcore.com>\n" 0306 "To: Ned Freed <ned@innosoft.com>\n" 0307 "Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)\n" 0308 "Subject: Sample message\n" 0309 "MIME-Version: 1.0\n" 0310 "Content-type: multipart/mixed; boundary=\"simple boundary\"\n" 0311 "\n" 0312 "This is the preamble. It is to be ignored, though it\n" 0313 "is a handy place for composition agents to include an\n" 0314 "explanatory note to non-MIME conformant readers.\n" 0315 "\n" 0316 "--simple boundary\n" 0317 "\n" 0318 "This is implicitly typed plain US-ASCII text.\n" 0319 "It does NOT end with a linebreak.\n" 0320 "--simple boundary\n" 0321 "Content-type: text/plain; charset=us-ascii\n" 0322 "\n" 0323 "This is explicitly typed plain US-ASCII text.\n" 0324 "It DOES end with a linebreak.\n" 0325 "\n" 0326 "--simple boundary--\n" 0327 "\n" 0328 "This is the epilogue. It is also to be ignored.\n"; 0329 0330 QByteArray part1 = 0331 "This is implicitly typed plain US-ASCII text.\n" 0332 "It does NOT end with a linebreak."; 0333 0334 QByteArray part2 = 0335 "This is explicitly typed plain US-ASCII text.\n" 0336 "It DOES end with a linebreak.\n"; 0337 0338 // What we expect KMime to parse the above data into. 0339 QByteArray parsedWithPreambleAndEpilogue = 0340 "From: Nathaniel Borenstein <nsb@bellcore.com>\n" 0341 "To: Ned Freed <ned@innosoft.com>\n" 0342 "Date: Sun, 21 Mar 1993 23:56:48 -0800\n" 0343 "Subject: Sample message\n" 0344 "MIME-Version: 1.0\n" 0345 "Content-Type: multipart/mixed; boundary=\"simple boundary\"\n" 0346 "\n" 0347 "This is the preamble. It is to be ignored, though it\n" 0348 "is a handy place for composition agents to include an\n" 0349 "explanatory note to non-MIME conformant readers.\n" 0350 "\n" 0351 "--simple boundary\n" 0352 "Content-Type: text/plain; charset=\"us-ascii\"\n\n" 0353 "This is implicitly typed plain US-ASCII text.\n" 0354 "It does NOT end with a linebreak.\n" 0355 "--simple boundary\n" 0356 "Content-Type: text/plain; charset=\"us-ascii\"\n" 0357 "\n" 0358 "This is explicitly typed plain US-ASCII text.\n" 0359 "It DOES end with a linebreak.\n" 0360 "\n" 0361 "--simple boundary--\n" 0362 "\n" 0363 "This is the epilogue. It is also to be ignored.\n"; 0364 0365 // What we expect KMime to assemble the above data into. 0366 QByteArray assembled = 0367 "From: Nathaniel Borenstein <nsb@bellcore.com>\n" 0368 "To: Ned Freed <ned@innosoft.com>\n" 0369 "Date: Sun, 21 Mar 1993 23:56:48 -0800\n" 0370 "Subject: Sample message\n" 0371 "MIME-Version: 1.0\n" 0372 "Content-Type: multipart/mixed; boundary=\"simple boundary\"\n" 0373 "Content-Transfer-Encoding: 7Bit\n" 0374 "\n" 0375 "--simple boundary\n" 0376 "\n" 0377 "This is implicitly typed plain US-ASCII text.\n" 0378 "It does NOT end with a linebreak.\n" 0379 "--simple boundary\n" 0380 "Content-Type: text/plain; charset=\"us-ascii\"\n" 0381 "\n" 0382 "This is explicitly typed plain US-ASCII text.\n" 0383 "It DOES end with a linebreak.\n" 0384 "\n" 0385 "--simple boundary--\n"; 0386 0387 // test parsing 0388 auto msg = new Message(); 0389 msg->setContent(data); 0390 QCOMPARE(msg->encodedContent(), data); 0391 msg->parse(); 0392 QVERIFY(msg->contentType()->isMultipart()); 0393 0394 auto list = msg->contents(); 0395 QCOMPARE(list.count(), 2); 0396 Content *c = list.takeFirst(); 0397 QCOMPARE(c->body(), part1); 0398 c = list.takeFirst(); 0399 QCOMPARE(c->body(), part2); 0400 0401 // assemble again 0402 msg->assemble(); 0403 //qDebug() << "expected assembled content" << parsedWithPreambleAndEpilogue; 0404 //qDebug() << "actual new encoded content" << msg->encodedContent(); 0405 QCOMPARE(msg->encodedContent(), parsedWithPreambleAndEpilogue); 0406 delete msg; 0407 0408 // assembling from scratch 0409 // (The headers have to be in the same order, as we compare with the above assembled.) 0410 msg = new Message(); 0411 msg->from()->from7BitString("Nathaniel Borenstein <nsb@bellcore.com>"); 0412 msg->to()->from7BitString("Ned Freed <ned@innosoft.com>"); 0413 msg->date()->from7BitString("Sun, 21 Mar 1993 23:56:48 -0800 (PST)"); 0414 msg->subject()->from7BitString("Sample message"); 0415 // HACK to make MIME-Version appear before Content-Type, as in the expected message. 0416 auto header = new Headers::MIMEVersion; 0417 header->from7BitString("1.234"); 0418 msg->setHeader(header); 0419 msg->contentType()->from7BitString("multipart/mixed"); 0420 msg->contentTransferEncoding()->setEncoding(KMime::Headers::CE7Bit); 0421 0422 c = new Content(); 0423 c->setBody(part1); 0424 msg->appendContent(c); 0425 0426 c = new Content(); 0427 c->setBody(part2); 0428 c->contentType()->setMimeType("text/plain"); 0429 c->contentType()->setCharset("us-ascii"); 0430 msg->appendContent(c); 0431 msg->contentType()->setBoundary("simple boundary"); 0432 0433 list = msg->contents(); 0434 QCOMPARE(list.count(), 2); 0435 c = list.takeFirst(); 0436 QCOMPARE(c->body(), part1); 0437 c = list.takeFirst(); 0438 QCOMPARE(c->body(), part2); 0439 0440 msg->assemble(); 0441 //QByteArray encc = msg->encodedContent(); 0442 //qDebug().noquote() << "expected assembled content" << assembled; 0443 //qDebug().noquote() << "actual encoded content" << encc; 0444 QCOMPARE(msg->encodedContent(), assembled); 0445 delete msg; 0446 } 0447 0448 void ContentTest::testParsingUuencoded() 0449 { 0450 const QByteArray body = 0451 "This is a test message that should appears as a text/plain part\n" 0452 "once this message is parsed and convert to a MIME tree.\n" 0453 "\n" 0454 "\n"; 0455 0456 const QString imageName = QStringLiteral("Name of the encoded file (oxygen 22x22 kde.png)"); 0457 const QByteArray imageBase64 = 0458 "\n" 0459 "iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\n" 0460 "AAADdgAAA3YBfdWCzAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAU4SURB\n" 0461 "VBgZjcFbiF1XGcDx/7fW2pdznTOXNJlJc4WWVK3RqiC2FOyTiGCs+lKkohWTIl5QWrAp9ckLKpYi\n" 0462 "KFjwodgXoRDMk1VECj7UpkIqUZuCTUycyWXOzJxz9tnXtdfnxNqnvvj7iaryNhGxgPBOAh/gLa+y\n" 0463 "S3kn3dXyP6KqyEe+1Rm6tSc6nYVHO+loOXYR1hisFYRAIOBljtecyPaItEMkXeK4S2QTVAxVOZ1t\n" 0464 "TzaeG6//9fTWuR9MnOxyx7/xzaWjB548cvgAUeyJbGDYj9mzPGJl1GdpocOwlxCCMs1qtrKSrZ2c\n" 0465 "ze0Z126O2ZkWSJoO0rDylUabREROOsCoG3z58JEDrK4NIFQMBz0WBl2G3ZReGiNi+debO6gKC3sH\n" 0466 "DAcxNu6QpF1GiwtsTzMm04wrVyeY7upngEcdYIy4pSgVJtmMYb+HmBiVGE9Eo47ZdsHJj3eJnOHp\n" 0467 "M3P6exbIJxmffr/ibMK58zN+M4nwlGCTPmAMu8QYKasCFYd1CWoSgkT4YGmCoWggTRLiOKH0UFTK\n" 0468 "A8csdx0ZcnBfl/PXIuJ+j253gBED3CEGDluxVtqgGBcTJCKIZboxJq9bssozLxqiKMJZS1G3LIct\n" 0469 "7nvfAs5FvPDSjHlnEbER3f4AsUZYG1rD2t3GGIu4GIhosUSzCd9/5HZOvKtldnmd7evbRM7hnEOz\n" 0470 "CV/8xCrOWv52qeKVGx0CBpUIF3cwxsLwdmtYPGSMtaLW0WIIKuStIXLCh9+9wE++fgfWV4jwX489\n" 0471 "fJQkMswr5ee/26EMgaaFVoW6VsRaGXWWrFnqWyPWSV0rrULlA7M45dd/uEHZwOlfvMGW6yAiiAhr\n" 0472 "KwkgGIEiL8jrmryuqWpPWbWItYTlNWvauGeNs8xLT9W2FFXDdGPMwb0pz569wsUqpqgbQADhmecu\n" 0473 "IgK91HHqY7cxz0um85zxrKAVMNYSbGKNtqkIhtB6xptTvntiyJnv3MVH71niT3+fUHvQ1vC2F1+v\n" 0474 "efHPm9xy33sXubtXsj3NaJqKNjSA0KePEVsqKEE9dZWTOBCUtg1sZoamhrYFVQWUphV+dPYml67l\n" 0475 "3PLtz99Jr8zxdYn3NSJKRoYxhQZ2+aZCteWhZy7yydOvceHNOXeuWNRbQmMIIaCqGGJcOuL0s5fJ\n" 0476 "S8+gY3j8U4fQ2hPqEg0BqQnCsUcGg7XjNxZXV1MbJQx6I1ZW9vPge4QHPrjM47/cwXZ6VFmBaEsy\n" 0477 "6GPqgqEtqJqWsmq4OpmT+Sl1XTHdHIemeG3ZML3RBu+1rkp8mROahqiYceL+RQ7eZvnewwusyoRh\n" 0478 "f8hgtMywmfPUQ0Oe+sI+WlJ0tIrrJjR1SdMUBO/Z2fhn61g/68PRe7UqC4JraDo1h3oVsW1440rD\n" 0479 "718uOfXgiL1LEIKiOsI5IY0CT36uzxO/KvF1TV3MqX1D8F6Z/8U7QEPr1WCpyzlVVXJuo+WrP7xE\n" 0480 "ke5neeUA55+/ytNfSxAnPPazEnVdPntvweV/52R5oK4KqiqnqhtQr1y50jpAQ1PmvbTfG493mE62\n" 0481 "oYV/+CWGgzFN8EQm5vo4RxWmLKBty09/65nPC6bZDjuTLeZZhrMJWs8rdjkghOmlF3x57NTy4hrX\n" 0482 "b65T5zl1WVAWc7LuhDTpcvLHFcYY6E7xTUNZ5eT5jFm2w3S6RWRT9oz2cXX9lT8Cragqsv9DK93F\n" 0483 "48/3995zf7e/J41dhDMWawQkoNriTYbXnMj2ibRLJF3iuEtkE1SEfL7VXLv00qs3Xz/zpWp84YKo\n" 0484 "KreIiANGwH5AAOH/o7xlE7gOeN31H1IDp2dl3tAoAAAAAElFTkSuQmCC\n" 0485 ; 0486 0487 const QByteArray uuencodedMsg = 0488 "Path: news.example.net!not-for-mail\n" 0489 "From: Coin coin <meuh@example.net>\n" 0490 "Newsgroups: test.kmime.uuencoded\n" 0491 "Subject: Kmime test\n" 0492 "Date: Thu, 14 Apr 2005 20:12:47 -0700\n" 0493 "Message-ID: <xxxxxxxxxxxxxxxxxx@xxxxx.kmime.example.net>\n" 0494 "X-Newsreader: Forte Agent 2.0/32.640\n" 0495 "Lines: 1283\n" 0496 "Organization: Ament\n" 0497 "Xref: news.example.net test.kmime.uuencoded:4584\n" 0498 "\n" 0499 "This is a test message that should appears as a text/plain part\n" 0500 "once this message is parsed and convert to a MIME tree.\n" 0501 "\n" 0502 "begin 644 Name of the encoded file (oxygen 22x22 kde.png)\n" 0503 "MB5!.1PT*&@H````-24A$4@```!8````6\"`8```#$M&P[````!'-\"250(\"`@(\n" 0504 "M?`ADB`````EP2%ES```#=@```W8!?=6\"S````!ET15AT4V]F='=A<F4`=W=W\n" 0505 "M+FEN:W-C87!E+F]R9YON/!H```4X241!5!@9C<%;B%U7&<#Q_[?6VI=SG3.7\n" 0506 "M-)E)<X665*W1JB\"V%.R3B&\"L^E*DHA63(EY06K`I]<D+*I8B*%CPH=@7H1#,\n" 0507 "MDU5$\"C[4ID(J49N\"34R<R67.S)QS]MG7M=?GQ-JGOOC[B:KR-A&Q@/!.`A_@\n" 0508 "M+:^R2WDGW=7R/Z*JR$>^U1FZM2<ZG85'.^EH.781UABL%81`(.!ECM><R/:(\n" 0509 "MM$,D7>*X2V035`Q5.9UM3S:>&Z__]?36N1],G.QRQ[_QS:6C!YX\\<O@`4>R)\n" 0510 "M;C]FS/&)EU&=IH<.PEQ\"\",LUJMK*2K9V<S>T9UVZ.V9D62)H.TK#RE4:;\n" 0511 "M1$1..L\"H&WSY\\)$#K*X-(%0,!ST6!EV&W91>&B-B^=>;.Z@*\"WL'#`<Q-NZ0\n" 0512 "MI%U&BPML3S,FTXPK5R>8[NIG@$<=8(RXI2@5)MF,8;^'F!B5&$]$HX[9=L')\n" 0513 "MCW>)G.'I,W/Z>Q;()QF??K_B;,*Y\\S-^,XGPE&\"3/F`,N\\08*:L\"%8=U\"6H2\n" 0514 "M@D3X8&F\"H6@@31+B.*'T4%3*`\\<L=QT9<G!?E_/7(N)^CVYW@!$#W\"$&#ENQ\n" 0515 "M5MJ@&!<3)\"*(9;HQ)J];LLHS+QJB*,)92U&W+(<M[GO?`LY%O/#2C'EG$;$1\n" 0516 "MW?X`L498&UK#VMW&&(NX&(AHL42S\"=]_Y'9.O*ME=GF=[>O;1,[AG$.S\"5_\\\n" 0517 "MQ\"K.6OYVJ>*5&QT\"!I4(%W<PQL+P=FM8/&2,M:+6T6((*N2M(7+\"A]^]P$^^\n" 0518 "M?@?65XCP7X\\]?)0D,LPKY>>_VZ$,@::%5H6Z5L1:&766K%GJ6R/625TKK4+E\n" 0519 "M`[,XY==_N$'9P.E?O,&6ZR`BB`AK*PD@&($B+\\CKFKRNJ6I/6;6(M83E-6O:\n" 0520 "MN&>-L\\Q+3]6V%%7#=&/,P;TISYZ]PL4JIJ@;0`#AF><N(@*]U''J8[<QSTNF\n" 0521 "M\\YSQK*`5,-82;&*-MJD(AM!ZQIM3OGMBR)GOW,5'[UGB3W^?4'O0UO\"V%U^O\n" 0522 "M>?'/F]QRWWL7N;M7LCW-:)J*-C2`T*>/$5LJ*$$]=963.!\"4M@UL9H:FAK8%\n" 0523 "M5064IA5^=/8FEZ[EW/+MS]])K\\SQ=8GW-2)*1H8QA09V^:9\"M>6A9R[RR=.O\n" 0524 "M<>'-.7>N6-1;0F,((:\"J&&)<.N+TLY?)2\\^@8WC\\4X?0VA/J$@T!J0G\"L4<&\n" 0525 "M@[7C-Q975U,;)0QZ(U96]O/@>X0'/KC,X[_<P79Z5%F!:$LRZ&/J@J$MJ)J6\n" 0526 "MLFJX.IF3^2EU73'='(>F>&W9,+W1!N^UKDI\\F1.:AJB8<>+^10[>9OG>PPNL\n" 0527 "MRH1A?\\A@M,RPF?/40T.>^L(^6E)TM(KK)C1U2=,4!._9V?AGZU@_Z\\/1>[4J\n" 0528 "M\"X)K:#HUAWH5L6UXXTK#[U\\N.?7@B+U+$(*B.L(Y(8T\"3WZNSQ._*O%U35W,\n" 0529 "MJ7U#\\%Z9_\\4[0$/KU6\"IRSE557)NH^6K/[Q$D>YG>>4`YY^_RM-?2Q`G//:S\n" 0530 "M$G5=/GMOP>5_YV1YH*X*JBJGJAM0KURYTCI`0U/FO;3?&X]WF$ZVH85_^\"6&\n" 0531 "M@S%-\\$0FYOHX1Q6F+*!MRT]_ZYG/\"Z;9#CN3+>99AK,)6L\\K=CD@A.FE%WQY\n" 0532 "M[-3RXAK7;ZY3YSEU65`6<[+NA#3I<O+'%<88Z$[Q34-9Y>3YC%FVPW2Z1613\n" 0533 "M]HSV<77]E3\\\"K:@JLO]#*]W%X\\_W]]YS?[>_)XU=A#,6:P0DH-KB38;7G,CV\n" 0534 "MB;1+)%WBN$MD$U2$?+[57+OTTJLW7S_SI6I\\X8*H*K>(B`-&P'Y``.'_H[QE\n" 0535 ";$[@.>-WU'U(#IV=EWM`H`````$E%3D2N0F\"\"\n" 0536 "`\n" 0537 "end\n" 0538 "\n"; 0539 0540 auto msg = new Message(); 0541 msg->setContent(uuencodedMsg); 0542 msg->parse(); 0543 auto contents = msg->contents(); 0544 0545 // text + image 0546 QCOMPARE(contents.size(), 2); 0547 0548 Content *c = nullptr; 0549 0550 // Check the first text part 0551 c = contents.at(0); 0552 QVERIFY(c->contentType()->isPlainText()); 0553 QCOMPARE(c->body(), body); 0554 0555 // Check the image part 0556 c = contents.at(1); 0557 QVERIFY(!c->contentType()->isText()); 0558 QCOMPARE(c->contentType()->name(), imageName); 0559 // The uuencoded content as been recoded as base64 0560 QCOMPARE(c->encodedContent().data(), imageBase64.data()); 0561 0562 delete msg; 0563 } 0564 0565 void ContentTest::testParent() 0566 { 0567 auto c1 = new Content(); 0568 c1->contentType()->from7BitString("multipart/mixed"); 0569 0570 auto c2 = new Content(); 0571 c2->contentType()->from7BitString("text/plain"); 0572 c2->setBody("textpart"); 0573 0574 auto c3 = new Content(); 0575 c3->contentType()->from7BitString("text/html"); 0576 c3->setBody("htmlpart"); 0577 0578 auto c4 = new Content(); 0579 c4->contentType()->from7BitString("text/html"); 0580 c4->setBody("htmlpart2"); 0581 0582 auto c5 = new Content(); 0583 c5->contentType()->from7BitString("multipart/mixed"); 0584 0585 //c2 doesn't have a parent yet 0586 QCOMPARE(c2->parent(), (Content *)nullptr); 0587 0588 c1->appendContent(c2); 0589 c1->appendContent(c3); 0590 c1->appendContent(c4); 0591 QCOMPARE(c1->contents().size(), 3); 0592 0593 // c1 is the parent of those 0594 QCOMPARE(c2->parent(), c1); 0595 QCOMPARE(c3->parent(), c1); 0596 0597 //test removal 0598 c1->takeContent(c2); 0599 QCOMPARE(c2->parent(), (Content *)nullptr); 0600 QCOMPARE(c1->contents().at(0), c3); 0601 QCOMPARE(c1->contents().size(), 2); 0602 0603 //check if the content is moved correctly to another parent 0604 c5->appendContent(c4); 0605 QCOMPARE(c4->parent(), c5); 0606 QCOMPARE(c1->contents().size(), 1); 0607 QCOMPARE(c1->contents().at(0), c3); 0608 QCOMPARE(c5->contents().size(), 1); 0609 QCOMPARE(c5->contents().at(0), c4); 0610 0611 // example taken from RFC 2046, section 5.1.1. 0612 QByteArray data = 0613 "From: Nathaniel Borenstein <nsb@bellcore.com>\n" 0614 "To: Ned Freed <ned@innosoft.com>\n" 0615 "Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)\n" 0616 "Subject: Sample message\n" 0617 "MIME-Version: 1.0\n" 0618 "Content-type: multipart/mixed; boundary=\"simple boundary\"\n" 0619 "\n" 0620 "This is the preamble. It is to be ignored, though it\n" 0621 "is a handy place for composition agents to include an\n" 0622 "explanatory note to non-MIME conformant readers.\n" 0623 "\n" 0624 "--simple boundary\n" 0625 "\n" 0626 "This is implicitly typed plain US-ASCII text.\n" 0627 "It does NOT end with a linebreak.\n" 0628 "--simple boundary\n" 0629 "Content-type: text/plain; charset=us-ascii\n" 0630 "\n" 0631 "This is explicitly typed plain US-ASCII text.\n" 0632 "It DOES end with a linebreak.\n" 0633 "\n" 0634 "--simple boundary--\n" 0635 "\n" 0636 "This is the epilogue. It is also to be ignored.\n"; 0637 0638 // test parsing 0639 auto msg = new Message(); 0640 msg->setContent(data); 0641 msg->parse(); 0642 QCOMPARE(msg->parent(), (Content *)nullptr); 0643 QCOMPARE(msg->contents().at(0)->parent(), msg); 0644 QCOMPARE(msg->contents().at(1)->parent(), msg); 0645 delete msg; 0646 0647 delete c1; 0648 delete c2; 0649 delete c5; 0650 } 0651 0652 void ContentTest::testFreezing() 0653 { 0654 // Example taken from RFC 2046, section 5.1.1. 0655 QByteArray data = 0656 "From: Nathaniel Borenstein <nsb@bellcore.com>\n" 0657 "To: Ned Freed <ned@innosoft.com>\n" 0658 "Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)\n" 0659 "Subject: Sample message\n" 0660 "MIME-Version: 1.0\n" 0661 "Content-type: multipart/mixed; boundary=\"simple boundary\"\n" 0662 "\n" 0663 "This is the preamble. It is to be ignored, though it\n" 0664 "is a handy place for composition agents to include an\n" 0665 "explanatory note to non-MIME conformant readers.\n" 0666 "\n" 0667 "--simple boundary\n" 0668 "\n" 0669 "This is implicitly typed plain US-ASCII text.\n" 0670 "It does NOT end with a linebreak.\n" 0671 "--simple boundary\n" 0672 "Content-type: text/plain; charset=us-ascii\n" 0673 "\n" 0674 "This is explicitly typed plain US-ASCII text.\n" 0675 "It DOES end with a linebreak.\n" 0676 "\n" 0677 "--simple boundary--\n" 0678 "\n" 0679 "This is the epilogue. It is also to be ignored.\n"; 0680 0681 auto msg = new Message; 0682 msg->setContent(data); 0683 msg->setFrozen(true); 0684 0685 // The data should be untouched before parsing. 0686 //qDebug() << "original data" << data; 0687 //qDebug() << "data from message" << msg->encodedContent(); 0688 QCOMPARE(msg->encodedContent(), data); 0689 0690 // The data should remain untouched after parsing. 0691 msg->parse(); 0692 QVERIFY(msg->contentType()->isMultipart()); 0693 QCOMPARE(msg->contents().count(), 2); 0694 QCOMPARE(msg->encodedContent(), data); 0695 0696 // Calling assemble() should not alter the data. 0697 msg->assemble(); 0698 QCOMPARE(msg->encodedContent(), data); 0699 delete msg; 0700 } 0701 0702 void ContentTest::testContentTypeMimetype_data() 0703 { 0704 QTest::addColumn<QByteArray>("data"); 0705 QTest::addColumn<QByteArray>("mimetype"); 0706 QTest::addColumn<int>("contentCount"); 0707 QTest::addColumn<QList<QByteArray> >("contentMimeType"); 0708 QByteArray data = 0709 "From: Nathaniel Borenstein <nsb@bellcore.com>\n" 0710 "To: Ned Freed <ned@innosoft.com>\n" 0711 "Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)\n" 0712 "Subject: Sample message\n" 0713 "MIME-Version: 1.0\n" 0714 "Content-type: multipart/mixed; boundary=\"simple boundary\"\n" 0715 "\n" 0716 "This is the preamble. It is to be ignored, though it\n" 0717 "is a handy place for composition agents to include an\n" 0718 "explanatory note to non-MIME conformant readers.\n" 0719 "\n" 0720 "--simple boundary\n" 0721 "\n" 0722 "This is implicitly typed plain US-ASCII text.\n" 0723 "It does NOT end with a linebreak.\n" 0724 "--simple boundary\n" 0725 "Content-type: text/plain; charset=us-ascii\n" 0726 "\n" 0727 "This is explicitly typed plain US-ASCII text.\n" 0728 "It DOES end with a linebreak.\n" 0729 "\n" 0730 "--simple boundary--\n" 0731 "\n" 0732 "This is the epilogue. It is also to be ignored.\n"; 0733 0734 QList<QByteArray> contentMimes = { "text/plain", "text/plain"}; 0735 QTest::newRow("multipart") << data << QByteArrayLiteral("multipart/mixed") << 2 << contentMimes; 0736 0737 data = 0738 "From: Montel Laurent <null@kde.org>\n" 0739 "To: kde-commits@kde.org\n" 0740 "Content-Type: text/plain; charset=\"utf-8\"\n" 0741 "MIME-Version: 1.0\n" 0742 "Content-Transfer-Encoding: quoted-printable\n" 0743 "Subject: [libksieve] src/ksieveui: coding style\n" 0744 "Date: Tue, 30 May 2017 19:25:59 +0000\n" 0745 "\n" 0746 "Git commit 5410a2b3b6eef29ba32d0ac5e363fd38a56f535b by Montel Laurent.\n" 0747 "Committed on 30/05/2017 at 19:25.\n"; 0748 QTest::newRow("text/plain") << data << QByteArrayLiteral("text/plain") << 0 << QList<QByteArray>(); 0749 0750 data = 0751 "From: Montel Laurent <null@kde.org>\n" 0752 "To: kde-commits@kde.org\n" 0753 "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" 0754 "name=\"file.pdf\"\n" 0755 "MIME-Version: 1.0\n" 0756 "Content-Transfer-Encoding: quoted-printable\n" 0757 "Subject: [libksieve] src/ksieveui: coding style\n" 0758 "Date: Tue, 30 May 2017 19:25:59 +0000\n" 0759 "\n" 0760 "Git commit 5410a2b3b6eef29ba32d0ac5e363fd38a56f535b by Montel Laurent.\n" 0761 "Committed on 30/05/2017 at 19:25.\n"; 0762 QTest::newRow("broken") << data << QByteArrayLiteral("text/plain") << 0 << QList<QByteArray>(); 0763 0764 data = 0765 "From: Montel Laurent <null@kde.org>\n" 0766 "To: kde-commits@kde.org\n" 0767 "Content-Type: application/pdf;\n" 0768 "name=\"file.pdf\"\n" 0769 "MIME-Version: 1.0\n" 0770 "Content-Transfer-Encoding: quoted-printable\n" 0771 "Subject: [libksieve] src/ksieveui: coding style\n" 0772 "Date: Tue, 30 May 2017 19:25:59 +0000\n" 0773 "\n" 0774 "Git commit 5410a2b3b6eef29ba32d0ac5e363fd38a56f535b by Montel Laurent.\n" 0775 "Committed on 30/05/2017 at 19:25.\n"; 0776 QTest::newRow("not broken") << data << QByteArrayLiteral("application/pdf") << 0 << QList<QByteArray>(); 0777 0778 data = 0779 "From kde@kde.org Fri Jan 29 19:19:26 2010\n" 0780 "Return-Path: <kde@kde.org>\n" 0781 "Delivered-To: kde@kde.org\n" 0782 "Received: from localhost (localhost [127.0.0.1])\n" 0783 " by mail.kde.org (Postfix) with ESMTP id 8A6FF2B23D\n" 0784 " for <kde@kde.org>; Fri, 29 Jan 2010 19:19:27 +0100 (CET)\n" 0785 "From: KDE <kde@kde.org>\n" 0786 "To: kde@kde.org\n" 0787 "Subject: Attachment test Outlook\n" 0788 "Date: Fri, 29 Jan 2010 19:19:26 +0100\n" 0789 "User-Agent: KMail/1.13.0 (Linux/2.6.32-gentoo-r1; KDE/4.3.95; x86_64; ; )\n" 0790 "MIME-Version: 1.0\n" 0791 "Content-Type: Multipart/Mixed;\n" 0792 " boundary=\"Boundary-00=_uayYLfn6pjD7iFW\"\n" 0793 "Message-Id: <201001291919.26518.kde@kde.org>\n" 0794 "X-Length: 10467\n" 0795 "X-UID: 17\n" 0796 "\n" 0797 "--Boundary-00=_uayYLfn6pjD7iFW\n" 0798 "Content-Type: Text/Plain;\n" 0799 " charset=\"us-ascii\"\n" 0800 "Content-Transfer-Encoding: 7bit\n" 0801 "\n" 0802 "Attachment test Outlook\n" 0803 "\n" 0804 "--Boundary-00=_uayYLfn6pjD7iFW\n" 0805 "Content-Type: text/x-patch;\n" 0806 " charset=\"UTF-8\";\n" 0807 " name*=UTF-8''%C3%A5%2Ediff\n" 0808 "Content-Transfer-Encoding: 7bit\n" 0809 "Content-Disposition: attachment;\n" 0810 " filename=\"=?iso-8859-1?q?=E5=2Ediff?=\"\n" 0811 "\n" 0812 "Index: kmime/kmime_headers_p.h\n" 0813 "===================================================================\n" 0814 "--- kmime/kmime_headers_p.h (revision 1068282)\n" 0815 "+++ kmime/kmime_headers_p.h (working copy)\n" 0816 "@@ -170,6 +170,7 @@\n" 0817 " int lines;\n" 0818 " };\n" 0819 "\n" 0820 "+kmime_mk_empty_private( ContentID, Generics::SingleIdent )\n" 0821 " }\n" 0822 "\n" 0823 " }\n" 0824 "\n" 0825 "--Boundary-00=_uayYLfn6pjD7iFW--"; 0826 contentMimes = { "text/plain", "text/x-patch"}; 0827 QTest::newRow("example1") << data << QByteArrayLiteral("multipart/mixed") << 2 << contentMimes; 0828 } 0829 0830 0831 void ContentTest::testContentTypeMimetype() 0832 { 0833 QFETCH(QByteArray, data); 0834 QFETCH(QByteArray, mimetype); 0835 QFETCH(int, contentCount); 0836 QFETCH(QList<QByteArray> , contentMimeType); 0837 0838 // test parsing 0839 Message msg; 0840 msg.setContent(data); 0841 msg.parse(); 0842 //QEXPECT_FAIL("broken", "Problem with content type", Continue); 0843 QCOMPARE(msg.contentType(false)->mimeType(), mimetype); 0844 QCOMPARE(msg.contents().count(), contentCount); 0845 for (int i = 0; i < msg.contents().count(); ++i) { 0846 QVERIFY(msg.contents().at(i)->contentType(false)); 0847 QCOMPARE(contentMimeType.count(), contentCount); 0848 QCOMPARE(msg.contents().at(i)->contentType(false)->mimeType(), contentMimeType.at(i)); 0849 } 0850 } 0851 0852 #include "moc_contenttest.cpp"