diff --git a/plugins/messageviewer/bodypartformatter/semantic/CMakeLists.txt b/plugins/messageviewer/bodypartformatter/semantic/CMakeLists.txt index 01e43176..cc523858 100644 --- a/plugins/messageviewer/bodypartformatter/semantic/CMakeLists.txt +++ b/plugins/messageviewer/bodypartformatter/semantic/CMakeLists.txt @@ -1,22 +1,23 @@ set(semantic_plugin_srcs semantic_plugin.cpp semanticmemento.cpp semanticprocessor.cpp semanticrenderer.cpp semanticurlhandler.cpp ) ecm_qt_declare_logging_category(semantic_plugin_srcs HEADER semantic_debug.h IDENTIFIER SEMANTIC_LOG CATEGORY_NAME org.kde.pim.messageviewer.semantic) qt5_add_resources(semantic_plugin_srcs templates.qrc) add_library(messageviewer_bodypartformatter_semantic MODULE ${semantic_plugin_srcs}) target_compile_definitions(messageviewer_bodypartformatter_semantic PRIVATE -DTRANSLATION_DOMAIN=\"messageviewer_semantic_plugin\") target_link_libraries(messageviewer_bodypartformatter_semantic KF5::MessageViewer KF5::CalendarSupport KF5::I18n Grantlee5::Templates Qt5::DBus KF5::Prison KPim::Itinerary + KPim::PkPass ) install(TARGETS messageviewer_bodypartformatter_semantic DESTINATION ${KDE_INSTALL_PLUGINDIR}/messageviewer/bodypartformatter) diff --git a/plugins/messageviewer/bodypartformatter/semantic/semantic_plugin.cpp b/plugins/messageviewer/bodypartformatter/semantic/semantic_plugin.cpp index 19ee5b65..197c2d01 100644 --- a/plugins/messageviewer/bodypartformatter/semantic/semantic_plugin.cpp +++ b/plugins/messageviewer/bodypartformatter/semantic/semantic_plugin.cpp @@ -1,61 +1,61 @@ /* Copyright (c) 2017 Volker Krause 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 "semanticprocessor.h" #include "semanticrenderer.h" #include "semanticurlhandler.h" #include #include namespace { class SemanticPlugin : public QObject, public MimeTreeParser::Interface::BodyPartFormatterPlugin, public MessageViewer::MessagePartRenderPlugin { Q_OBJECT Q_INTERFACES(MimeTreeParser::Interface::BodyPartFormatterPlugin) Q_INTERFACES(MessageViewer::MessagePartRenderPlugin) Q_PLUGIN_METADATA(IID "com.kde.messageviewer.bodypartformatter" FILE "semantic_plugin.json") public: const MimeTreeParser::Interface::BodyPartFormatter *bodyPartFormatter(int idx) const override { - if (idx < 3) { + if (idx < 4) { return new SemanticProcessor(); } return nullptr; } MessageViewer::MessagePartRendererBase *renderer(int idx) override { if (idx == 0) { return new SemanticRenderer(); } return nullptr; } const MessageViewer::Interface::BodyPartURLHandler *urlHandler(int idx) const override { if (idx == 0) { return new SemanticUrlHandler(); } return nullptr; } }; } #include "semantic_plugin.moc" diff --git a/plugins/messageviewer/bodypartformatter/semantic/semantic_plugin.json b/plugins/messageviewer/bodypartformatter/semantic/semantic_plugin.json index 2a9351fb..f243df9e 100644 --- a/plugins/messageviewer/bodypartformatter/semantic/semantic_plugin.json +++ b/plugins/messageviewer/bodypartformatter/semantic/semantic_plugin.json @@ -1,10 +1,11 @@ { "formatter": [ { "mimetype": "text/html" }, { "mimetype": "text/plain" }, - { "mimetype": "application/pdf" } + { "mimetype": "application/pdf" }, + { "mimetype": "application/vnd.apple.pkpass" } ], "renderer": [ { "type": "MimeTreeParser::MessagePartList" } ] } diff --git a/plugins/messageviewer/bodypartformatter/semantic/semanticprocessor.cpp b/plugins/messageviewer/bodypartformatter/semantic/semanticprocessor.cpp index eae87e18..93c734b7 100644 --- a/plugins/messageviewer/bodypartformatter/semantic/semanticprocessor.cpp +++ b/plugins/messageviewer/bodypartformatter/semantic/semanticprocessor.cpp @@ -1,130 +1,140 @@ /* Copyright (c) 2017 Volker Krause 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 "semanticprocessor.h" #include "semanticmemento.h" #include "semantic_debug.h" #include #include #include #include #include +#include + #include #include using namespace KItinerary; std::weak_ptr SemanticProcessor::s_repository; SemanticProcessor::SemanticProcessor() { m_repository = s_repository.lock(); if (!m_repository) { m_repository.reset(new ExtractorRepository); s_repository = m_repository; } } SemanticProcessor::~SemanticProcessor() = default; MimeTreeParser::MessagePart::Ptr SemanticProcessor::process(MimeTreeParser::Interface::BodyPart &part) const { auto nodeHelper = part.nodeHelper(); if (!nodeHelper) { return {}; } auto memento = dynamic_cast(nodeHelper->bodyPartMemento(part.topLevelContent(), "org.kde.messageviewer.semanticData")); if (!memento) { memento = new SemanticMemento; nodeHelper->setBodyPartMemento(part.topLevelContent(), "org.kde.messageviewer.semanticData", memento); } // check if we still have to do anything at all if (memento->hasStructuredData()) { return {}; } if (memento->isParsed(part.content()->index())) { return {}; } memento->setParsed(part.content()->index()); qCDebug(SEMANTIC_LOG) << "-------------------------------------------- BEGIN SEMANTIC PARSING"; qCDebug(SEMANTIC_LOG) << part.content()->contentType()->mimeType(); // look for structured data first, cheaper and better quality - if (part.content()->contentType()->mimeType() == "text/html") { + if (part.content()->contentType()->isHTMLText()) { StructuredDataExtractor extractor; extractor.parse(part.content()->decodedText()); const auto data = extractor.data(); const auto decodedData = JsonLdDocument::fromJson(data); if (data.size() != decodedData.size()) { qCDebug(SEMANTIC_LOG).noquote() << "Unhandled content:" << QJsonDocument(data).toJson(); } if (!decodedData.isEmpty()) { memento->setData(decodedData); memento->setStructuredDataFound(true); qCDebug(SEMANTIC_LOG) << "Found structured data:" << decodedData; } } // try the unstructured data extractor as a fallback if (memento->isEmpty()) { - const auto extractors = m_repository->extractorsForMessage(part.content()); + std::vector extractors; + std::unique_ptr pass; + if (part.content()->contentType()->mimeType() == "application/vnd.apple.pkpass") { + pass.reset(KPkPass::Pass::fromData(part.content()->decodedContent())); + extractors = m_repository->extractorsForPass(pass.get()); + } else { + extractors = m_repository->extractorsForMessage(part.content()); + } if (extractors.empty()) { + qCDebug(SEMANTIC_LOG) << "Found no suitable extractors."; return {}; } qCDebug(SEMANTIC_LOG) << "Found unstructured extractor rules for message" << extractors.size(); ExtractorPreprocessor preproc; if (part.content()->contentType()->isPlainText()) { preproc.preprocessPlainText(part.content()->decodedText()); } else if (part.content()->contentType()->isHTMLText()) { preproc.preprocessHtml(part.content()->decodedText()); } else if (part.content()->contentType()->mimeType() == "application/pdf") { preproc.preprocessPdf(part.content()->decodedContent()); - } else { - return {}; } for (auto extractor : extractors) { ExtractorEngine engine; engine.setExtractor(extractor); engine.setSenderDate(static_cast(part.content()->topLevel())->date()->dateTime()); engine.setText(preproc.text()); + engine.setPass(pass.get()); const auto data = engine.extract(); qCDebug(SEMANTIC_LOG).noquote() << QJsonDocument(data).toJson(); const auto decodedData = JsonLdDocument::fromJson(data); if (!decodedData.isEmpty()) { memento->setData(decodedData); break; } } } // postprocessor to filter incomplete/broken elements and merge duplicates ExtractorPostprocessor postproc; + postproc.setContextDate(static_cast(part.content()->topLevel())->date()->dateTime()); postproc.process(memento->data()); memento->setData(postproc.result()); qCDebug(SEMANTIC_LOG) << "-------------------------------------------- END SEMANTIC PARSING"; return {}; }