diff --git a/framework/domain/mimetreeparser/interface.cpp b/framework/domain/mimetreeparser/interface.cpp index c239fcc0..e34ffda7 100644 --- a/framework/domain/mimetreeparser/interface.cpp +++ b/framework/domain/mimetreeparser/interface.cpp @@ -1,378 +1,367 @@ /* 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 "interface.h" +#include "interface_p.h" #include "stringhtmlwriter.h" #include "objecttreesource.h" #include #include #include #include #include -#include class PartPrivate { public: PartPrivate(Part *part); void appendSubPart(Part::Ptr subpart); QVector subParts(); Part *parent() const; private: Part *q; Part *mParent; QVector mSubParts; }; PartPrivate::PartPrivate(Part* part) : q(part) , mParent(Q_NULLPTR) { } void PartPrivate::appendSubPart(Part::Ptr subpart) { subpart->d->mParent = q; mSubParts.append(subpart); } Part *PartPrivate::parent() const { return mParent; } QVector< Part::Ptr > PartPrivate::subParts() { return mSubParts; } Part::Part() : d(std::unique_ptr(new PartPrivate(this))) { } bool Part::hasSubParts() const { return !subParts().isEmpty(); } QVector Part::subParts() const { return d->subParts(); } QByteArray Part::type() const { return "Part"; } QVector Part::encryptions() const { auto parent = d->parent(); if (parent) { return parent->encryptions(); } else { return QVector(); } } QVector Part::signatures() const { auto parent = d->parent(); if (parent) { return parent->signatures(); } else { return QVector(); } } class ContentPrivate { public: QByteArray mContent; QByteArray mCodec; Part *mParent; Content *q; }; Content::Content(const QByteArray& content, ContentPart *parent) : d(std::unique_ptr(new ContentPrivate)) { d->q = this; d->mContent = content; d->mCodec = "utf-8"; d->mParent = parent; } Content::~Content() { } QVector< Encryption > Content::encryptions() const { if (d->mParent) { return d->mParent->encryptions(); } return QVector(); } QVector< Signature > Content::signatures() const { if (d->mParent) { return d->mParent->signatures(); } return QVector(); } QByteArray Content::content() const { return d->mContent; } QByteArray Content::charset() const { return d->mCodec; } class ContentPartPrivate { public: void fillFrom(MimeTreeParser::TextMessagePart::Ptr part); void fillFrom(MimeTreeParser::HtmlMessagePart::Ptr part); void fillFrom(MimeTreeParser::AlternativeMessagePart::Ptr part); - QVector content() const; + QVector content(ContentPart::Type ct) const; ContentPart *q; ContentPart::Types types() const; - + private: - QVector mContent; + QMap> mContent; ContentPart::Types mTypes; }; void ContentPartPrivate::fillFrom(MimeTreeParser::TextMessagePart::Ptr part) { + qDebug() << "jepp"; mTypes = ContentPart::PlainText; foreach (const auto &mp, part->subParts()) { auto content = std::make_shared(mp->text().toLocal8Bit(), q); - mContent.append(content); + mContent[ContentPart::PlainText].append(content); } } void ContentPartPrivate::fillFrom(MimeTreeParser::HtmlMessagePart::Ptr part) { mTypes = ContentPart::Html; + auto content = std::make_shared(part->text().toLocal8Bit(), q); + mContent[ContentPart::Html].append(content); } void ContentPartPrivate::fillFrom(MimeTreeParser::AlternativeMessagePart::Ptr part) { mTypes = ContentPart::Html | ContentPart::PlainText; + + auto content = std::make_shared(part->htmlContent().toLocal8Bit(), q); + mContent[ContentPart::Html].append(content); + content = std::make_shared(part->plaintextContent().toLocal8Bit(), q); + mContent[ContentPart::PlainText].append(content); } ContentPart::Types ContentPartPrivate::types() const { return mTypes; } -QVector ContentPartPrivate::content() const +QVector ContentPartPrivate::content(ContentPart::Type ct) const { - return mContent; + return mContent[ct]; } QVector ContentPart::content(ContentPart::Type ct) const { - return d->content(); + return d->content(ct); } ContentPart::ContentPart() : d(std::unique_ptr(new ContentPartPrivate)) { d->q = this; } ContentPart::~ContentPart() { } QByteArray ContentPart::type() const { return "ContentPart"; } ContentPart::Types ContentPart::availableContents() const { return d->types(); } class MimePartPrivate { public: void fillFrom(MimeTreeParser::MessagePart::Ptr part); }; QByteArray MimePart::type() const { return "MimePart"; } class AttachmentPartPrivate { public: void fillFrom(MimeTreeParser::AttachmentMessagePart::Ptr part); }; void AttachmentPartPrivate::fillFrom(MimeTreeParser::AttachmentMessagePart::Ptr part) { } QByteArray AttachmentPart::type() const { return "AttachmentPart"; } -class ParserPrivate -{ -public: - ParserPrivate(Parser *parser); - - void setMessage(const QByteArray &mimeMessage); - void createTree(const MimeTreeParser::MessagePart::Ptr& start, const Part::Ptr& tree); - - Part::Ptr mTree; -private: - Parser *q; - - MimeTreeParser::MessagePart::Ptr mPartTree; - std::shared_ptr mNodeHelper; - QString mHtml; - QMap mEmbeddedPartMap; -}; - ParserPrivate::ParserPrivate(Parser* parser) : q(parser) , mNodeHelper(std::make_shared()) { } void ParserPrivate::setMessage(const QByteArray& mimeMessage) { const auto mailData = KMime::CRLFtoLF(mimeMessage); KMime::Message::Ptr msg(new KMime::Message); msg->setContent(mailData); msg->parse(); // render the mail StringHtmlWriter htmlWriter; - QImage paintDevice; ObjectTreeSource source(&htmlWriter); MimeTreeParser::ObjectTreeParser otp(&source, mNodeHelper.get()); otp.parseObjectTree(msg.data()); mPartTree = otp.parsedPart().dynamicCast(); mEmbeddedPartMap = htmlWriter.embeddedParts(); mHtml = htmlWriter.html(); mTree = std::make_shared(); createTree(mPartTree, mTree); } void ParserPrivate::createTree(const MimeTreeParser::MessagePart::Ptr &start, const Part::Ptr &tree) { foreach (const auto &mp, start->subParts()) { const auto m = mp.dynamicCast(); const auto text = mp.dynamicCast(); const auto alternative = mp.dynamicCast(); const auto html = mp.dynamicCast(); const auto attachment = mp.dynamicCast(); - if (text) { + if (attachment) { + auto part = std::make_shared(); + part->d->fillFrom(attachment); + mTree->d->appendSubPart(part); + } else if (text) { auto part = std::make_shared(); part->d->fillFrom(text); mTree->d->appendSubPart(part); } else if (alternative) { auto part = std::make_shared(); part->d->fillFrom(alternative); mTree->d->appendSubPart(part); } else if (html) { auto part = std::make_shared(); part->d->fillFrom(html); mTree->d->appendSubPart(part); - } else if (attachment) { - auto part = std::make_shared(); - part->d->fillFrom(attachment); - mTree->d->appendSubPart(part); } else { createTree(m, tree); } } } Parser::Parser(const QByteArray& mimeMessage) :d(std::unique_ptr(new ParserPrivate(this))) { d->setMessage(mimeMessage); } Parser::~Parser() { } ContentPart::Ptr Parser::collectContentPart(const Part::Ptr &start) const { - const auto ret = collect(start, [](const Part::Ptr &p){return p->type() == "ContentPart";}, [](const ContentPart::Ptr &p){return true;}); + const auto ret = collect(start, [](const Part::Ptr &p){return p->type() == "ContentPart";}, [](const ContentPart::Ptr &p){return true;}); if (ret.size() > 0) { return ret[0]; }; return ContentPart::Ptr(); } ContentPart::Ptr Parser::collectContentPart() const { return collectContentPart(d->mTree); } template QVector Parser::collect(const Part::Ptr &start, std::function select, std::function filter) const { QVector ret; foreach (const auto &part, start->subParts()) { if (select(part)){ const auto p = std::dynamic_pointer_cast(part); if (p && filter(p)) { ret.append(p); } ret += collect(part, select, filter); } } return ret; } diff --git a/framework/domain/mimetreeparser/interface.h b/framework/domain/mimetreeparser/interface.h index 8a0047ff..0aef7fd0 100644 --- a/framework/domain/mimetreeparser/interface.h +++ b/framework/domain/mimetreeparser/interface.h @@ -1,329 +1,332 @@ /* 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. */ #pragma once #include #include #include #include #include class Part; class PartPrivate; class MimePart; class MimePartPrivate; class ContentPart; class ContentPartPrivate; class EncryptionPart; class EncryptionPartPrivate; class AttachmentPart; class AttachmentPartPrivate; class EncapsulatedPart; class EncapsulatedPartPrivate; class CertPart; class CertPartPrivate; class Content; class ContentPrivate; class Key; class Signature; class Encryption; class Parser; class ParserPrivate; class Part { public: typedef std::shared_ptr Ptr; Part(); virtual QByteArray type() const; bool hasSubParts() const; QVector subParts() const; Part *parent() const; virtual QVector signatures() const; virtual QVector encryptions() const; private: std::unique_ptr d; friend class ParserPrivate; friend class PartPrivate; }; class Content { public: typedef std::shared_ptr Ptr; Content(const QByteArray &content, ContentPart *parent); virtual ~Content(); QByteArray content() const; QByteArray charset() const; //Use default charset QString encodedContent() const; // overwrite default charset with given charset QString encodedContent(QByteArray charset) const; virtual QVector signatures() const; virtual QVector encryptions() const; private: std::unique_ptr d; }; /* * A MessagePart that is based on a KMime::Content */ class MimePart : public Part { public: typedef std::shared_ptr Ptr; /** * Various possible values for the "Content-Disposition" header. */ enum Disposition { Invalid, ///< Default, invalid value Inline, ///< inline Attachment ///< attachment }; // interessting header parts of a KMime::Content QMimeType mimetype() const; Disposition disposition() const; QUrl label() const; QByteArray cid() const; QByteArray charset() const; // we wanna overrwrite the charset of the content, because some clients set the charset wrong void setCharset(QByteArray charset); // Unique identifier to ecactly this KMime::Content QByteArray link() const; QByteArray content() const; //Use default charset QString encodedContent() const; // overwrite default charset with given charset QString encodedContent(QByteArray charset) const; QByteArray type() const Q_DECL_OVERRIDE; private: std::unique_ptr d; }; /* * The main ContentPart * is MimePart a good parent class? * do we wanna need parts of the header of the connected KMime::Contents * usecases: * - * for htmlonly it is representating only one MimePart (ok) * for plaintext only also only one MimePart (ok) * for alternative, we are represating three messageparts * - "headers" do we return?, we can use setType to make it possible to select and than return these headers */ class ContentPart : public Part { public: typedef std::shared_ptr Ptr; enum Type { PlainText = 0x0001, Html = 0x0002 }; Q_DECLARE_FLAGS(Types, Type) ContentPart(); virtual ~ContentPart(); QVector content(Type ct) const; Types availableContents() const; QByteArray type() const Q_DECL_OVERRIDE; private: std::unique_ptr d; friend class ParserPrivate; }; Q_DECLARE_OPERATORS_FOR_FLAGS(ContentPart::Types); class AttachmentPart : public MimePart { public: typedef std::shared_ptr Ptr; QByteArray type() const Q_DECL_OVERRIDE; private: std::unique_ptr d; + friend class ParserPrivate; }; /* * Open Questions: * - How to make the string translateable for multiple clients, so that multiple clients can show same error messages, * that helps users to understand what is going on ? * - Does openpgp have translations already? */ class EncryptionError { public: int errorId() const; QString errorString() const; }; class EncryptionPart : public MimePart { public: typedef std::shared_ptr Ptr; QByteArray type() const Q_DECL_OVERRIDE; EncryptionError error() const; private: std::unique_ptr d; }; /* * we want to request complete headers like: * from/to... */ class EncapsulatedPart : public AttachmentPart { public: typedef std::shared_ptr Ptr; QByteArray type() const Q_DECL_OVERRIDE; //template QByteArray header(); private: std::unique_ptr d; }; /* * importing a cert GpgMe::ImportResult * checking a cert (if it is a valid cert) */ class CertPart : public AttachmentPart { public: typedef std::shared_ptr Ptr; QByteArray type() const Q_DECL_OVERRIDE; enum CertType { Pgp, SMime }; enum CertSubType { Public, Private }; CertType certType() const; CertSubType certSubType() const; int keyLength() const; private: std::unique_ptr d; }; class Key { QString keyid() const; QString name() const; QString email() const; QString comment() const; QVector emails() const; enum KeyTrust { Unknown, Undefined, Never, Marginal, Full, Ultimate }; KeyTrust keyTrust() const; bool isRevokation() const; bool isInvalid() const; bool isExpired() const; std::vector subkeys(); Key parentkey() const; }; class Signature { Key key() const; QDateTime creationDateTime() const; QDateTime expirationTime() const; bool neverExpires() const; //template <> StatusObject verify() const; }; /* * Normally the Keys for encryption are subkeys * for clients the parentkeys are "more interessting", because they store the name, email etc. * but a client may also wants show to what subkey the mail is really encrypted, an if this subkey isRevoked or something else */ class Encryption { std::vector recipients() const; }; class Parser { public: typedef std::shared_ptr Ptr; Parser(const QByteArray &mimeMessage); ~Parser(); Part::Ptr getPart(QUrl url); template QVector collect(const Part::Ptr &start, std::function select, std::function filter) const; QVector collectAttachments(Part::Ptr start, std::function select, std::function filter) const; ContentPart::Ptr collectContentPart(Part::Ptr start, std::function select, std::function filter) const; ContentPart::Ptr collectContentPart(const Part::Ptr& start) const; ContentPart::Ptr collectContentPart() const; //template <> QVector collect() const; //template <> static StatusObject verifySignature(const Signature signature) const; //template <> static StatusObject decrypt(const EncryptedPart part) const; signals: void partsChanged(); private: std::unique_ptr d; + + friend class InterfaceTest; }; diff --git a/framework/domain/mimetreeparser/interface_p.h b/framework/domain/mimetreeparser/interface_p.h new file mode 100644 index 00000000..f83af6eb --- /dev/null +++ b/framework/domain/mimetreeparser/interface_p.h @@ -0,0 +1,50 @@ +/* + 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. +*/ + +#pragma once + +#include "interface.h" + +#include +#include + +namespace MimeTreeParser +{ + class MessagePart; + class NodeHelper; + typedef QSharedPointer MessagePartPtr; +} + +class ParserPrivate +{ +public: + ParserPrivate(Parser *parser); + + void setMessage(const QByteArray &mimeMessage); + void createTree(const MimeTreeParser::MessagePartPtr& start, const Part::Ptr& tree); + + Part::Ptr mTree; +private: + Parser *q; + + MimeTreeParser::MessagePartPtr mPartTree; + std::shared_ptr mNodeHelper; + QString mHtml; + QMap mEmbeddedPartMap; +}; \ No newline at end of file diff --git a/framework/domain/mimetreeparser/tests/data/alternative.mbox b/framework/domain/mimetreeparser/tests/data/alternative.mbox index a2c58591..6522c34b 100644 --- a/framework/domain/mimetreeparser/tests/data/alternative.mbox +++ b/framework/domain/mimetreeparser/tests/data/alternative.mbox @@ -1,34 +1,28 @@ Return-Path: Date: Wed, 8 Jun 2016 20:34:44 -0700 From: Konqi To: konqi@kde.org Subject: A random subject with alternative contenttype MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="----=_Part_12345678_12345678" ------=_Part_12345678_12345678 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable If you can see this text it means that your email client couldn't display o= ur newsletter properly. Please visit this link to view the newsletter on our website: http://www.go= g.com/newsletter/ -=2D GOG.com Team - ------=_Part_12345678_12345678 Content-Transfer-Encoding: 7Bit Content-Type: text/html; charset="windows-1252" - - -

