File indexing completed on 2024-04-14 05:12:17

0001 /*
0002     SPDX-FileCopyrightText: 2006-2015 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #undef QT_USE_FAST_CONCATENATION
0008 #undef QT_USE_FAST_OPERATOR_PLUS
0009 
0010 #include <QTest>
0011 
0012 #include "attachmenttest.h"
0013 
0014 #include "kmime_util.h"
0015 #include "kmime_message.h"
0016 
0017 using namespace KMime;
0018 
0019 QTEST_MAIN(AttachmentTest)
0020 
0021 void AttachmentTest::testIsAttachment_data()
0022 {
0023     QTest::addColumn<QByteArray>("mimeType");
0024     QTest::addColumn<QString>("name");
0025     QTest::addColumn<QString>("fileName");
0026     QTest::addColumn<bool>("isAtt");
0027 
0028     QTest::newRow("empty") << QByteArray() << QString() << QString() << false;
0029     QTest::newRow("text part") << QByteArray("text/plain") << QString() << QString() << false;
0030     QTest::newRow("text part w/ CT name") << QByteArray("text/plain") << QStringLiteral("file.txt") << QString() << true;
0031     QTest::newRow("text part w/ CD name") << QByteArray("text/plain") << QString() << QStringLiteral("file.txt") << true;
0032 
0033     // multipart is never an attachment, even with a CD name
0034     QTest::newRow("multipart/mixed") << QByteArray("multipart/mixed") << QString() << QStringLiteral("file.txt") << false;
0035     QTest::newRow("multipart/mixed upper") << QByteArray("MULTIPART/MIXED") << QString() << QStringLiteral("file.txt") << false;
0036 
0037     // emails are always attachments, even without CT/CD names
0038     QTest::newRow("message/rfc822") <<  QByteArray("message/rfc822") << QString() << QString() << true;
0039 
0040     // crypto nodes, even when looking like attachments, are not attachments
0041     QTest::newRow("crypto part") << QByteArray("application/octet-stream") << QString() << QStringLiteral("msg.asc") << false;
0042 }
0043 
0044 void AttachmentTest::testIsAttachment()
0045 {
0046     QFETCH(QByteArray, mimeType);
0047     QFETCH(QString, name);
0048     QFETCH(QString, fileName);
0049     QFETCH(bool, isAtt);
0050 
0051     auto root = new KMime::Message;
0052     root->contentType()->from7BitString("multipart/mixed");
0053     root->contentTransferEncoding()->setEncoding(KMime::Headers::CE7Bit);
0054     auto c0 = new KMime::Content;
0055     root->appendContent(c0);
0056     auto c = new KMime::Content;
0057     root->appendContent(c);
0058     if (!mimeType.isEmpty()) {
0059         c->contentType()->setMimeType(mimeType);
0060     }
0061     if (!name.isEmpty()) {
0062         c->contentType()->setName(name, "utf-8");
0063     }
0064     if (!fileName.isEmpty()) {
0065         c->contentDisposition()->setFilename(fileName);
0066     }
0067     QCOMPARE(KMime::isAttachment(c), isAtt);
0068     QCOMPARE(KMime::hasAttachment(root), isAtt);
0069 
0070     if (isAtt) {
0071         QCOMPARE(root->attachments().size(), 1);
0072         QCOMPARE(root->attachments().at(0), c);
0073     } else {
0074         QVERIFY(root->attachments().isEmpty());
0075     }
0076     QVERIFY(c->attachments().isEmpty());
0077 
0078     delete root;
0079 }
0080 
0081 // stuff not covered above
0082 void AttachmentTest::testIsAttachmentSpecial()
0083 {
0084     // don't crash on invalid input
0085     QCOMPARE(KMime::isAttachment(nullptr), false);
0086     QCOMPARE(KMime::hasAttachment(nullptr), false);
0087 
0088     // disposition type "attachment" is a clear indicator...
0089     KMime::Content c;
0090     c.contentDisposition()->setDisposition(Headers::CDattachment);
0091     QCOMPARE(KMime::isAttachment(&c), true);
0092 }
0093 
0094 void AttachmentTest::testHasAttachment()
0095 {
0096     // multipart/related is not an attachment
0097     auto root = new KMime::Message;
0098     root->contentType()->setMimeType("multipart/related");
0099 
0100     auto c1 = new KMime::Content;
0101     c1->contentType()->setMimeType("text/plain");
0102     root->appendContent(c1);
0103 
0104     auto c2 = new KMime::Content;
0105     c2->contentType()->setMimeType("image/jpeg");
0106     c2->contentDisposition()->setFilename(QStringLiteral("image.jpg"));
0107     root->appendContent(c2);
0108 
0109     QCOMPARE(KMime::hasAttachment(root), false);
0110     QCOMPARE(root->attachments().size(), 0);
0111 
0112     // just to make sure this actually works for non multipart/related
0113     QCOMPARE(KMime::isAttachment(c2), true);
0114     root->contentType()->setMimeType("multipart/mixed");
0115     QCOMPARE(KMime::hasAttachment(root), true);
0116     QCOMPARE(root->attachments().size(), 1);
0117     QCOMPARE(root->attachments().at(0), c2);
0118     delete root;
0119 
0120     // multipart/alternative is also not an attachment
0121     root = new KMime::Message;
0122     root->contentType()->setMimeType("multipart/alternative");
0123 
0124     c1 = new KMime::Content;
0125     c1->contentType()->setMimeType("text/plain");
0126     root->appendContent(c1);
0127 
0128     c2 = new KMime::Content;
0129     c2->contentType()->setMimeType("text/html");
0130     root->appendContent(c2);
0131 
0132     QCOMPARE(KMime::hasAttachment(root), false);
0133     QCOMPARE(root->attachments().size(), 0);
0134     delete root;
0135 
0136     // the main part of multipart/mixed is not an attachment, even if it looks like one
0137     root = new KMime::Message;
0138     root->contentType()->from7BitString("multipart/mixed");
0139     root->contentTransferEncoding()->setEncoding(KMime::Headers::CE7Bit);
0140     auto c0 = new KMime::Content;
0141     root->appendContent(c0);
0142 
0143     c1 = new KMime::Content;
0144     c1->contentType()->setMimeType("text/plain");
0145     c1->contentType()->setName(QStringLiteral("file.txt"), "utf-8");
0146     root->prependContent(c1);
0147     QCOMPARE(KMime::isAttachment(c1), false);
0148     QCOMPARE(KMime::hasAttachment(c1), false);
0149     QCOMPARE(KMime::hasAttachment(root), false);
0150     QCOMPARE(root->attachments().size(), 0);
0151     delete root;
0152 }
0153 
0154 void AttachmentTest::testNestedMultipart()
0155 {
0156     auto root = new KMime::Message;
0157     root->contentType()->from7BitString("multipart/mixed");
0158     root->contentTransferEncoding()->setEncoding(KMime::Headers::CE7Bit);
0159     auto c0 = new KMime::Content;
0160     root->appendContent(c0);
0161 
0162     auto sig = new KMime::Content;
0163     sig->contentType()->setMimeType("application/pgp-signature");
0164     sig->contentType()->setName(QStringLiteral("signature.asc"), "utf-8");
0165     root->appendContent(sig);
0166     root->contentType()->setMimeType("multipart/signed");
0167 
0168     auto mixed = root->contents().at(0);
0169 
0170     auto att = new KMime::Content;
0171     att->contentType()->setMimeType("image/jpeg");
0172     att->contentType()->setName(QStringLiteral("attachment.jpg"), "utf-8");
0173     mixed->appendContent(att);
0174 
0175     mixed->contentType()->setMimeType("multipart/mixed");
0176 
0177     QVERIFY(KMime::hasAttachment(root));
0178     QVERIFY(KMime::hasAttachment(mixed));
0179     QCOMPARE(root->attachments().size(), 1);
0180     QCOMPARE(root->attachments().at(0), att);
0181 
0182     delete root;
0183 }
0184 
0185 void AttachmentTest::testEncrypted()
0186 {
0187     auto root = new KMime::Message;
0188     root->setContent(
0189         "From: firstname.lastname@example.com\n"
0190         "To: test@kolab.org\n"
0191         "Subject: OpenPGP encrypted with 2 text attachments\n"
0192         "Date: Sun, 30 Aug 2015 12:05:17 +0200\n"
0193         "Message-ID: <1505824.VT0nqpAGu0@vkpc5>\n"
0194         "MIME-Version: 1.0\n"
0195         "Content-Type: multipart/encrypted; boundary=\"nextPart3335835.KxmPgziKxd\"; protocol=\"application/pgp-encrypted\"\n"
0196         "\n"
0197         "--nextPart3335835.KxmPgziKxd\n"
0198         "Content-Type: application/pgp-encrypted\n"
0199         "Content-Disposition: attachment\n"
0200         "Content-Transfer-Encoding: 7Bit\n"
0201         "\n"
0202         "Version: 1\n"
0203         "--nextPart3335835.KxmPgziKxd\n"
0204         "Content-Type: application/octet-stream\n"
0205         "Content-Disposition: inline; filename=\"msg.asc\"\n"
0206         "Content-Transfer-Encoding: 7Bit\n"
0207         "\n"
0208         "-----BEGIN PGP MESSAGE-----\n"
0209         "-----END PGP MESSAGE-----\n"
0210         "\n"
0211         "--nextPart3335835.KxmPgziKxd--\n"
0212     );
0213     root->parse();
0214     QCOMPARE(hasAttachment(root), false);
0215     delete root;
0216 }
0217 
0218 void AttachmentTest::testAttachment1()
0219 {
0220     auto root = new KMime::Message;
0221     root->setContent("From: Sender <sender@test.org>\n"
0222                      "To: Receiver <receiver@test.org>\n"
0223                      "Subject: Test\n"
0224                      "Date: Thu, 19 Jul 2018 10:30:06 +0200\n"
0225                      "MIME-Version: 1.0\n"
0226                      "Content-Type: multipart/mixed; boundary=\"nextPart5103690.GVhdRC0Mqz\"\n"
0227                      "Content-Transfer-Encoding: 7Bit\n"
0228                      "\n"
0229                      "This is a multi-part message in MIME format.\n"
0230                      "\n"
0231                      "--nextPart5103690.GVhdRC0Mqz\n"
0232                      "Content-Transfer-Encoding: 7Bit\n"
0233                      "Content-Type: text/plain; charset=\"us-ascii\"\n"
0234                      "\n"
0235                      "Foo\n"
0236                      "\n"
0237                      "--nextPart5103690.GVhdRC0Mqz\n"
0238                      "Content-Disposition: attachment; filename=\"Screenshot_20180719_102529.png\"\n"
0239                      "Content-Transfer-Encoding: base64\n"
0240                      "Content-Type: image/png; name=\"Screenshot_20180719_102529.png\"\n"
0241                      "\n"
0242                      "ddd\n"
0243                      "\n"
0244                      "--nextPart5103690.GVhdRC0Mqz\n"
0245                      "Content-Disposition: attachment; filename=\"Screenshot_20180719_102550.png\"\n"
0246                      "Content-Transfer-Encoding: base64\n"
0247                      "Content-Type: image/png; name=\"Screenshot_20180719_102550.png\"\n"
0248                      "\n"
0249                      "zzzz\n"
0250                      "\n"
0251                      "--nextPart5103690.GVhdRC0Mqz--\n");
0252 
0253         root->parse();
0254         QCOMPARE(hasAttachment(root), true);
0255         delete root;
0256 }
0257 
0258 void AttachmentTest::testAttachment2()
0259 {
0260     auto root = new KMime::Message;
0261     root->setContent("From: Sender <sender@test.org>\n"
0262                      "Content-Type: multipart/alternative; boundary=\"Apple-Mail=_627B41D2-E6ED-4B17-8F96-6CD63EC055AE\"\n"
0263                      "MIME-Version: 1.0\n"
0264                      "Subject: Test\n"
0265                      "Date: Tue, 11 Dec 2018 10:44:41 +0000\n"
0266                      "To: Receiver <receiver@test.org>\n"
0267                      "\n"
0268                      "\n"
0269                      "\n"
0270                      "--Apple-Mail=_627B41D2-E6ED-4B17-8F96-6CD63EC055AE\n"
0271                      "Content-Transfer-Encoding: quoted-printable\n"
0272                      "Content-Type: text/plain; charset=\"us-ascii\"\n"
0273                      "\n"
0274                      "Text blabla\n"
0275                      "\n"
0276                      "--Apple-Mail=_627B41D2-E6ED-4B17-8F96-6CD63EC055AE\n"
0277                      "Content-Type: multipart/mixed; boundary=\"Apple-Mail=_5FDAE280-1EA6-4604-9F81-BBB9B9137CE1\"\n"
0278                      "\n"
0279                      "\n"
0280                      "--Apple-Mail=_5FDAE280-1EA6-4604-9F81-BBB9B9137CE1\n"
0281                      "Content-Transfer-Encoding: 7bit\n"
0282                      "Content-Type: text/html; charset=\"us-ascii\"\n"
0283                      "\n"
0284                      "<html><head><body>foo</body></html>\n"
0285                      "--Apple-Mail=_5FDAE280-1EA6-4604-9F81-BBB9B9137CE1\n"
0286                      "Content-Disposition: inline; filename=\"bla.pdf\"\n"
0287                      "Content-Type: application/pdf; name=\"bla.pdf\"; x-unix-mode=\"0644\"\n"
0288                      "Content-Transfer-Encoding: base64\n"
0289                      "\n"
0290                      "bla\n"
0291                      "\n"
0292                      "--Apple-Mail=_5FDAE280-1EA6-4604-9F81-BBB9B9137CE1\n"
0293                      "Content-Transfer-Encoding: quoted-printable\n"
0294                      "Content-Type: text/html; charset=\"us-ascii\"\n"
0295                      "\n"
0296                      "<html><body>foo html</body></html>=\n"
0297                      "\n"
0298                      "--Apple-Mail=_5FDAE280-1EA6-4604-9F81-BBB9B9137CE1--\n"
0299                      "\n"
0300                      "--Apple-Mail=_627B41D2-E6ED-4B17-8F96-6CD63EC055AE--\n");
0301 
0302         root->parse();
0303         //Fix show has attachment
0304         QCOMPARE(hasAttachment(root), true);
0305         delete root;
0306 }
0307 
0308 #include "moc_attachmenttest.cpp"