File indexing completed on 2024-12-22 05:07:43
0001 // SPDX-FileCopyrightText: 2017 Christian Mollekopf <mollekopf@kolabsys.com> 0002 // SPDX-License-Identifier: GPL-2.0-or-later 0003 0004 #include <QDebug> 0005 #include <QDir> 0006 #include <QSignalSpy> 0007 #include <QStandardPaths> 0008 #include <QTest> 0009 #include <functional> 0010 0011 #include "../mailcrypto.h" 0012 #include "../mailtemplates.h" 0013 0014 static KMime::Content *getSubpart(KMime::Content *msg, const QByteArray &mimeType) 0015 { 0016 for (const auto c : msg->contents()) { 0017 if (c->contentType(false)->mimeType() == mimeType) { 0018 return c; 0019 } 0020 } 0021 return nullptr; 0022 } 0023 0024 static QByteArray readMailFromFile(const QString &mailFile) 0025 { 0026 Q_ASSERT(!QString::fromLatin1(MAIL_DATA_DIR).isEmpty()); 0027 QFile file(QLatin1String(MAIL_DATA_DIR) + QLatin1Char('/') + mailFile); 0028 file.open(QIODevice::ReadOnly); 0029 Q_ASSERT(file.isOpen()); 0030 return file.readAll(); 0031 } 0032 0033 static KMime::Message::Ptr readMail(const QString &mailFile) 0034 { 0035 auto msg = KMime::Message::Ptr::create(); 0036 msg->setContent(readMailFromFile(mailFile)); 0037 msg->parse(); 0038 return msg; 0039 } 0040 0041 static QString removeFirstLine(const QString &s) 0042 { 0043 return s.mid(s.indexOf(QLatin1String("\n")) + 1); 0044 } 0045 0046 static QString normalize(const QString &s) 0047 { 0048 auto text = s; 0049 text.replace(QLatin1String(">"), QString()); 0050 text.replace(QLatin1String("\n"), QString()); 0051 text.replace(QLatin1String("="), QString()); 0052 text.replace(QLatin1String(" "), QString()); 0053 return text; 0054 } 0055 0056 static QString unquote(const QString &s) 0057 { 0058 auto text = s; 0059 text.replace(QLatin1String("> "), QString()); 0060 return text; 0061 } 0062 0063 class MailTemplateTest : public QObject 0064 { 0065 Q_OBJECT 0066 0067 bool validate(KMime::Message::Ptr msg) 0068 { 0069 const auto data = msg->encodedContent(); 0070 // IMAP compat: The ASCII NUL character, %x00, MUST NOT be used at any time. 0071 if (data.contains('\0')) { 0072 return false; 0073 } 0074 return true; 0075 } 0076 0077 private Q_SLOTS: 0078 0079 // Ensures we don't crash on garbage 0080 void testEmpty() 0081 { 0082 MailTemplates::reply(KMime::Message::Ptr::create(), [&](const KMime::Message::Ptr &) {}); 0083 } 0084 0085 void testPlainReply() 0086 { 0087 auto msg = readMail(QLatin1String("plaintext.mbox")); 0088 KMime::Message::Ptr result; 0089 MailTemplates::reply(msg, [&](const KMime::Message::Ptr &r) { 0090 result = r; 0091 }); 0092 QTRY_VERIFY(result); 0093 QCOMPARE(normalize(removeFirstLine(QString::fromUtf8(result->body()))), normalize(QString::fromUtf8(msg->body()))); 0094 QCOMPARE(result->to()->addresses(), {{"konqi@example.org"}}); 0095 QCOMPARE(result->subject()->asUnicodeString(), QLatin1String{"RE: A random subject with alternative contenttype"}); 0096 } 0097 0098 void testHtmlReply() 0099 { 0100 auto msg = readMail(QLatin1String("html.mbox")); 0101 KMime::Message::Ptr result; 0102 MailTemplates::reply(msg, [&](const KMime::Message::Ptr &r) { 0103 result = r; 0104 }); 0105 QTRY_VERIFY(result); 0106 QCOMPARE(unquote(removeFirstLine(QString::fromUtf8(result->body()))), QLatin1String("HTML text")); 0107 } 0108 0109 void testStripSignatureReply() 0110 { 0111 auto msg = readMail(QLatin1String("plaintext-with-signature.mbox")); 0112 KMime::Message::Ptr result; 0113 MailTemplates::reply(msg, [&](const KMime::Message::Ptr &r) { 0114 result = r; 0115 }); 0116 QTRY_VERIFY(result); 0117 QVERIFY(!result->body().contains("This is a signature")); 0118 } 0119 0120 void testStripSignatureHtmlReply() 0121 { 0122 auto msg = readMail(QLatin1String("html-with-signature.mbox")); 0123 KMime::Message::Ptr result; 0124 MailTemplates::reply(msg, [&](const KMime::Message::Ptr &r) { 0125 result = r; 0126 }); 0127 QTRY_VERIFY(result); 0128 QVERIFY(!result->body().contains("This is a signature")); 0129 } 0130 0131 // We can't test this because we can't commit a CRLF file due to commit hooks. 0132 // void testStripSignatureCrlfReply() 0133 // { 0134 // auto msg = readMail("crlf-with-signature.mbox"); 0135 // KMime::Message::Ptr result; 0136 // MailTemplates::reply(msg, [&] (const KMime::Message::Ptr &r) { 0137 // result = r; 0138 // }); 0139 // QTRY_VERIFY(result); 0140 // QVERIFY(!result->body().contains("This is a signature")); 0141 // } 0142 0143 void testStripEncryptedCRLFReply() 0144 { 0145 auto msg = readMail(QLatin1String("crlf-encrypted-with-signature.mbox")); 0146 KMime::Message::Ptr result; 0147 MailTemplates::reply(msg, [&](const KMime::Message::Ptr &r) { 0148 result = r; 0149 }); 0150 QTRY_VERIFY(result); 0151 QVERIFY(!result->body().contains("This is a signature")); 0152 } 0153 0154 void testHtml8BitEncodedReply() 0155 { 0156 auto msg = readMail(QLatin1String("8bitencoded.mbox")); 0157 KMime::Message::Ptr result; 0158 MailTemplates::reply(msg, [&](const KMime::Message::Ptr &r) { 0159 result = r; 0160 }); 0161 QTRY_VERIFY(result); 0162 QVERIFY(MailTemplates::plaintextContent(result).contains(QString::fromUtf8("Why Pisa’s Tower"))); 0163 } 0164 0165 void testMultipartSignedReply() 0166 { 0167 auto msg = readMail(QLatin1String("openpgp-signed-mailinglist.mbox")); 0168 KMime::Message::Ptr result; 0169 MailTemplates::reply(msg, [&](const KMime::Message::Ptr &r) { 0170 result = r; 0171 }); 0172 QTRY_VERIFY(result); 0173 auto content = removeFirstLine(QString::fromUtf8(result->body())); 0174 QVERIFY(!content.isEmpty()); 0175 QVERIFY(content.contains(QLatin1String("i noticed a new branch"))); 0176 } 0177 0178 void testMultipartAlternativeReply() 0179 { 0180 auto msg = readMail(QLatin1String("alternative.mbox")); 0181 KMime::Message::Ptr result; 0182 MailTemplates::reply(msg, [&](const KMime::Message::Ptr &r) { 0183 result = r; 0184 }); 0185 QTRY_VERIFY(result); 0186 auto content = removeFirstLine(QString::fromUtf8(result->body())); 0187 QVERIFY(!content.isEmpty()); 0188 QCOMPARE(unquote(content), 0189 QLatin1String("If you can see this text it means that your email client couldn't display our newsletter properly.\nPlease visit this link to " 0190 "view the newsletter on our website: http://www.gog.com/newsletter/\n")); 0191 } 0192 0193 void testAttachmentReply() 0194 { 0195 auto msg = readMail(QLatin1String("plaintextattachment.mbox")); 0196 KMime::Message::Ptr result; 0197 MailTemplates::reply(msg, [&](const KMime::Message::Ptr &r) { 0198 result = r; 0199 }); 0200 QTRY_VERIFY(result); 0201 auto content = removeFirstLine(QString::fromUtf8(result->body())); 0202 QVERIFY(!content.isEmpty()); 0203 QCOMPARE(unquote(content), QLatin1String("sdlkjsdjf")); 0204 } 0205 0206 void testMultiRecipientReply() 0207 { 0208 auto msg = readMail(QLatin1String("multirecipients.mbox")); 0209 KMime::Message::Ptr result; 0210 MailTemplates::reply(msg, [&](const KMime::Message::Ptr &r) { 0211 result = r; 0212 }); 0213 QTRY_VERIFY(result); 0214 auto content = removeFirstLine(QString::fromUtf8(result->body())); 0215 QVERIFY(!content.isEmpty()); 0216 QCOMPARE(unquote(content), QLatin1String("test")); 0217 QCOMPARE(result->to()->addresses(), {{"from@example.org"}}); 0218 auto l = QVector<QByteArray>{{"to1@example.org"}, {"to2@example.org"}, {"cc1@example.org"}, {"cc2@example.org"}}; 0219 QCOMPARE(result->cc()->addresses(), l); 0220 } 0221 0222 void testMultiRecipientReplyFilteringMe() 0223 { 0224 KMime::Types::AddrSpecList me; 0225 KMime::Types::Mailbox mb; 0226 mb.setAddress("to1@example.org"); 0227 me << mb.addrSpec(); 0228 0229 auto msg = readMail(QLatin1String("multirecipients.mbox")); 0230 KMime::Message::Ptr result; 0231 MailTemplates::reply( 0232 msg, 0233 [&](const KMime::Message::Ptr &r) { 0234 result = r; 0235 }, 0236 me); 0237 QTRY_VERIFY(result); 0238 QCOMPARE(result->to()->addresses(), {{"from@example.org"}}); 0239 auto l = QVector<QByteArray>{{"to2@example.org"}, {"cc1@example.org"}, {"cc2@example.org"}}; 0240 QCOMPARE(result->cc()->addresses(), l); 0241 } 0242 0243 void testMultiRecipientReplyOwnMessage() 0244 { 0245 KMime::Types::AddrSpecList me; 0246 KMime::Types::Mailbox mb; 0247 mb.setAddress("from@example.org"); 0248 me << mb.addrSpec(); 0249 0250 auto msg = readMail(QLatin1String("multirecipients.mbox")); 0251 KMime::Message::Ptr result; 0252 MailTemplates::reply( 0253 msg, 0254 [&](const KMime::Message::Ptr &r) { 0255 result = r; 0256 }, 0257 me); 0258 QTRY_VERIFY(result); 0259 0260 auto to = QVector<QByteArray>{{"to1@example.org"}, {"to2@example.org"}}; 0261 QCOMPARE(result->to()->addresses(), to); 0262 auto cc = QVector<QByteArray>{{"cc1@example.org"}, {"cc2@example.org"}}; 0263 QCOMPARE(result->cc()->addresses(), cc); 0264 } 0265 0266 void testReplyList() 0267 { 0268 KMime::Types::AddrSpecList me; 0269 KMime::Types::Mailbox mb; 0270 mb.setAddress("me@example.org"); 0271 me << mb.addrSpec(); 0272 0273 auto msg = readMail(QLatin1String("listmessage.mbox")); 0274 KMime::Message::Ptr result; 0275 MailTemplates::reply( 0276 msg, 0277 [&](const KMime::Message::Ptr &r) { 0278 result = r; 0279 }, 0280 me); 0281 QTRY_VERIFY(result); 0282 0283 auto to = QVector<QByteArray>{{"list@example.org"}}; 0284 QCOMPARE(result->to()->addresses(), to); 0285 auto cc = QVector<QByteArray>{{"to@example.org"}, {"cc1@example.org"}}; 0286 QCOMPARE(result->cc()->addresses(), cc); 0287 } 0288 0289 void testForwardAsAttachment() 0290 { 0291 auto msg = readMail(QString::fromUtf8("plaintext.mbox")); 0292 KMime::Message::Ptr result; 0293 MailTemplates::forward(msg, [&](const KMime::Message::Ptr &r) { 0294 result = r; 0295 }); 0296 QTRY_VERIFY(result); 0297 QCOMPARE(result->subject(false)->asUnicodeString(), QLatin1String{"FW: A random subject with alternative contenttype"}); 0298 QCOMPARE(result->to()->addresses(), {}); 0299 QCOMPARE(result->cc()->addresses(), {}); 0300 QCOMPARE(result->references()->identifiers(), {"1505824.VT1nqpAGu0@vkpc5"}); 0301 QCOMPARE(result->inReplyTo()->identifiers(), {}); 0302 0303 auto attachments = result->attachments(); 0304 QCOMPARE(attachments.size(), 1); 0305 auto attachment = attachments[0]; 0306 QCOMPARE(attachment->contentDisposition(false)->disposition(), KMime::Headers::CDinline); 0307 QCOMPARE(attachment->contentDisposition(false)->filename(), QLatin1String{"A random subject with alternative contenttype.eml"}); 0308 QVERIFY(attachment->bodyIsMessage()); 0309 0310 attachment->parse(); 0311 auto origMsg = attachment->bodyAsMessage(); 0312 QCOMPARE(origMsg->subject(false)->asUnicodeString(), QLatin1String{"A random subject with alternative contenttype"}); 0313 } 0314 0315 void testEncryptedForwardAsAttachment() 0316 { 0317 auto msg = readMail(QLatin1String("openpgp-encrypted.mbox")); 0318 KMime::Message::Ptr result; 0319 MailTemplates::forward(msg, [&](const KMime::Message::Ptr &r) { 0320 result = r; 0321 }); 0322 QTRY_VERIFY(result); 0323 QCOMPARE(result->subject(false)->asUnicodeString(), QLatin1String{"FW: OpenPGP encrypted"}); 0324 QCOMPARE(result->to()->addresses(), {}); 0325 QCOMPARE(result->cc()->addresses(), {}); 0326 QCOMPARE(result->references()->identifiers(), {"1505824.VT2nqpAGu0@vkpc5"}); 0327 QCOMPARE(result->inReplyTo()->identifiers(), {}); 0328 0329 auto attachments = result->attachments(); 0330 QCOMPARE(attachments.size(), 1); 0331 auto attachment = attachments[0]; 0332 QCOMPARE(attachment->contentDisposition(false)->disposition(), KMime::Headers::CDinline); 0333 QCOMPARE(attachment->contentDisposition(false)->filename(), QLatin1String{"OpenPGP encrypted.eml"}); 0334 QVERIFY(attachment->bodyIsMessage()); 0335 0336 attachment->parse(); 0337 auto origMsg = attachment->bodyAsMessage(); 0338 QCOMPARE(origMsg->subject(false)->asUnicodeString(), QLatin1String{"OpenPGP encrypted"}); 0339 } 0340 0341 void testEncryptedWithAttachmentsForwardAsAttachment() 0342 { 0343 auto msg = readMail(QLatin1String("openpgp-encrypted-two-attachments.mbox")); 0344 KMime::Message::Ptr result; 0345 MailTemplates::forward(msg, [&](const KMime::Message::Ptr &r) { 0346 result = r; 0347 }); 0348 QTRY_VERIFY(result); 0349 QCOMPARE(result->subject(false)->asUnicodeString(), QLatin1String{"FW: OpenPGP encrypted with 2 text attachments"}); 0350 QCOMPARE(result->to()->addresses(), {}); 0351 QCOMPARE(result->cc()->addresses(), {}); 0352 QCOMPARE(result->references()->identifiers(), {"1505824.VT0nqpAGu0@vkpc5"}); 0353 QCOMPARE(result->inReplyTo()->identifiers(), {}); 0354 0355 auto attachments = result->attachments(); 0356 QCOMPARE(attachments.size(), 1); 0357 auto attachment = attachments[0]; 0358 QCOMPARE(attachment->contentDisposition(false)->disposition(), KMime::Headers::CDinline); 0359 QCOMPARE(attachment->contentDisposition(false)->filename(), QLatin1String{"OpenPGP encrypted with 2 text attachments.eml"}); 0360 QVERIFY(attachment->bodyIsMessage()); 0361 0362 attachment->parse(); 0363 auto origMsg = attachment->bodyAsMessage(); 0364 QCOMPARE(origMsg->subject(false)->asUnicodeString(), QLatin1String{"OpenPGP encrypted with 2 text attachments"}); 0365 0366 auto attattachments = origMsg->attachments(); 0367 QCOMPARE(attattachments.size(), 2); 0368 QCOMPARE(attattachments[0]->contentDisposition(false)->filename(), QLatin1String{"attachment1.txt"}); 0369 QCOMPARE(attattachments[1]->contentDisposition(false)->filename(), QLatin1String{"attachment2.txt"}); 0370 } 0371 0372 void testForwardAlreadyForwarded() 0373 { 0374 auto msg = readMail(QLatin1String("cid-links-forwarded-inline.mbox")); 0375 KMime::Message::Ptr result; 0376 MailTemplates::forward(msg, [&](const KMime::Message::Ptr &r) { 0377 result = r; 0378 }); 0379 QTRY_VERIFY(result); 0380 QCOMPARE(result->subject(false)->asUnicodeString(), QLatin1String{"FW: Html Hello (inlin)"}); 0381 QCOMPARE(result->to()->addresses(), {}); 0382 QCOMPARE(result->cc()->addresses(), {}); 0383 const QVector references{QByteArray{"a1777ec781546ccc5dcd4918a5e4e03d@info"}, QByteArray{"46b164308eb6056361c866932a740a3c@info"}}; 0384 QCOMPARE(result->references()->identifiers(), references); 0385 QCOMPARE(result->inReplyTo()->identifiers(), {}); 0386 } 0387 0388 void testCreatePlainMail() 0389 { 0390 QStringList to = {{QLatin1String("to@example.org")}}; 0391 QStringList cc = {{QLatin1String("cc@example.org")}}; 0392 QStringList bcc = {{QLatin1String("bcc@example.org")}}; 0393 0394 KMime::Types::Mailbox from; 0395 from.fromUnicodeString(QLatin1String("from@example.org")); 0396 QString subject = QLatin1String("subject"); 0397 QString body = QLatin1String("body"); 0398 QList<Attachment> attachments; 0399 0400 auto result = MailTemplates::createMessage({}, to, cc, bcc, from, subject, body, false, attachments); 0401 0402 QVERIFY(result); 0403 QVERIFY(validate(result)); 0404 QCOMPARE(result->subject()->asUnicodeString(), subject); 0405 QCOMPARE(result->body(), body.toUtf8()); 0406 QVERIFY(result->date(false)->dateTime().isValid()); 0407 QVERIFY(result->contentType()->isMimeType("text/plain")); 0408 QVERIFY(result->messageID(false) && !result->messageID(false)->isEmpty()); 0409 } 0410 0411 void testCreateHtmlMail() 0412 { 0413 QStringList to = {{QLatin1String("to@example.org")}}; 0414 QStringList cc = {{QLatin1String("cc@example.org")}}; 0415 QStringList bcc = {{QLatin1String("bcc@example.org")}}; 0416 0417 KMime::Types::Mailbox from; 0418 from.fromUnicodeString(QLatin1String("from@example.org")); 0419 QString subject = QLatin1String("subject"); 0420 QString body = QLatin1String("body"); 0421 QList<Attachment> attachments; 0422 0423 auto result = MailTemplates::createMessage({}, to, cc, bcc, from, subject, body, true, attachments); 0424 0425 QVERIFY(result); 0426 QVERIFY(validate(result)); 0427 QCOMPARE(result->subject()->asUnicodeString(), subject); 0428 QVERIFY(result->date(false)->dateTime().isValid()); 0429 QVERIFY(result->contentType()->isMimeType("multipart/alternative")); 0430 const auto contents = result->contents(); 0431 // 1 Plain + 1 Html 0432 QCOMPARE(contents.size(), 2); 0433 } 0434 0435 void testCreatePlainMailWithAttachments() 0436 { 0437 QStringList to = {{QLatin1String("to@example.org")}}; 0438 QStringList cc = {{QLatin1String("cc@example.org")}}; 0439 QStringList bcc = {{QLatin1String("bcc@example.org")}}; 0440 0441 KMime::Types::Mailbox from; 0442 from.fromUnicodeString(QLatin1String("from@example.org")); 0443 QString subject = QLatin1String("subject"); 0444 QString body = QLatin1String("body"); 0445 QList<Attachment> attachments = {{QLatin1String("name"), QLatin1String("filename"), "mimetype", true, "inlineAttachment"}, 0446 {QLatin1String("name"), QLatin1String("filename"), "mimetype", false, "nonInlineAttachment"}}; 0447 0448 auto result = MailTemplates::createMessage({}, to, cc, bcc, from, subject, body, false, attachments); 0449 0450 QVERIFY(result); 0451 QVERIFY(validate(result)); 0452 QCOMPARE(result->subject()->asUnicodeString(), subject); 0453 QVERIFY(result->contentType()->isMimeType("multipart/mixed")); 0454 QVERIFY(result->date(false)->dateTime().isValid()); 0455 const auto contents = result->contents(); 0456 // 1 Plain + 2 Attachments 0457 QCOMPARE(contents.size(), 3); 0458 auto p = getSubpart(result.data(), "text/plain"); 0459 QVERIFY(p); 0460 } 0461 0462 void testCreateHtmlMailWithAttachments() 0463 { 0464 QStringList to = {{QLatin1String("to@example.org")}}; 0465 QStringList cc = {{QLatin1String("cc@example.org")}}; 0466 QStringList bcc = {{QLatin1String("bcc@example.org")}}; 0467 0468 KMime::Types::Mailbox from; 0469 from.fromUnicodeString(QLatin1String("from@example.org")); 0470 QString subject = QLatin1String("subject"); 0471 QString body = QLatin1String("body"); 0472 QList<Attachment> attachments = { 0473 {QLatin1String("name"), QLatin1String("filename"), "mimetype", true, "inlineAttachment"}, 0474 {QLatin1String("name"), QLatin1String("filename"), "mimetype", false, "nonInlineAttachment"}, 0475 }; 0476 0477 auto result = MailTemplates::createMessage({}, to, cc, bcc, from, subject, body, true, attachments); 0478 0479 QVERIFY(result); 0480 QVERIFY(validate(result)); 0481 QCOMPARE(result->subject()->asUnicodeString(), subject); 0482 QVERIFY(result->contentType()->isMimeType("multipart/mixed")); 0483 QVERIFY(result->date(false)->dateTime().isValid()); 0484 const auto contents = result->contents(); 0485 // 1 alternative + 2 Attachments 0486 QCOMPARE(contents.size(), 3); 0487 auto p = getSubpart(result.data(), "multipart/alternative"); 0488 QVERIFY(p); 0489 } 0490 0491 void testCreatePlainMailSigned() 0492 { 0493 QStringList to = {{QLatin1String("to@example.org")}}; 0494 QStringList cc = {{QLatin1String("cc@example.org")}}; 0495 QStringList bcc = {{QLatin1String("bcc@example.org")}}; 0496 0497 KMime::Types::Mailbox from; 0498 from.fromUnicodeString(QLatin1String("from@example.org")); 0499 QString subject = QLatin1String("subject"); 0500 QString body = QLatin1String("body"); 0501 QList<Attachment> attachments; 0502 0503 auto keys = Crypto::findKeys({}, true, false); 0504 auto result = MailTemplates::createMessage({}, to, cc, bcc, from, subject, body, false, attachments, keys, {}, keys[0]); 0505 0506 QVERIFY(result); 0507 QVERIFY(validate(result)); 0508 // qWarning() << "---------------------------------"; 0509 // qWarning().noquote() << result->encodedContent(); 0510 // qWarning() << "---------------------------------"; 0511 QCOMPARE(result->subject()->asUnicodeString(), subject); 0512 QVERIFY(result->date(false)->dateTime().isValid()); 0513 0514 QCOMPARE(result->contentType()->mimeType(), QByteArray{"multipart/signed"}); 0515 QCOMPARE(result->attachments().size(), 1); 0516 QCOMPARE(result->attachments()[0]->contentDisposition()->filename(), QLatin1String{"0x8F246DE6.asc"}); 0517 QCOMPARE(result->contents().size(), 2); 0518 0519 auto signedMessage = result->contents()[0]; 0520 QVERIFY(signedMessage->contentType()->isMimeType("multipart/mixed")); 0521 const auto contents = signedMessage->contents(); 0522 QCOMPARE(contents.size(), 2); 0523 QCOMPARE(contents[0]->contentType()->mimeType(), QByteArray{"text/plain"}); 0524 QCOMPARE(contents[1]->contentType()->mimeType(), QByteArray{"application/pgp-keys"}); 0525 QCOMPARE(contents[1]->contentDisposition()->filename(), QLatin1String{"0x8F246DE6.asc"}); 0526 0527 auto signature = result->contents()[1]; 0528 QCOMPARE(signature->contentDisposition()->filename(), QLatin1String{"signature.asc"}); 0529 QVERIFY(signature->contentType()->isMimeType("application/pgp-signature")); 0530 } 0531 0532 void testCreatePlainMailWithAttachmentsSigned() 0533 { 0534 QStringList to = {{QLatin1String("to@example.org")}}; 0535 QStringList cc = {{QLatin1String("cc@example.org")}}; 0536 QStringList bcc = {{QLatin1String("bcc@example.org")}}; 0537 0538 KMime::Types::Mailbox from; 0539 from.fromUnicodeString(QLatin1String("from@example.org")); 0540 QString subject = QLatin1String("subject"); 0541 QString body = QLatin1String("body"); 0542 QList<Attachment> attachments = { 0543 {QLatin1String("name"), QLatin1String("filename1"), "mimetype1", true, "inlineAttachment"}, 0544 {QLatin1String("name"), QLatin1String("filename2"), "mimetype2", false, "nonInlineAttachment"}, 0545 }; 0546 0547 auto signingKeys = Crypto::findKeys({}, true, false); 0548 auto result = MailTemplates::createMessage({}, to, cc, bcc, from, subject, body, false, attachments, signingKeys, {}, signingKeys[0]); 0549 0550 QVERIFY(result); 0551 QVERIFY(validate(result)); 0552 qWarning() << "---------------------------------"; 0553 qWarning().noquote() << result->encodedContent(); 0554 qWarning() << "---------------------------------"; 0555 QCOMPARE(result->subject()->asUnicodeString(), subject); 0556 QVERIFY(result->date(false)->dateTime().isValid()); 0557 0558 QCOMPARE(result->contentType()->mimeType(), QByteArray{"multipart/signed"}); 0559 QCOMPARE(result->attachments().size(), 3); 0560 QCOMPARE(result->attachments()[0]->contentDisposition()->filename(), QLatin1String{"filename1"}); 0561 QCOMPARE(result->attachments()[1]->contentDisposition()->filename(), QLatin1String{"filename2"}); 0562 QCOMPARE(result->attachments()[2]->contentDisposition()->filename(), QLatin1String{"0x8F246DE6.asc"}); 0563 0564 QCOMPARE(result->contents().size(), 2); 0565 0566 auto signedMessage = result->contents()[0]; 0567 QVERIFY(signedMessage->contentType()->isMimeType("multipart/mixed")); 0568 const auto contents = signedMessage->contents(); 0569 QCOMPARE(contents.size(), 4); 0570 QCOMPARE(contents[0]->contentType()->mimeType(), QByteArray{"text/plain"}); 0571 QCOMPARE(contents[1]->contentDisposition()->filename(), QLatin1String{"filename1"}); 0572 QCOMPARE(contents[2]->contentDisposition()->filename(), QLatin1String{"filename2"}); 0573 QCOMPARE(contents[3]->contentType()->mimeType(), QByteArray{"application/pgp-keys"}); 0574 QCOMPARE(contents[3]->contentDisposition()->filename(), QLatin1String{"0x8F246DE6.asc"}); 0575 } 0576 0577 void testCreateIMipMessage() 0578 { 0579 QStringList to = {{QLatin1String("to@example.org")}}; 0580 QStringList cc = {{QLatin1String("cc@example.org")}}; 0581 QStringList bcc = {{QLatin1String("bcc@example.org")}}; 0582 QString from = {QLatin1String("from@example.org")}; 0583 QString subject = QLatin1String("subject"); 0584 QString body = QLatin1String("body"); 0585 0586 QString ical = QLatin1String("ical"); 0587 0588 auto result = MailTemplates::createIMipMessage(from, {to, cc, bcc}, subject, body, ical); 0589 0590 QVERIFY(result); 0591 QVERIFY(validate(result)); 0592 qWarning() << "---------------------------------"; 0593 qWarning().noquote() << result->encodedContent(); 0594 qWarning() << "---------------------------------"; 0595 0596 QCOMPARE(result->contentType()->mimeType(), QByteArray{"multipart/alternative"}); 0597 0598 QCOMPARE(result->attachments().size(), 0); 0599 0600 QCOMPARE(result->contents().size(), 2); 0601 QVERIFY(result->contents()[0]->contentType()->isMimeType("text/plain")); 0602 QVERIFY(result->contents()[1]->contentType()->isMimeType("text/calendar")); 0603 QCOMPARE(result->contents()[1]->contentType()->name(), QLatin1String{"event.ics"}); 0604 } 0605 0606 void testEncryptedWithProtectedHeadersReply() 0607 { 0608 KMime::Types::AddrSpecList me; 0609 KMime::Types::Mailbox mb; 0610 mb.setAddress("to1@example.org"); 0611 me << mb.addrSpec(); 0612 0613 auto msg = readMail(QLatin1String("openpgp-encrypted-memoryhole2.mbox")); 0614 KMime::Message::Ptr result; 0615 MailTemplates::reply( 0616 msg, 0617 [&](const KMime::Message::Ptr &r) { 0618 result = r; 0619 }, 0620 me); 0621 QTRY_VERIFY(result); 0622 QCOMPARE(result->subject()->asUnicodeString(), QLatin1String{"RE: This is the subject"}); 0623 QCOMPARE(result->to()->addresses(), {{"jane@doe.com"}}); 0624 QCOMPARE(result->cc()->addresses(), {{"john@doe.com"}}); 0625 QCOMPARE(result->inReplyTo()->asUnicodeString(), QLatin1String{"<03db3530-0000-0000-95a2-8a148f00000@example.com>"}); 0626 QCOMPARE(result->references()->asUnicodeString(), 0627 QLatin1String{"<dbe9d22b-0a3f-cb1e-e883-8a148f00000@example.com> <03db3530-0000-0000-95a2-8a148f00000@example.com>"}); 0628 QCOMPARE(normalize(removeFirstLine(QString::fromUtf8(result->body()))), 0629 QLatin1String{"FsdflkjdslfjHappyMonday!Belowyouwillfindaquickoverviewofthecurrenton-goings.Remember"}); 0630 } 0631 0632 void testEncryptedWithProtectedHeadersForwardAsAttachment() 0633 { 0634 auto msg = readMail(QLatin1String("openpgp-encrypted-memoryhole2.mbox")); 0635 KMime::Message::Ptr result; 0636 MailTemplates::forward(msg, [&](const KMime::Message::Ptr &r) { 0637 result = r; 0638 }); 0639 QTRY_VERIFY(result); 0640 QCOMPARE(result->subject()->asUnicodeString(), QLatin1String{"FW: This is the subject"}); 0641 QCOMPARE(result->to()->addresses(), {}); 0642 QCOMPARE(result->cc()->addresses(), {}); 0643 QCOMPARE(result->references()->asUnicodeString(), 0644 QLatin1String{"<dbe9d22b-0a3f-cb1e-e883-8a148f00000@example.com> <03db3530-0000-0000-95a2-8a148f00000@example.com>"}); 0645 QCOMPARE(result->inReplyTo()->identifiers(), {}); 0646 0647 auto attachments = result->attachments(); 0648 QCOMPARE(attachments.size(), 1); 0649 auto attachment = attachments[0]; 0650 QCOMPARE(attachment->contentDisposition(false)->disposition(), KMime::Headers::CDinline); 0651 QCOMPARE(attachment->contentDisposition(false)->filename(), QLatin1String{"This is the subject.eml"}); 0652 QVERIFY(attachment->bodyIsMessage()); 0653 0654 attachment->parse(); 0655 auto origMsg = attachment->bodyAsMessage(); 0656 QCOMPARE(origMsg->subject(false)->asUnicodeString(), QLatin1String{"..."}); 0657 } 0658 }; 0659 0660 QTEST_MAIN(MailTemplateTest) 0661 #include "mailtemplatetest.moc"