Some HTML text

+

HTML text

------=_Part_12345678_12345678-- diff --git a/framework/domain/mimetreeparser/tests/data/html.mbox b/framework/domain/mimetreeparser/tests/data/html.mbox index d476a8d4..bf5c685d 100644 --- a/framework/domain/mimetreeparser/tests/data/html.mbox +++ b/framework/domain/mimetreeparser/tests/data/html.mbox @@ -1,19 +1,15 @@ From foo@example.com Thu, 26 May 2011 01:16:54 +0100 From: Thomas McGuire Subject: HTML test Date: Thu, 26 May 2011 01:16:54 +0100 Message-ID: <1501334.pROlBb7MZF@herrwackelpudding.localhost> X-KMail-Transport: GMX X-KMail-Fcc: 28 X-KMail-Drafts: 7 X-KMail-Templates: 9 User-Agent: KMail/4.6 beta5 (Linux/2.6.34.7-0.7-desktop; KDE/4.6.41; x86_64; git-0269848; 2011-04-19) MIME-Version: 1.0 Content-Transfer-Encoding: 7Bit Content-Type: text/html; charset="windows-1252" - - -

Some HTML text

+

HTML text

\ No newline at end of file diff --git a/framework/domain/mimetreeparser/tests/data/htmlonly.mbox b/framework/domain/mimetreeparser/tests/data/htmlonly.mbox deleted file mode 100644 index e45b1c4d..00000000 --- a/framework/domain/mimetreeparser/tests/data/htmlonly.mbox +++ /dev/null @@ -1,21 +0,0 @@ -From foo@example.com Thu, 26 May 2011 01:16:54 +0100 -From: Thomas McGuire -Subject: HTML test -Date: Thu, 26 May 2011 01:16:54 +0100 -Message-ID: <1501334.pROlBb7MZF@herrwackelpudding.localhost> -X-KMail-Transport: GMX -X-KMail-Fcc: 28 -X-KMail-Drafts: 7 -X-KMail-Templates: 9 -User-Agent: KMail/4.6 beta5 (Linux/2.6.34.7-0.7-desktop; KDE/4.6.41; x86_64; git-0269848; 2011-04-19) -MIME-Version: 1.0 -Content-Type: text/html -Content-Transfer-Encoding: 7Bit - - - - - -SOME HTML text. - - diff --git a/framework/domain/mimetreeparser/tests/data/htmlonlyexternal.mbox b/framework/domain/mimetreeparser/tests/data/htmlonlyexternal.mbox deleted file mode 100644 index 4eb3e2c3..00000000 --- a/framework/domain/mimetreeparser/tests/data/htmlonlyexternal.mbox +++ /dev/null @@ -1,21 +0,0 @@ -From foo@example.com Thu, 26 May 2011 01:16:54 +0100 -From: Thomas McGuire -Subject: HTML test -Date: Thu, 26 May 2011 01:16:54 +0100 -Message-ID: <1501334.pROlBb7MZF@herrwackelpudding.localhost> -X-KMail-Transport: GMX -X-KMail-Fcc: 28 -X-KMail-Drafts: 7 -X-KMail-Templates: 9 -User-Agent: KMail/4.6 beta5 (Linux/2.6.34.7-0.7-desktop; KDE/4.6.41; x86_64; git-0269848; 2011-04-19) -MIME-Version: 1.0 -Content-Type: text/html -Content-Transfer-Encoding: 7Bit - - - - - -SOME HTML text. - - diff --git a/framework/domain/mimetreeparser/tests/data/openpgp-encrypted-attachment-and-non-encrypted-attachment.mbox b/framework/domain/mimetreeparser/tests/data/openpgp-encrypted-attachment-and-non-encrypted-attachment.mbox new file mode 100644 index 00000000..2d9726ea --- /dev/null +++ b/framework/domain/mimetreeparser/tests/data/openpgp-encrypted-attachment-and-non-encrypted-attachment.mbox @@ -0,0 +1,115 @@ +From test@kolab.org Fri May 01 15:12:47 2015 +From: testkey +To: you@you.com +Subject: enc & non enc attachment +Date: Fri, 01 May 2015 17:12:47 +0200 +Message-ID: <13897561.XENKdJMSlR@tabin.local> +X-KMail-Identity: 1197256126 +User-Agent: KMail/4.13.0.1 (Linux/3.19.1-towo.1-siduction-amd64; KDE/4.14.2; x86_64; git-cd33034; 2015-04-11) +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="nextPart1939768.sIoLGH0PD8" +Content-Transfer-Encoding: 7Bit + +This is a multi-part message in MIME format. + +--nextPart1939768.sIoLGH0PD8 +Content-Type: multipart/encrypted; boundary="nextPart2814166.CHKktCGlQ3"; protocol="application/pgp-encrypted" + + +--nextPart2814166.CHKktCGlQ3 +Content-Type: application/pgp-encrypted +Content-Disposition: attachment +Content-Transfer-Encoding: 7Bit + +Version: 1 +--nextPart2814166.CHKktCGlQ3 +Content-Type: application/octet-stream +Content-Disposition: inline; filename="msg.asc" +Content-Transfer-Encoding: 7Bit + +-----BEGIN PGP MESSAGE----- +Version: GnuPG v2 + +hIwDGJlthTT7oq0BA/9cXFQ6mN9Vxnc2B9M10odS3/6z1tsIY9oJdsiOjpfxqapX +P7nOzR/jNWdFQanXoG1SjAcY2FeZEN0c3SkxEM6R5QVF1vMh/Xsni1clI+peZyVT +Z4OSU74YCfYLg+cgDnPCF3kyNPVe6Z1pnfWOCZNCG3rpApw6UVLN63ScWC6eQIUB +DAMMzkNap8zaOwEIANKHn1svvj+hBOIZYf8R+q2Bw7cd4xEChiJ7uQLnD98j0Fh1 +85v7/8JbZx6rEDDenPp1mCciDodb0aCmi0XLuzJz2ANGTVflfq+ZA+v1pwLksWCs +0YcHLEjOJzjr3KKmvu6wqnun5J2yV69K3OW3qTTGhNvcYZulqQ617pPa48+sFCgh +nM8TMAD0ElVEwmMtrS3AWoJz52Af+R3YzpAnX8NzV317/JG+b6e2ksl3tR7TWp1q +2FOqC1sXAxuv+DIz4GgRfaK1+xYr2ckkg+H/3HJqa5LmJ7rGCyv+Epfp9u+OvdBG +PBvuCtO3tm0crmnttMw57Gy35BKutRf/8MpBj/nS6QFX0t7XOLeL4Me7/a2H20wz +HZsuRGDXMCh0lL0FYCBAwdbbYvvy0gz/5iaNvoADtaIu+VtbFNrTUN0SwuL+AIFS ++WIiaSbFt4Ng3t9YmqL6pqB7fjxI10S+PK0s7ABqe4pgbzUWWt1yzBcxfk8l/47Q +JrlvcE7HuDOhNOHfZIgUP2Dbeu+pVvHIJbmLsNWpl4s+nHhoxc9HrVhYG/MTZtQ3 +kkUWviegO6mwEZjQvgBxjWib7090sCxkO847b8A93mfQNHnuy2ZEEJ+9xyk7nIWs +4RsiNR8pYc/SMvdocyAvQMH/qSvmn/IFJ+jHhtT8UJlXJ0bHvXTHjHMqBp6fP69z +Jh1ERadWQdMaTkzQ+asl+kl/x3p6RZP8MEVbZIl/3pcV+xiFCYcFu2TETKMtbW+b +NYOlrltFxFDvyu3WeNNp0g9k0nFpD/T1OXHRBRcbUDWE4QF6NWTm6NO9wy2UYHCi +7QTSecBWgMaw7cUdwvnW6chIVoov1pm69BI9D0PoV76zCI7KzpiDsTFxdilKwbQf +K/PDnv9Adx3ERh0/F8llBHrj2UGsRs4aHSEBDBJIHDCp8+lqtsRcINQBKEU3qIjt +wf5vizdaVIgQnsD2z8QmBQ7QCCipI0ur6GKl+YWDDOSDLDUs9dK4A6xo/4Q0bsnI +rH63ti5HslGq6uArfFkewH2MWff/8Li3uGEqzpK5NhP5UpbArelK+QaQQP5SdsmW +XFwUqDS4QTCKNJXw/5SQMl8UE10l2Xaav3TkiOYTcBcvPNDovYgnMyRff/tTeFa8 +83STkvpGtkULkCntp22fydv5rg6DZ7eJrYfC2oZXdM87hHhUALUO6Y/VtVmNdNYw +F3Uim4PDuLIKt+mFqRtFqnWm+5X/AslC31qLkjH+Fbb83TY+mC9gbIn7CZGJRCjn +zzzMX2h15V/VHzNUgx9V/h28T0/z25FxoozZiJxpmhOtqoxMHp+y6nXXfMoIAD1D +963Pc7u1HS0ny54A7bqc6KKd4W9IF7HkXn3SoBwCyn0IOPoKQTDD8mW3lbBI6+h9 +vP+MAQpfD8s+3VZ9r7OKYCVmUv47ViTRlf428Co6WT7rTHjGM09tqz826fTOXA== +=6Eu9 +-----END PGP MESSAGE----- + +--nextPart2814166.CHKktCGlQ3-- + +--nextPart1939768.sIoLGH0PD8 +Content-Disposition: attachment; filename="image.png" +Content-Transfer-Encoding: base64 +Content-Type: image/png; name="image.png" + +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 +o/0d59+Lh3Y1HHcAAAAASUVORK5CYII= + +--nextPart1939768.sIoLGH0PD8-- + diff --git a/framework/domain/mimetreeparser/tests/data/openpgp-inline-charset-encrypted.mbox b/framework/domain/mimetreeparser/tests/data/openpgp-inline-charset-encrypted.mbox new file mode 100644 index 00000000..8bd06910 --- /dev/null +++ b/framework/domain/mimetreeparser/tests/data/openpgp-inline-charset-encrypted.mbox @@ -0,0 +1,40 @@ +From test@example.com Thu, 17 Oct 2013 02:13:03 +0200 +Return-Path: +Delivered-To: you@you.com +Received: from localhost (localhost [127.0.0.1]) + by test@example.com (Postfix) with ESMTP id B30D8120030 + for ; Thu, 17 Oct 2013 02:13:05 +0200 (CEST) +From: test +To: you@you.com +Subject: charset +Date: Thu, 17 Oct 2013 02:13:03 +0200 +Message-ID: <4081645.yGjUJ4o4Se@example.local> +User-Agent: KMail/4.12 pre (Linux/3.11-4.towo-siduction-amd64; KDE/4.11.2; x86_64; git-f7f14e3; 2013-10-15) +MIME-Version: 1.0 +Content-Transfer-Encoding: 7Bit +Content-Type: text/plain; charset="ISO-8859-15" + +-----BEGIN PGP MESSAGE----- +Version: GnuPG v2.0.22 (GNU/Linux) + +hIwDGJlthTT7oq0BBACbaRZudMigMTetPZNRgkfEXv4QQowR1jborw0dcgKKqMQ1 +6o67NkpxvmXKGJTfTVCLBX3nk6FKYo6NwlPCyU7X9X0DDk8hvaBdR9wGfrdm5YWX +GKOzcqJY1EypiMsspXeZvjzEW7O8I956c3vBb/2pM3xqYEK1kh8+d9bVH+cjf4UB +DAMMzkNap8zaOwEH/1rPShyYL8meJN+/GGgS8+Nf1BW5pSHdAPCg0dnX4QCLEx7u +GkBU6N4JGYayaCBofibOLacQPhYZdnR5Xb/Pvrx03GrzyzyDp0WyeI9nGNfkani7 +sCRWbzlMPsEvGEvJVnMLNRSk4xhPIWumL4APkw+Mgi6mf+Br8z0RhfnGwyMA53Mr +pG9VQKlq3v7/aaN40pMjAsxiytcHS515jXrb3Ko4pWbTlAr/eytOEfkLRJgSOpQT +BY7lWs+UQJqiG8Yn65vS9LMDNJgX9EOGx77Z4u9wvv4ZieOxzgbHGg5kYCoae7ba +hxZeNjYKscH+E6epbOxM/wlTdr4UTiiW9dMsH0zSwMUB891gToeXq+LDGEPTKVSX +tsJm4HS/kISJBwrCI4EUqWZML6xQ427NkZGmF2z/sD3kmL66GjspIKnb4zHmXacp +84n2KrI9s7p6AnKnQjsxvB/4/lpXPCIY5GH7KjySEJiMsHECzeN1dJSL6keykBsx +DtmYDA+dhZ6UWbwzx/78+mjNREhyp/UiSAmLzlJh89OH/xelAPvKcIosYwz4cY9N +wjralTmL+Y0aHKeZJOeqPLaXADcPFiZrCNPCH65Ey5GEtDpjLpEbjVbykPV9+YkK +7JKW6bwMraOl5zmAoR77PWMo3IoYb9q4GuqDr1V2ZGlb7eMH1gj1nfgfVintKC1X +3jFfy7aK6LIQDVKEwbi0SxVXTKStuliVUy5oX4woDOxmTEotJf1QlKZpn5oF20UP +tumYrp0SPoP8Bo4EVRVaLupduI5cYce1q/kFj9Iho/wk56MoG9PxMMfsH7oKg3AA +CqQ6/kM4oJNdN5xIf1EH5HeaNFkDy1jlLznnhwVAZKPo/9ffpg== +=bPqu +-----END PGP MESSAGE----- + + diff --git a/framework/domain/mimetreeparser/tests/data/plaintext.mbox b/framework/domain/mimetreeparser/tests/data/plaintext.mbox index c2e00a35..d185b1c1 100644 --- a/framework/domain/mimetreeparser/tests/data/plaintext.mbox +++ b/framework/domain/mimetreeparser/tests/data/plaintext.mbox @@ -1,17 +1,13 @@ Return-Path: Date: Wed, 8 Jun 2016 20:34:44 -0700 From: Konqi To: konqi@kde.org Subject: A random subject with alternative contenttype MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable If you can see this text it means that your email client couldn't display o= ur newsletter properly. Please visit this link to view the newsletter on our website: http://www.go= g.com/newsletter/ - -=2D GOG.com Team - - diff --git a/framework/domain/mimetreeparser/tests/data/smime-encrypted.mbox b/framework/domain/mimetreeparser/tests/data/smime-encrypted.mbox new file mode 100644 index 00000000..6b6d6a0d --- /dev/null +++ b/framework/domain/mimetreeparser/tests/data/smime-encrypted.mbox @@ -0,0 +1,22 @@ +From test@example.com Sat, 13 Apr 2013 01:54:30 +0200 +From: test +To: you@you.com +Subject: test +Date: Sat, 13 Apr 2013 01:54:30 +0200 +Message-ID: <1576646.QQxzHWx8dA@tabin> +X-KMail-Identity: 505942601 +User-Agent: KMail/4.10.2 (Linux/3.9.0-rc4-experimental-amd64; KDE/4.10.60; x86_64; git-fc9b82c; 2013-04-11) +MIME-Version: 1.0 +Content-Type: application/pkcs7-mime; name="smime.p7m"; smime-type="enveloped-data" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7m" + +MIAGCSqGSIb3DQEHA6CAMIACAQAxgfwwgfkCAQAwYjBVMQswCQYDVQQGEwJVUzENMAsGA1UECgwE +S0RBQjEWMBQGA1UEAwwNdW5pdHRlc3QgY2VydDEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxl +LmNvbQIJANNFIDoYY4XJMA0GCSqGSIb3DQEBAQUABIGAJwmmaOeidXUHSQGOf2OBIsPYafVqdORe +y54pEXbXiAfSVUWgI4a9CsiWwcDX8vlaX9ZLLr+L2VmOfr6Yc5214yxzausZVvnUFjy6LUXotuEX +tSar4EW7XI9DjaZc1l985naMsTx9JUa5GyQ9J6PGqhosAKpKMGgKkFAHaOwE1/IwgAYJKoZIhvcN +AQcBMBQGCCqGSIb3DQMHBAieDfmz3WGbN6CABHgEpsLrNn0PAZTDUfNomDypvSCl5bQH+9cKm80m +upMV2r8RBiXS7OaP4SpCxq18afDTTPatvboHIoEX92taTbq8soiAgEs6raSGtEYZNvFL0IYqm7MA +o5HCOmjiEcInyPf14lL3HnPk10FaP3hh58qTHUh4LPYtL7UECOZELYnUfUVhAAAAAAAAAAAAAA== + diff --git a/framework/domain/mimetreeparser/tests/interfacetest.cpp b/framework/domain/mimetreeparser/tests/interfacetest.cpp index fd828960..88691539 100644 --- a/framework/domain/mimetreeparser/tests/interfacetest.cpp +++ b/framework/domain/mimetreeparser/tests/interfacetest.cpp @@ -1,70 +1,145 @@ /* 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 "interface.h" +#include "interface_p.h" #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 InterfaceTest : public QObject { Q_OBJECT +private: + void printTree(const Part::Ptr &start, QString pre) + { + foreach (const auto &part, start->subParts()) { + qWarning() << QStringLiteral("%1* %2").arg(pre).arg(QString::fromLatin1(part->type())); + printTree(part,pre + QStringLiteral(" ")); + } + } + private slots: void testTextMail() { Parser parser(readMailFromFile("plaintext.mbox")); auto contentPart = parser.collectContentPart(); QVERIFY((bool)contentPart); QCOMPARE(contentPart->availableContents(), ContentPart::PlainText); auto contentList = contentPart->content(ContentPart::PlainText); QCOMPARE(contentList.size(), 1); - QCOMPARE(contentList[0]->content(), 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\n- GOG.com Team\n\n").toLocal8Bit()); + QCOMPARE(contentList[0]->content(), 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/").toLocal8Bit()); QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit()); QCOMPARE(contentList[0]->encryptions().size(), 0); QCOMPARE(contentList[0]->signatures().size(), 0); + + contentList = contentPart->content(ContentPart::Html); + QCOMPARE(contentList.size(), 0); } void testTextAlternative() { Parser parser(readMailFromFile("alternative.mbox")); auto contentPart = parser.collectContentPart(); QVERIFY((bool)contentPart); QCOMPARE(contentPart->availableContents(), ContentPart::PlainText | ContentPart::Html); + auto contentList = contentPart->content(ContentPart::PlainText); + QCOMPARE(contentList.size(), 1); + QCOMPARE(contentList[0]->content(), 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").toLocal8Bit()); + QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit()); + QCOMPARE(contentList[0]->encryptions().size(), 0); + QCOMPARE(contentList[0]->signatures().size(), 0); + + contentList = contentPart->content(ContentPart::Html); + QCOMPARE(contentList.size(), 1); + QCOMPARE(contentList[0]->content(), QStringLiteral("

