/* 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 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(ContentPart::Type ct) const; ContentPart *q; ContentPart::Types types() const; private: 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[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(ContentPart::Type ct) const { return mContent[ct]; } QVector ContentPart::content(ContentPart::Type ct) const { 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"; } 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; 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 (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 { 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;}); 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; }