diff --git a/framework/src/domain/mime/mimetreeparser/tests/mimetreeparsertest.cpp b/framework/src/domain/mime/mimetreeparser/tests/mimetreeparsertest.cpp index 478cd0f1..5bc66cbf 100644 --- a/framework/src/domain/mime/mimetreeparser/tests/mimetreeparsertest.cpp +++ b/framework/src/domain/mime/mimetreeparser/tests/mimetreeparsertest.cpp @@ -1,469 +1,507 @@ /* Copyright (c) 2016 Sandro Knauß This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include QByteArray readMailFromFile(const QString &mailFile) { QFile file(QLatin1String(MAIL_DATA_DIR) + QLatin1Char('/') + mailFile); file.open(QIODevice::ReadOnly); Q_ASSERT(file.isOpen()); return file.readAll(); } class MimeTreeParserTest : public QObject { Q_OBJECT private slots: void testTextMail() { const auto expectedText = QStringLiteral("If you can see this text it means that your email client couldn't display our newsletter properly.\nPlease visit this link to view the newsletter on our website: http://www.gog.com/newsletter/"); MimeTreeParser::ObjectTreeParser otp; otp.parseObjectTree(readMailFromFile("plaintext.mbox")); auto partList = otp.collectContentParts(); QCOMPARE(partList.size(), 1); auto part = partList[0].dynamicCast(); QCOMPARE(part->text(), expectedText); QCOMPARE(part->charset(), QStringLiteral("utf-8").toLocal8Bit()); QCOMPARE(part->encryptions().size(), 0); QCOMPARE(part->signatures().size(), 0); QCOMPARE(otp.collectAttachmentParts().size(), 0); QCOMPARE(otp.plainTextContent(), expectedText); QVERIFY(otp.htmlContent().isEmpty()); } void testAlternative() { MimeTreeParser::ObjectTreeParser otp; otp.parseObjectTree(readMailFromFile("alternative.mbox")); auto partList = otp.collectContentParts(); QCOMPARE(partList.size(), 1); auto part = partList[0].dynamicCast(); QVERIFY(bool(part)); QCOMPARE(part->plaintextContent(), QStringLiteral("If you can see this text it means that your email client couldn't display our newsletter properly.\nPlease visit this link to view the newsletter on our website: http://www.gog.com/newsletter/\n")); //FIXME html charset is different from plain, and both are not ISO-8859-1 QCOMPARE(part->charset(), QStringLiteral("ISO-8859-1").toLocal8Bit()); QCOMPARE(part->htmlContent(), QStringLiteral("

HTML text

\n\n")); QCOMPARE(otp.collectAttachmentParts().size(), 0); QCOMPARE(part->encryptions().size(), 0); QCOMPARE(part->signatures().size(), 0); } void testTextHtml() { auto expectedText = QStringLiteral("

HTML text

"); MimeTreeParser::ObjectTreeParser otp; otp.parseObjectTree(readMailFromFile("html.mbox")); otp.print(); auto partList = otp.collectContentParts(); QCOMPARE(partList.size(), 1); auto part = partList[0].dynamicCast(); QVERIFY(bool(part)); QCOMPARE(part->htmlContent(), expectedText); QCOMPARE(part->charset(), QStringLiteral("windows-1252").toLocal8Bit()); QCOMPARE(part->encryptions().size(), 0); QCOMPARE(part->signatures().size(), 0); auto contentAttachmentList = otp.collectAttachmentParts(); QCOMPARE(contentAttachmentList.size(), 0); QCOMPARE(otp.htmlContent(), expectedText); QVERIFY(otp.plainTextContent().isEmpty()); } void testSMimeEncrypted() { MimeTreeParser::ObjectTreeParser otp; otp.parseObjectTree(readMailFromFile("smime-encrypted.mbox")); otp.print(); otp.decryptParts(); otp.print(); auto partList = otp.collectContentParts(); QCOMPARE(partList.size(), 1); auto part = partList[0].dynamicCast(); QVERIFY(bool(part)); QCOMPARE(part->text(), QStringLiteral("The quick brown fox jumped over the lazy dog.")); QCOMPARE(part->charset(), QStringLiteral("us-ascii").toLocal8Bit()); QCOMPARE(part->encryptions().size(), 1); QCOMPARE(part->signatures().size(), 0); auto contentAttachmentList = otp.collectAttachmentParts(); QCOMPARE(contentAttachmentList.size(), 0); } void testOpenPGPEncryptedAttachment() { MimeTreeParser::ObjectTreeParser otp; otp.parseObjectTree(readMailFromFile("openpgp-encrypted-attachment-and-non-encrypted-attachment.mbox")); otp.print(); otp.decryptParts(); otp.print(); auto partList = otp.collectContentParts(); QCOMPARE(partList.size(), 1); auto part = partList[0].dynamicCast(); QVERIFY(bool(part)); QCOMPARE(part->text(), QStringLiteral("test text")); QCOMPARE(part->charset(), QStringLiteral("us-ascii").toLocal8Bit()); QCOMPARE(part->encryptions().size(), 1); QCOMPARE(part->signatures().size(), 1); QCOMPARE(part->encryptionState(), MimeTreeParser::KMMsgFullyEncrypted); QCOMPARE(part->signatureState(), MimeTreeParser::KMMsgFullySigned); auto contentAttachmentList = otp.collectAttachmentParts(); QCOMPARE(contentAttachmentList.size(), 2); // QCOMPARE(contentAttachmentList[0]->availableContents(), QVector() << "text/plain"); // QCOMPARE(contentAttachmentList[0]->content().size(), 1); QCOMPARE(contentAttachmentList[0]->encryptions().size(), 1); QCOMPARE(contentAttachmentList[0]->signatures().size(), 1); QCOMPARE(contentAttachmentList[0]->encryptionState(), MimeTreeParser::KMMsgFullyEncrypted); QCOMPARE(contentAttachmentList[0]->signatureState(), MimeTreeParser::KMMsgFullySigned); // QCOMPARE(contentAttachmentList[1]->availableContents(), QVector() << "image/png"); // QCOMPARE(contentAttachmentList[1]->content().size(), 1); QCOMPARE(contentAttachmentList[1]->encryptions().size(), 0); QCOMPARE(contentAttachmentList[1]->signatures().size(), 0); QCOMPARE(contentAttachmentList[1]->encryptionState(), MimeTreeParser::KMMsgNotEncrypted); QCOMPARE(contentAttachmentList[1]->signatureState(), MimeTreeParser::KMMsgNotSigned); } void testOpenPGPInline() { MimeTreeParser::ObjectTreeParser otp; otp.parseObjectTree(readMailFromFile("openpgp-inline-charset-encrypted.mbox")); otp.print(); otp.decryptParts(); otp.print(); auto partList = otp.collectContentParts(); QCOMPARE(partList.size(), 1); auto part = partList[0].dynamicCast(); QVERIFY(bool(part)); QCOMPARE(part->charset(), QStringLiteral("ISO-8859-1").toLocal8Bit()); QCOMPARE(part->text(), QString::fromUtf8("asdasd asd asd asdf sadf sdaf sadf öäü")); QCOMPARE(part->encryptions().size(), 1); QCOMPARE(part->signatures().size(), 1); QCOMPARE(otp.collectAttachmentParts().size(), 0); } void testOpenPPGInlineWithNonEncText() { MimeTreeParser::ObjectTreeParser otp; otp.parseObjectTree(readMailFromFile("openpgp-inline-encrypted+nonenc.mbox")); otp.print(); otp.decryptParts(); otp.print(); auto partList = otp.collectContentParts(); QCOMPARE(partList.size(), 1); auto part1 = partList[0].dynamicCast(); QVERIFY(bool(part1)); QCOMPARE(part1->text(), QStringLiteral("Not encrypted not signed :(\n\nsome random text")); //TODO test if we get the proper subparts with the appropriate encryptions QCOMPARE(part1->charset(), QStringLiteral("us-ascii").toLocal8Bit()); QCOMPARE(part1->encryptionState(), MimeTreeParser::KMMsgPartiallyEncrypted); QCOMPARE(part1->signatureState(), MimeTreeParser::KMMsgNotSigned); // QCOMPARE(part1->text(), QStringLiteral("Not encrypted not signed :(\n\n")); // QCOMPARE(part1->charset(), QStringLiteral("us-ascii").toLocal8Bit()); // QCOMPARE(contentList[1]->content(), QStringLiteral("some random text").toLocal8Bit()); // QCOMPARE(contentList[1]->charset(), QStringLiteral("us-ascii").toLocal8Bit()); // QCOMPARE(contentList[1]->encryptions().size(), 1); // QCOMPARE(contentList[1]->signatures().size(), 0); QCOMPARE(otp.collectAttachmentParts().size(), 0); } void testEncryptionBlock() { MimeTreeParser::ObjectTreeParser otp; otp.parseObjectTree(readMailFromFile("openpgp-encrypted-attachment-and-non-encrypted-attachment.mbox")); otp.print(); otp.decryptParts(); otp.print(); auto partList = otp.collectContentParts(); QCOMPARE(partList.size(), 1); auto part1 = partList[0].dynamicCast(); QVERIFY(bool(part1)); QCOMPARE(part1->encryptions().size(), 1); // auto enc = contentList[0]->encryptions()[0]; // QCOMPARE((int) enc->recipients().size(), 2); // auto r = enc->recipients()[0]; // QCOMPARE(r->keyid(),QStringLiteral("14B79E26050467AA")); // QCOMPARE(r->name(),QStringLiteral("kdetest")); // QCOMPARE(r->email(),QStringLiteral("you@you.com")); // QCOMPARE(r->comment(),QStringLiteral("")); // r = enc->recipients()[1]; // QCOMPARE(r->keyid(),QStringLiteral("8D9860C58F246DE6")); // QCOMPARE(r->name(),QStringLiteral("unittest key")); // QCOMPARE(r->email(),QStringLiteral("test@kolab.org")); // QCOMPARE(r->comment(),QStringLiteral("no password")); auto attachmentList = otp.collectAttachmentParts(); QCOMPARE(attachmentList.size(), 2); auto attachment1 = attachmentList[0]; QVERIFY(attachment1->node()); QCOMPARE(attachment1->filename(), QStringLiteral("file.txt")); auto attachment2 = attachmentList[1]; QVERIFY(attachment2->node()); QCOMPARE(attachment2->filename(), QStringLiteral("image.png")); } void testSignatureBlock() { MimeTreeParser::ObjectTreeParser otp; otp.parseObjectTree(readMailFromFile("openpgp-encrypted-attachment-and-non-encrypted-attachment.mbox")); otp.print(); otp.decryptParts(); otp.print(); auto partList = otp.collectContentParts(); QCOMPARE(partList.size(), 1); auto part = partList[0].dynamicCast(); QVERIFY(bool(part)); // QCOMPARE(contentList[0]->signatures().size(), 1); // auto sig = contentList[0]->signatures()[0]; // QCOMPARE(sig->creationDateTime(), QDateTime(QDate(2015,05,01),QTime(15,12,47))); // QCOMPARE(sig->expirationDateTime(), QDateTime()); // QCOMPARE(sig->neverExpires(), true); // auto key = sig->key(); // QCOMPARE(key->keyid(),QStringLiteral("8D9860C58F246DE6")); // QCOMPARE(key->name(),QStringLiteral("unittest key")); // QCOMPARE(key->email(),QStringLiteral("test@kolab.org")); // QCOMPARE(key->comment(),QStringLiteral("no password")); } void testRelatedAlternative() { MimeTreeParser::ObjectTreeParser otp; otp.parseObjectTree(readMailFromFile("cid-links.mbox")); otp.print(); auto partList = otp.collectContentParts(); QCOMPARE(partList.size(), 1); auto part = partList[0].dynamicCast(); QVERIFY(bool(part)); QCOMPARE(part->encryptions().size(), 0); QCOMPARE(part->signatures().size(), 0); QCOMPARE(otp.collectAttachmentParts().size(), 1); } void testAttachmentPart() { MimeTreeParser::ObjectTreeParser otp; otp.parseObjectTree(readMailFromFile("attachment.mbox")); otp.print(); auto partList = otp.collectAttachmentParts(); QCOMPARE(partList.size(), 1); auto part = partList[0].dynamicCast(); QVERIFY(bool(part)); auto att = part->node(); qWarning() << "Attachment type: " << att->contentType(true)->mimeType(); QCOMPARE(part->mimeType(), QByteArray("image/jpeg")); } void testCidLink() { MimeTreeParser::ObjectTreeParser otp; otp.parseObjectTree(readMailFromFile("cid-links.mbox")); otp.print(); auto partList = otp.collectContentParts(); QCOMPARE(partList.size(), 1); auto part = partList[0].dynamicCast(); QVERIFY(bool(part)); auto resolvedContent = otp.resolveCidLinks(part->htmlContent()); QVERIFY(!resolvedContent.contains("cid:")); } void testCidLinkInForwardedInline() { MimeTreeParser::ObjectTreeParser otp; otp.parseObjectTree(readMailFromFile("cid-links-forwarded-inline.mbox")); otp.print(); auto partList = otp.collectContentParts(); QCOMPARE(partList.size(), 1); auto part = partList[0].dynamicCast(); QVERIFY(bool(part)); auto resolvedContent = otp.resolveCidLinks(part->htmlContent()); QVERIFY(!resolvedContent.contains("cid:")); } void testOpenPGPInlineError() { MimeTreeParser::ObjectTreeParser otp; otp.parseObjectTree(readMailFromFile("inlinepgpgencrypted-error.mbox")); otp.print(); otp.decryptParts(); otp.print(); auto partList = otp.collectContentParts(); QCOMPARE(partList.size(), 1); auto part = partList[0].dynamicCast(); QVERIFY(bool(part)); QVERIFY(part->error()); } void testEncapsulated() { MimeTreeParser::ObjectTreeParser otp; otp.parseObjectTree(readMailFromFile("encapsulated-with-attachment.mbox")); otp.decryptParts(); auto partList = otp.collectContentParts(); QCOMPARE(partList.size(), 2); auto part = partList[1].dynamicCast(); QVERIFY(bool(part)); QCOMPARE(part->from(), QLatin1String("Thomas McGuire ")); QCOMPARE(part->date().toString(), QLatin1String("Wed Aug 5 10:57:58 2009 GMT+0200")); auto subPartList = otp.collectContentParts(part); QCOMPARE(subPartList.size(), 1); qWarning() << subPartList[0]->metaObject()->className(); auto subPart = subPartList[0].dynamicCast(); QVERIFY(bool(subPart)); } void test8bitEncodedInPlaintext() { MimeTreeParser::ObjectTreeParser otp; otp.parseObjectTree(readMailFromFile("8bitencoded.mbox")); QVERIFY(otp.plainTextContent().contains(QString::fromUtf8("Why Pisa’s Tower"))); QVERIFY(otp.htmlContent().contains(QString::fromUtf8("Why Pisa’s Tower"))); } void testInlineSigned() { MimeTreeParser::ObjectTreeParser otp; otp.parseObjectTree(readMailFromFile("openpgp-inline-signed.mbox")); otp.decryptParts(); auto partList = otp.collectContentParts(); QCOMPARE(partList.size(), 1); auto part = partList[0].dynamicCast(); QCOMPARE(part->signatures().size(), 1); QCOMPARE(part->encryptionState(), MimeTreeParser::KMMsgNotEncrypted); QCOMPARE(part->signatureState(), MimeTreeParser::KMMsgFullySigned); auto signaturePart = part->signatures().first(); QCOMPARE(signaturePart->partMetaData()->isGoodSignature, true); QCOMPARE(signaturePart->partMetaData()->keyIsTrusted, true); QCOMPARE(signaturePart->partMetaData()->keyMissing, false); QCOMPARE(signaturePart->partMetaData()->keyExpired, false); QCOMPARE(signaturePart->partMetaData()->keyRevoked, false); QCOMPARE(signaturePart->partMetaData()->sigExpired, false); QCOMPARE(signaturePart->partMetaData()->crlMissing, false); QCOMPARE(signaturePart->partMetaData()->crlTooOld, false); QCOMPARE(signaturePart->partMetaData()->keyId, QByteArray{"8D9860C58F246DE6"}); QCOMPARE(signaturePart->partMetaData()->signer, {"unittest key (no password) "}); QCOMPARE(signaturePart->partMetaData()->signerMailAddresses, QStringList{{"test@kolab.org"}}); } void testEncryptedAndSigned() { MimeTreeParser::ObjectTreeParser otp; otp.parseObjectTree(readMailFromFile("openpgp-encrypted+signed.mbox")); otp.decryptParts(); auto partList = otp.collectContentParts(); QCOMPARE(partList.size(), 1); auto part = partList[0].dynamicCast(); QCOMPARE(part->signatures().size(), 1); QCOMPARE(part->encryptions().size(), 1); QCOMPARE(part->encryptionState(), MimeTreeParser::KMMsgFullyEncrypted); QCOMPARE(part->signatureState(), MimeTreeParser::KMMsgFullySigned); QVERIFY(otp.plainTextContent().contains(QString::fromUtf8("encrypted message text"))); auto signaturePart = part->signatures().first(); QCOMPARE(signaturePart->partMetaData()->keyId, QByteArray{"8D9860C58F246DE6"}); QCOMPARE(signaturePart->partMetaData()->isGoodSignature, true); } void testOpenpgpMultipartEmbedded() { MimeTreeParser::ObjectTreeParser otp; otp.parseObjectTree(readMailFromFile("openpgp-multipart-embedded.mbox")); otp.print(); otp.decryptParts(); otp.print(); auto partList = otp.collectContentParts(); QCOMPARE(partList.size(), 1); auto part = partList[0].dynamicCast(); QCOMPARE(part->encryptions().size(), 1); QCOMPARE(part->encryptionState(), MimeTreeParser::KMMsgFullyEncrypted); QCOMPARE(otp.plainTextContent(), QString::fromUtf8("sdflskjsdf\n\n-- \nThis is a HTML signature.\n")); } void testOpenpgpMultipartEmbeddedSigned() { MimeTreeParser::ObjectTreeParser otp; otp.parseObjectTree(readMailFromFile("openpgp-multipart-embedded-signed.mbox")); otp.decryptParts(); auto partList = otp.collectContentParts(); QCOMPARE(partList.size(), 1); auto part = partList[0].dynamicCast(); QCOMPARE(part->encryptions().size(), 1); QCOMPARE(part->signatures().size(), 1); QCOMPARE(part->encryptionState(), MimeTreeParser::KMMsgFullyEncrypted); QCOMPARE(part->signatureState(), MimeTreeParser::KMMsgFullySigned); QCOMPARE(otp.plainTextContent(), QString::fromUtf8("test\n\n-- \nThis is a HTML signature.\n")); auto signaturePart = part->signatures().first(); QVERIFY(signaturePart->partMetaData()->keyId.endsWith(QByteArray{"2E3B7787B1B75920"})); //We lack the public key for this message QCOMPARE(signaturePart->partMetaData()->isGoodSignature, false); QCOMPARE(signaturePart->partMetaData()->keyMissing, true); } void testAppleHtmlWithAttachments() { MimeTreeParser::ObjectTreeParser otp; otp.parseObjectTree(readMailFromFile("applehtmlwithattachments.mbox")); otp.decryptParts(); auto partList = otp.collectContentParts(); QCOMPARE(partList.size(), 1); auto part = partList[0].dynamicCast(); QVERIFY(part); QCOMPARE(part->encryptions().size(), 0); QCOMPARE(part->signatures().size(), 0); QVERIFY(part->isHtml()); QCOMPARE(otp.plainTextContent(), QString::fromUtf8("Hi,\n\nThis is an HTML message with attachments.\n\nCheers,\nChristian")); QCOMPARE(otp.htmlContent(), QString::fromUtf8("
Hi,

This is an HTML message with attachments.

Cheers,
Christian
")); auto attachments = otp.collectAttachmentParts(); QCOMPARE(attachments.size(), 1); } void testAppleHtmlWithAttachmentsMixed() { MimeTreeParser::ObjectTreeParser otp; otp.parseObjectTree(readMailFromFile("applehtmlwithattachmentsmixed.mbox")); otp.decryptParts(); otp.print(); auto partList = otp.collectContentParts(); QCOMPARE(partList.size(), 1); auto part = partList[0].dynamicCast(); QVERIFY(part); QCOMPARE(part->encryptions().size(), 0); QCOMPARE(part->signatures().size(), 0); QVERIFY(part->isHtml()); QCOMPARE(otp.plainTextContent(), QString::fromUtf8("Hello\n\n\n\nRegards\n\nFsdfsdf")); QCOMPARE(otp.htmlContent(), QString::fromUtf8("Hello


Regards

Fsdfsdf
")); auto attachments = otp.collectAttachmentParts(); QCOMPARE(attachments.size(), 1); } + + void testInvitation() + { + MimeTreeParser::ObjectTreeParser otp; + otp.parseObjectTree(readMailFromFile("invitation.mbox")); + otp.decryptParts(); + otp.print(); + auto partList = otp.collectContentParts(); + QCOMPARE(partList.size(), 1); + auto part = partList[0].dynamicCast(); + QVERIFY(part); + QCOMPARE(part->encryptions().size(), 0); + QCOMPARE(part->signatures().size(), 0); + QVERIFY(!part->isHtml()); + QVERIFY(part->availableModes().contains(MimeTreeParser::Util::MultipartIcal)); + + auto attachments = otp.collectAttachmentParts(); + QCOMPARE(attachments.size(), 0); + } + + void testGmailInvitation() + { + MimeTreeParser::ObjectTreeParser otp; + otp.parseObjectTree(readMailFromFile("gmail-invitation.mbox")); + otp.decryptParts(); + otp.print(); + auto partList = otp.collectContentParts(); + QCOMPARE(partList.size(), 1); + auto part = partList[0].dynamicCast(); + QVERIFY(part); + QCOMPARE(part->encryptions().size(), 0); + QCOMPARE(part->signatures().size(), 0); + QVERIFY(part->isHtml()); + QVERIFY(part->availableModes().contains(MimeTreeParser::Util::MultipartIcal)); + + auto attachments = otp.collectAttachmentParts(); + QCOMPARE(attachments.size(), 1); + } }; QTEST_GUILESS_MAIN(MimeTreeParserTest) #include "mimetreeparsertest.moc" diff --git a/framework/src/domain/mime/testdata/gmail-invitation.mbox b/framework/src/domain/mime/testdata/gmail-invitation.mbox new file mode 100644 index 00000000..18f914e4 --- /dev/null +++ b/framework/src/domain/mime/testdata/gmail-invitation.mbox @@ -0,0 +1,222 @@ +Return-Path: +MIME-Version: 1.0 +Reply-To: doe@gmail.com +Sender: Google Calendar +Message-ID: <0000000000000d116705904d4868@google.com> +Date: Sat, 17 Aug 2019 10:07:59 +0000 +Subject: Invitation: test1 @ Sat 17 Aug 2019 15:00 - 16:00 (CEST) (test1@kolab.org) +From: doe@gmail.com +To: test1@kolab.org +Content-Type: multipart/mixed; boundary="0000000000000d114f05904d4867" + +--0000000000000d114f05904d4867 +Content-Type: multipart/alternative; boundary="0000000000000d114c05904d4865" + +--0000000000000d114c05904d4865 +Content-Type: text/plain; charset="UTF-8"; format=flowed; delsp=yes +Content-Transfer-Encoding: base64 + +WW91IGhhdmUgYmVlbiBpbnZpdGVkIHRvIHRoZSBmb2xsb3dpbmcgZXZlbnQuDQoNClRpdGxlOiB0 +ZXN0MQ0KV2hlbjogU2F0IDE3IEF1ZyAyMDE5IDE1OjAwIOKAkyAxNjowMCBDZW50cmFsIEV1cm9w +ZWFuIFRpbWUgLSBadXJpY2gNCkNhbGVuZGFyOiB0ZXN0MUBrb2xhYi5vcmcNCldobzoNCiAgICAg +KiBjbW9sbGVrb3BmQGdtYWlsLmNvbS0gb3JnYW5pc2VyDQogICAgICogdGVzdDFAa29sYWIub3Jn +DQoNCkV2ZW50IGRldGFpbHM6ICANCmh0dHBzOi8vd3d3Lmdvb2dsZS5jb20vY2FsZW5kYXIvZXZl +bnQ/YWN0aW9uPVZJRVcmZWlkPU1IVTFjRE15Tm5ab00yeGxOemt3ZEdGeWJuRnZkREEyZGpJZ2RH +VnpkREZBYTI5c1lXSXViM0puJnRvaz1NakFqWTIxdmJHeGxhMjl3WmtCbmJXRnBiQzVqYjIwNE5U +aGhOamN5TUdFd05UWTJZVFpsWW1VNFpEUTVZak0yWm1Fd05EUmtabVZrTlRWa1lqTmwmY3R6PUV1 +cm9wZSUyRlp1cmljaCZobD1lbl9HQiZlcz0wDQoNCkludml0YXRpb24gZnJvbSBHb29nbGUgQ2Fs +ZW5kYXI6IGh0dHBzOi8vd3d3Lmdvb2dsZS5jb20vY2FsZW5kYXIvDQoNCllvdSBhcmUgcmVjZWl2 +aW5nIHRoaXMgY291cnRlc3kgZW1haWwgYXQgdGhlIGFjY291bnQgdGVzdDFAa29sYWIub3JnICAN +CmJlY2F1c2UgeW91IGFyZSBhbiBhdHRlbmRlZSBvZiB0aGlzIGV2ZW50Lg0KDQpUbyBzdG9wIHJl +Y2VpdmluZyBmdXR1cmUgdXBkYXRlcyBmb3IgdGhpcyBldmVudCwgZGVjbGluZSB0aGlzIGV2ZW50 +LiAgDQpBbHRlcm5hdGl2ZWx5LCB5b3UgY2FuIHNpZ24gdXAgZm9yIGEgR29vZ2xlIEFjY291bnQg +YXQgIA0KaHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS9jYWxlbmRhci8gYW5kIGNvbnRyb2wgeW91ciBu +b3RpZmljYXRpb24gc2V0dGluZ3MgZm9yICANCnlvdXIgZW50aXJlIGNhbGVuZGFyLg0KDQpGb3J3 +YXJkaW5nIHRoaXMgaW52aXRhdGlvbiBjb3VsZCBhbGxvdyBhbnkgcmVjaXBpZW50IHRvIHNlbmQg +YSByZXNwb25zZSB0byAgDQp0aGUgb3JnYW5pc2VyIGFuZCBiZSBhZGRlZCB0byB0aGUgZ3Vlc3Qg +bGlzdCwgaW52aXRlIG90aGVycyByZWdhcmRsZXNzIG9mICANCnRoZWlyIG93biBpbnZpdGF0aW9u +IHN0YXR1cyBvciB0byBtb2RpZnkgeW91ciBSU1ZQLiBMZWFybiBtb3JlIGF0ICANCmh0dHBzOi8v +c3VwcG9ydC5nb29nbGUuY29tL2NhbGVuZGFyL2Fuc3dlci8zNzEzNSNmb3J3YXJkaW5nDQo= +--0000000000000d114c05904d4865 +Content-Type: text/html; charset="UTF-8" +Content-Transfer-Encoding: quoted-printable + +

You have been invited to the foll= +owing event.

test1

When
Sat 17 Aug 2019 15:00 = +=E2=80=93 16:00 Central European Time - Zurich
Calendar
test1@kolab.org
= +
Who
doepadinng@gmail.com- organiser
test1@k= +olab.org

Going (test1@k= +olab.org)?   Yes<= +span style=3D"margin:0 0.4em;font-weight:normal"> - Maybe - = +No    more options »

Invitation from Google Calendar

<= +p>You are receiving this courtesy email at the account test1@kolab.org beca= +use you are an attendee of this event.

To stop receiving future updat= +es for this event, decline this event. Alternatively, you can sign up for a= + Google Account at https://www.google.com/calendar/ and control your notifi= +cation settings for your entire calendar.

Forwarding this invitation = +could allow any recipient to send a response to the organiser and be added = +to the guest list, invite others regardless of their own invitation status = +or to modify your RSVP. Learn more.

+--0000000000000d114c05904d4865 +Content-Type: text/calendar; charset="UTF-8"; method=REQUEST +Content-Transfer-Encoding: 7bit + +BEGIN:VCALENDAR +PRODID:-//Google Inc//Google Calendar 70.9054//EN +VERSION:2.0 +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VEVENT +DTSTART:20190817T130000Z +DTEND:20190817T140000Z +DTSTAMP:20190817T100759Z +ORGANIZER;CN=doe@gmail.com:mailto:doe@gmail.com +UID:0u5p326vh3le790tarnqot06v2@google.com +ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;RSVP=TRUE + ;CN=doe@gmail.com;X-NUM-GUESTS=0:mailto:doe@gmail.com +ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP= + TRUE;CN=test1@kolab.org;X-NUM-GUESTS=0:mailto:test1@kolab.org +X-MICROSOFT-CDO-OWNERAPPTID:-750968860 +CREATED:20190817T100754Z +DESCRIPTION:-::~:~::~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~ + :~:~:~:~:~:~:~:~::~:~::-\nPlease do not edit this section of the descriptio + n.\n\nView your event at https://www.google.com/calendar/event?action=VIEW& + eid=MHU1cDMyNnZoM2xlNzkwdGFybnFvdDA2djIgdGVzdDFAa29sYWIub3Jn&tok=MjAjY21vbG + xla29wZkBnbWFpbC5jb204NThhNjcyMGEwNTY2YTZlYmU4ZDQ5YjM2ZmEwNDRkZmVkNTVkYjNl& + ctz=Europe%2FZurich&hl=en_GB&es=1.\n-::~:~::~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~ + :~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~::~:~::- +LAST-MODIFIED:20190817T100754Z +LOCATION: +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:test1 +TRANSP:OPAQUE +END:VEVENT +END:VCALENDAR + +--0000000000000d114c05904d4865-- +--0000000000000d114f05904d4867 +Content-Type: application/ics; name="invite.ics" +Content-Disposition: attachment; filename="invite.ics" +Content-Transfer-Encoding: base64 + +QkVHSU46VkNBTEVOREFSDQpQUk9ESUQ6LS8vR29vZ2xlIEluYy8vR29vZ2xlIENhbGVuZGFyIDcw +LjkwNTQvL0VODQpWRVJTSU9OOjIuMA0KQ0FMU0NBTEU6R1JFR09SSUFODQpNRVRIT0Q6UkVRVUVT +VA0KQkVHSU46VkVWRU5UDQpEVFNUQVJUOjIwMTkwODE3VDEzMDAwMFoNCkRURU5EOjIwMTkwODE3 +VDE0MDAwMFoNCkRUU1RBTVA6MjAxOTA4MTdUMTAwNzU5Wg0KT1JHQU5JWkVSO0NOPWNtb2xsZWtv +cGZAZ21haWwuY29tOm1haWx0bzpjbW9sbGVrb3BmQGdtYWlsLmNvbQ0KVUlEOjB1NXAzMjZ2aDNs +ZTc5MHRhcm5xb3QwNnYyQGdvb2dsZS5jb20NCkFUVEVOREVFO0NVVFlQRT1JTkRJVklEVUFMO1JP +TEU9UkVRLVBBUlRJQ0lQQU5UO1BBUlRTVEFUPUFDQ0VQVEVEO1JTVlA9VFJVRQ0KIDtDTj1jbW9s +bGVrb3BmQGdtYWlsLmNvbTtYLU5VTS1HVUVTVFM9MDptYWlsdG86Y21vbGxla29wZkBnbWFpbC5j +b20NCkFUVEVOREVFO0NVVFlQRT1JTkRJVklEVUFMO1JPTEU9UkVRLVBBUlRJQ0lQQU5UO1BBUlRT +VEFUPU5FRURTLUFDVElPTjtSU1ZQPQ0KIFRSVUU7Q049dGVzdDFAa29sYWIub3JnO1gtTlVNLUdV +RVNUUz0wOm1haWx0bzp0ZXN0MUBrb2xhYi5vcmcNClgtTUlDUk9TT0ZULUNETy1PV05FUkFQUFRJ +RDotNzUwOTY4ODYwDQpDUkVBVEVEOjIwMTkwODE3VDEwMDc1NFoNCkRFU0NSSVBUSU9OOi06On46 +fjo6fjp+On46fjp+On46fjp+On46fjp+On46fjp+On46fjp+On46fjp+On46fjp+On46fjp+On46 +fg0KIDp+On46fjp+On46fjp+On46On46fjo6LVxuUGxlYXNlIGRvIG5vdCBlZGl0IHRoaXMgc2Vj +dGlvbiBvZiB0aGUgZGVzY3JpcHRpbw0KIG4uXG5cblZpZXcgeW91ciBldmVudCBhdCBodHRwczov +L3d3dy5nb29nbGUuY29tL2NhbGVuZGFyL2V2ZW50P2FjdGlvbj1WSUVXJg0KIGVpZD1NSFUxY0RN +eU5uWm9NMnhsTnprd2RHRnlibkZ2ZERBMmRqSWdkR1Z6ZERGQWEyOXNZV0l1YjNKbiZ0b2s9TWpB +alkyMXZiRw0KIHhsYTI5d1prQm5iV0ZwYkM1amIyMDROVGhoTmpjeU1HRXdOVFkyWVRabFltVTRa +RFE1WWpNMlptRXdORFJrWm1Wa05UVmtZak5sJg0KIGN0ej1FdXJvcGUlMkZadXJpY2gmaGw9ZW5f +R0ImZXM9MS5cbi06On46fjo6fjp+On46fjp+On46fjp+On46fjp+On46fjp+On46fg0KIDp+On46 +fjp+On46fjp+On46fjp+On46fjp+On46fjp+On46fjp+On46On46fjo6LQ0KTEFTVC1NT0RJRklF +RDoyMDE5MDgxN1QxMDA3NTRaDQpMT0NBVElPTjoNClNFUVVFTkNFOjANClNUQVRVUzpDT05GSVJN +RUQNClNVTU1BUlk6dGVzdDENClRSQU5TUDpPUEFRVUUNCkVORDpWRVZFTlQNCkVORDpWQ0FMRU5E +QVINCg== +--0000000000000d114f05904d4867-- diff --git a/framework/src/domain/mime/testdata/invitation.mbox b/framework/src/domain/mime/testdata/invitation.mbox new file mode 100644 index 00000000..bfce2ff8 --- /dev/null +++ b/framework/src/domain/mime/testdata/invitation.mbox @@ -0,0 +1,82 @@ +Return-Path: +MIME-Version: 1.0 +Content-Type: multipart/alternative; + boundary="=_d141ae2d08ab2e576b4155f7053a7d1f" +From: john doe +Date: Fri, 02 Aug 2019 21:02:28 +0200 +Message-ID: +X-Sender: john@doe.ch +To: test1@kolab.org +Subject: You've been invited to "test1234" + +--=_d141ae2d08ab2e576b4155f7053a7d1f +Content-Transfer-Encoding: quoted-printable +Content-Type: text/plain; charset=UTF-8; + format=flowed + +*test1234* + +When: 2019-08-01 10:00 - 10:30 (Europe/Zurich) + +Invitees: john doe , + John Doe , + test1@kolab.org + +Please find attached an iCalendar file with all the event details which you= +=20 +can import to your calendar application. + +In case your email client doesn't support iTip requests you can use the=20 +following link to either accept or decline this invitation: +https://kolabnow.com/apps/?_task=3Dcalendar&_action=3Dattend&_t=3D0a896de59= +2c86b51039f3ff8e127514ab6dbc396.dGVzdDFAa29sYWIub3Jn.d9bc91 +--=_d141ae2d08ab2e576b4155f7053a7d1f +Content-Transfer-Encoding: 8bit +Content-Type: text/calendar; charset=UTF-8; method=REQUEST; + name=event.ics + +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Roundcube libcalendaring 1.4-git//Sabre//Sabre VObject 3.5.3//EN +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VTIMEZONE +TZID:Europe/Zurich +BEGIN:STANDARD +DTSTART:20181028T010000 +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +END:STANDARD +BEGIN:DAYLIGHT +DTSTART:20190331T010000 +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +TZNAME:CEST +END:DAYLIGHT +BEGIN:STANDARD +DTSTART:20191027T010000 +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +UID:39946D057115AA1B6A273693CF95D35C-24397012EEE1180F +DTSTAMP:20190802T190228Z +CREATED:20190802T190228Z +LAST-MODIFIED:20190802T190228Z +DTSTART;TZID=Europe/Zurich:20190801T100000 +DTEND;TZID=Europe/Zurich:20190801T103000 +SUMMARY:test1234 +SEQUENCE:0 +TRANSP:OPAQUE +ATTENDEE;CN=John Doe;PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;CUTYPE=INDI + VIDUAL;RSVP=TRUE:mailto:doe2@test.ch +ATTENDEE;PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;CUTYPE=INDIVIDUAL;RSVP= + TRUE:mailto:test1@kolab.org +ORGANIZER;CN=john doe:mailto:john@doe.ch +END:VEVENT +END:VCALENDAR + +--=_d141ae2d08ab2e576b4155f7053a7d1f--