HTML text

\n\n").toLocal8Bit()); + QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit()); + QCOMPARE(contentList[0]->encryptions().size(), 0); + QCOMPARE(contentList[0]->signatures().size(), 0); } void testTextHtml() { Parser parser(readMailFromFile("html.mbox")); auto contentPart = parser.collectContentPart(); QVERIFY((bool)contentPart); QCOMPARE(contentPart->availableContents(), ContentPart::Html); + + auto contentList = contentPart->content(ContentPart::PlainText); + QCOMPARE(contentList.size(), 0); + + contentList = contentPart->content(ContentPart::Html); + QCOMPARE(contentList.size(), 1); + QCOMPARE(contentList[0]->content(), QStringLiteral("

HTML text

").toLocal8Bit()); + QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit()); + QCOMPARE(contentList[0]->encryptions().size(), 0); + QCOMPARE(contentList[0]->signatures().size(), 0); + } + + void testSMimeEncrypted() + { + Parser parser(readMailFromFile("smime-encrypted.mbox")); + printTree(parser.d->mTree,QString()); + auto contentPart = parser.collectContentPart(); + QVERIFY((bool)contentPart); + QCOMPARE(contentPart->availableContents(), ContentPart::PlainText); + auto contentList = contentPart->content(ContentPart::PlainText); + QCOMPARE(contentList.size(), 1); + QCOMPARE(contentList[0]->content(), QStringLiteral("The quick brown fox jumped over the lazy dog.").toLocal8Bit()); + QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit()); + } + + void testOpenPGPEncryptedAttachment() + { + Parser parser(readMailFromFile("openpgp-encrypted-attachment-and-non-encrypted-attachment.mbox")); + printTree(parser.d->mTree,QString()); + auto contentPart = parser.collectContentPart(); + QVERIFY((bool)contentPart); + QCOMPARE(contentPart->availableContents(), ContentPart::PlainText); + auto contentList = contentPart->content(ContentPart::PlainText); + QCOMPARE(contentList.size(), 1); + QCOMPARE(contentList[0]->content(), QStringLiteral("test text").toLocal8Bit()); + QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit()); + } + + void testOpenPPGInline() + { + Parser parser(readMailFromFile("openpgp-inline-charset-encrypted.mbox")); + printTree(parser.d->mTree,QString()); + auto contentPart = parser.collectContentPart(); + QVERIFY((bool)contentPart); + QCOMPARE(contentPart->availableContents(), ContentPart::PlainText); + auto contentList = contentPart->content(ContentPart::PlainText); + QCOMPARE(contentList.size(), 1); + QCOMPARE(contentList[0]->content(), QStringLiteral("asdasd asd asd asdf sadf sdaf sadf äöü").toLocal8Bit()); + QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit()); } }; QTEST_GUILESS_MAIN(InterfaceTest) #include "interfacetest.moc" \ No newline at end of file