Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F34385083
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
31 KB
Subscribers
None
View Options
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 48d8291..e6c4951 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,113 +1,112 @@
# SPDX-FileCopyrightText: 2023 Carl Schwan <carl.schwan@gnupg.com>
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16 FATAL_ERROR)
set(PIM_VERSION "6.1.40")
project(MimeTreeParserNG VERSION ${PIM_VERSION})
# ECM setup
set(KF_MIN_VERSION "6.3.0")
find_package(ECM ${KF_MIN_VERSION} CONFIG REQUIRED)
set(CMAKE_MODULE_PATH
${CMAKE_MODULE_PATH}
${ECM_MODULE_PATH}
${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules
)
set(QT_REQUIRED_VERSION "6.6.0")
include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDECompilerSettings NO_POLICY_SCOPE)
include(GenerateExportHeader)
include(ECMGenerateHeaders)
include(ECMGeneratePriFile)
include(ECMQmlModule)
include(ECMSetupVersion)
include(FeatureSummary)
include(KDEGitCommitHooks)
include(KDEClangFormat)
file(GLOB_RECURSE ALL_CLANG_FORMAT_SOURCE_FILES *.cpp *.h *.c)
kde_clang_format(${ALL_CLANG_FORMAT_SOURCE_FILES})
include(ECMQtDeclareLoggingCategory)
include(ECMDeprecationSettings)
include(ECMFeatureSummary)
include(ECMAddQch)
include(ECMAddTests)
set(KPIM_MIME_VERSION "6.1.40")
set(KPIM_LIBKLEO_VERSION "6.1.40")
set(KPIM_MBOX_VERSION "6.1.40")
set(GPGME_REQUIRED_VERSION "1.20.0")
ecm_setup_version(PROJECT
VARIABLE_PREFIX MIMETREEPARSERNG
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/mimetreeparserng_version.h"
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KPim6MimeTreeParserCoreConfigVersion.cmake"
SOVERSION 6
)
configure_file(mimetreeparserng-version.h.in ${CMAKE_CURRENT_BINARY_DIR}/src/mimetreeparserng-version.h @ONLY)
option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF)
add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)")
if(BUILD_TESTING)
add_definitions(-DBUILD_TESTING)
endif()
########### Find packages ###########
find_package(Qt6Gui ${QT_REQUIRED_VERSION} CONFIG REQUIRED)
find_package(Qt6PrintSupport ${QT_REQUIRED_VERSION} CONFIG REQUIRED)
find_package(KF6I18n ${KF_MIN_VERSION} CONFIG REQUIRED)
-find_package(KF6Codecs ${KF_MIN_VERSION} CONFIG REQUIRED)
find_package(KF6CalendarCore ${KF_MIN_VERSION} CONFIG REQUIRED)
find_package(KF6WidgetsAddons ${KF_MIN_VERSION} CONFIG)
find_package(KPim6Mime ${KPIM_MIME_VERSION} CONFIG REQUIRED)
find_package(KPim6Mbox ${KPIM_MBOX_VERSION} CONFIG REQUIRED)
find_package(KPim6Libkleo ${KPIM_LIBKLEO_VERSION} CONFIG REQUIRED)
find_package(Gpgmepp ${GPGME_REQUIRED_VERSION} CONFIG REQUIRED)
find_package(Qt6Quick ${QT_REQUIRED_VERSION} CONFIG)
find_package(Qt6Widgets ${QT_REQUIRED_VERSION} CONFIG)
if (BUILD_TESTING)
find_package(Qt6Test ${QT_REQUIRED_VERSION} CONFIG REQUIRED)
endif()
########### Targets ###########
add_definitions(-DQT_NO_CONTEXTLESS_CONNECT)
ecm_set_disabled_deprecation_versions(QT 6.7.0 KF 6.4.0)
option(USE_UNITY_CMAKE_SUPPORT "Use UNITY cmake support (speedup compile time)" OFF)
set(COMPILE_WITH_UNITY_CMAKE_SUPPORT OFF)
if (USE_UNITY_CMAKE_SUPPORT)
set(COMPILE_WITH_UNITY_CMAKE_SUPPORT ON)
add_definitions(-DCOMPILE_WITH_UNITY_CMAKE_SUPPORT)
endif()
add_subdirectory(src)
if (BUILD_TESTING)
add_subdirectory(examples)
add_subdirectory(autotests)
endif()
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/mimetreeparserng_version.h
DESTINATION ${KDE_INSTALL_INCLUDEDIR}/KPim6/MimeTreeParserCore
COMPONENT Devel
)
ecm_qt_install_logging_categories(
EXPORT MIMETREEPARSERNG
FILE mimetreeparser.categories
DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR}
)
kde_configure_git_pre_commit_hook(CHECKS CLANG_FORMAT)
ki18n_install(po)
ecm_feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 4dff725..8581591 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -1,178 +1,177 @@
# SPDX-FileCopyrightText: 2023 Carl Schwan <carl.schwan@gnupg.com>
# SPDX-License-Identifier: BSD-3-Clause
ecm_setup_version(PROJECT
VARIABLE_PREFIX MIMETREEPARSER_CORE
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/mimetreeparser_core_version.h"
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KPim6MimeTreeParserCoreConfigVersion.cmake"
SOVERSION 6
)
# public dynamic library
add_library(KPim6MimeTreeParserCore)
add_library(KPim6::MimeTreeParserCore
ALIAS KPim6MimeTreeParserCore
)
ecm_qt_declare_logging_category(KPim6MimeTreeParserCore
HEADER mimetreeparser_core_debug.h
IDENTIFIER MIMETREEPARSER_CORE_LOG
CATEGORY_NAME org.kde.pim.mimetreeparser.core
DESCRIPTION "mimetreeparser (pim lib)"
EXPORT MIMETREEPARSERNG
)
target_sources(KPim6MimeTreeParserCore PRIVATE
errors.h
attachmentmodel.h
bodypartformatter.h
bodypartformatterbasefactory.h
bodypartformatterbasefactory_p.h
cryptohelper.h
enums.h
fileopener.h
htmlutils.h
messageparser.h
messagepart.h
objecttreeparser.h
partmetadata.h
partmodel.h
utils.h
attachmentmodel.cpp
bodypartformatter.cpp
bodypartformatter_impl.cpp
bodypartformatterbasefactory.cpp
cryptohelper.cpp
fileopener.cpp
htmlutils.cpp
messageparser.cpp
messagepart.cpp
objecttreeparser.cpp
partmodel.cpp
utils.cpp
)
if (COMPILE_WITH_UNITY_CMAKE_SUPPORT)
set_target_properties(KPim6MimeTreeParserCore PROPERTIES UNITY_BUILD ON)
endif()
generate_export_header(KPim6MimeTreeParserCore BASE_NAME mimetreeparser_core)
target_include_directories(KPim6MimeTreeParserCore
INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR}/KPim6/MimeTreeParserCore>")
target_link_libraries(KPim6MimeTreeParserCore
PUBLIC
KPim6::Mime
KPim6::Mbox
KF6::I18n
Qt::Gui
PRIVATE
- KF6::Codecs
Gpgmepp
KPim6::Libkleo
)
set_target_properties(KPim6MimeTreeParserCore PROPERTIES
VERSION ${MIMETREEPARSERNG_VERSION}
SOVERSION ${MIMETREEPARSERNG_SOVERSION}
EXPORT_NAME MimeTreeParserCore
)
ecm_generate_pri_file(BASE_NAME MimeTreeParserCore
LIB_NAME KPim6MimeTreeParserCore
DEPS "MimeTreeParserCore"
FILENAME_VAR PRI_FILENAME
)
install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR})
install(TARGETS
KPim6MimeTreeParserCore
EXPORT KPim6MimeTreeParserCoreTargets ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}
)
ecm_generate_headers(MimeTreeParserCore_CamelCase_HEADERS
HEADER_NAMES
AttachmentModel
CryptoHelper
Errors
FileOpener
MessageParser
MessagePart
ObjectTreeParser
PartModel
PartMetaData
Enums
REQUIRED_HEADERS MimeTreeParserCore_HEADERS
PREFIX MimeTreeParserCore
)
install(FILES
${MimeTreeParserCore_CamelCase_HEADERS}
DESTINATION ${KDE_INSTALL_INCLUDEDIR}/KPim6/MimeTreeParserCore/MimeTreeParserCore
COMPONENT Devel
)
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/mimetreeparser_core_export.h
${MimeTreeParserCore_HEADERS}
DESTINATION ${KDE_INSTALL_INCLUDEDIR}/KPim6/MimeTreeParserCore/mimetreeparsercore
COMPONENT Devel
)
if (BUILD_QCH)
ecm_add_qch(
KPim6MimeTreeParserCore_QCH
NAME MimeTreeParserCore
BASE_NAME KPim6MimeTreeParserCore
VERSION ${PIM_VERSION}
ORG_DOMAIN org.kde
# using only public headers, to cover only public API
SOURCES ${MimeTreeParserCore_HEADERS}
MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md"
LINK_QCHS
Qt6Core_QCH
INCLUDE_DIRS
${CMAKE_CURRENT_BINARY_DIR}
BLANK_MACROS
MIMETREEPARSERCORE_EXPORT
TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
COMPONENT Devel
)
endif()
########### CMake Config Files ###########
set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KPim6MimeTreeParserCore")
if (BUILD_QCH)
ecm_install_qch_export(
TARGETS KPim6MimeTreeParserCore_QCH
FILE KPim6MimeTreeParserCoreQchTargets.cmake
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
COMPONENT Devel
)
set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KPim6MimeTreeParserCoreQchTargets.cmake\")")
endif()
configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/KPimMimeTreeParserCoreConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/KPim6MimeTreeParserCoreConfig.cmake"
INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/KPim6MimeTreeParserCoreConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/KPim6MimeTreeParserCoreConfigVersion.cmake"
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
COMPONENT Devel
)
install(EXPORT KPim6MimeTreeParserCoreTargets
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
FILE KPim6MimeTreeParserCoreTargets.cmake
NAMESPACE KPim6::
)
diff --git a/src/core/objecttreeparser.cpp b/src/core/objecttreeparser.cpp
index 96c366b..5f470b8 100644
--- a/src/core/objecttreeparser.cpp
+++ b/src/core/objecttreeparser.cpp
@@ -1,492 +1,491 @@
// This file is part of KMail, the KDE mail client.
// SPDX-FileCopyrightText: 2003 Marc Mutz <mutz@kde.org>
// SPDX-FileCopyrightText: 2002-2004 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
// SPDX-FileCopyrightText: 2009 Andras Mantia <andras@kdab.net>
// SPDX-FileCopyrightText: 2015 Sandro Knauß <sknauss@kde.org>
// SPDX-FileCopyrightText: 2017 Christian Mollekopf <mollekopf@kolabsystems.com>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "objecttreeparser.h"
#include "bodypartformatterbasefactory.h"
#include "bodypartformatter.h"
#include <KMime/Message>
-#include <KCharsets>
#include <QByteArray>
#include <QDebug>
#include <QMimeDatabase>
#include <QRegularExpression>
#include <QStringDecoder>
#include <QTextStream>
#include <QUrl>
using namespace MimeTreeParser;
/*
* Collect message parts bottom up.
* Filter to avoid evaluating a subtree.
* Select parts to include it in the result set. Selecting a part in a branch will keep any parent parts from being selected.
*/
static QList<MessagePart::Ptr> collect(MessagePart::Ptr start,
const std::function<bool(const MessagePart::Ptr &)> &evaluateSubtree,
const std::function<bool(const MessagePart::Ptr &)> &select)
{
auto ptr = start.dynamicCast<MessagePart>();
Q_ASSERT(ptr);
MessagePart::List list;
if (evaluateSubtree(ptr)) {
for (const auto &p : ptr->subParts()) {
list << ::collect(p, evaluateSubtree, select);
}
}
// Don't consider this part if we already selected a subpart
if (list.isEmpty()) {
if (select(ptr)) {
list << start;
}
}
return list;
}
QString ObjectTreeParser::plainTextContent()
{
QString content;
if (mParsedPart) {
auto plainParts = ::collect(
mParsedPart,
[](const MessagePart::Ptr &) {
return true;
},
[](const MessagePart::Ptr &part) {
if (part->isAttachment()) {
return false;
}
if (dynamic_cast<MimeTreeParser::TextMessagePart *>(part.data())) {
return true;
}
if (dynamic_cast<MimeTreeParser::AlternativeMessagePart *>(part.data())) {
return true;
}
return false;
});
for (const auto &part : plainParts) {
content += part->text();
}
}
return content;
}
QString ObjectTreeParser::htmlContent()
{
QString content;
if (mParsedPart) {
MessagePart::List contentParts = ::collect(
mParsedPart,
[](const MessagePart::Ptr &) {
return true;
},
[](const MessagePart::Ptr &part) {
if (dynamic_cast<MimeTreeParser::HtmlMessagePart *>(part.data())) {
return true;
}
if (dynamic_cast<MimeTreeParser::AlternativeMessagePart *>(part.data())) {
return true;
}
return false;
});
for (const auto &part : contentParts) {
if (auto p = dynamic_cast<MimeTreeParser::AlternativeMessagePart *>(part.data())) {
content += p->htmlContent();
} else {
content += part->text();
}
}
}
return content;
}
bool ObjectTreeParser::hasEncryptedParts() const
{
bool result = false;
::collect(
mParsedPart,
[](const MessagePart::Ptr &) {
return true;
},
[&result](const MessagePart::Ptr &part) {
if (const auto enc = dynamic_cast<MimeTreeParser::EncryptedMessagePart *>(part.data())) {
result = true;
}
return false;
});
return result;
}
bool ObjectTreeParser::hasSignedParts() const
{
bool result = false;
::collect(
mParsedPart,
[](const MessagePart::Ptr &) {
return true;
},
[&result](const MessagePart::Ptr &part) {
if (const auto enc = dynamic_cast<MimeTreeParser::SignedMessagePart *>(part.data())) {
result = true;
}
return false;
});
return result;
}
static void print(QTextStream &stream, KMime::Content *node, const QString prefix = {})
{
QByteArray mediaType("text");
QByteArray subType("plain");
if (node->contentType(false) && !node->contentType()->mediaType().isEmpty() && !node->contentType()->subType().isEmpty()) {
mediaType = node->contentType()->mediaType();
subType = node->contentType()->subType();
}
stream << prefix << "! " << mediaType << subType << " isAttachment: " << KMime::isAttachment(node) << "\n";
const auto contents = node->contents();
for (const auto nodeContent : contents) {
print(stream, nodeContent, prefix + QLatin1StringView(" "));
}
}
static void print(QTextStream &stream, const MessagePart &messagePart, const QByteArray pre = {})
{
stream << pre << "# " << messagePart.metaObject()->className() << " isAttachment: " << messagePart.isAttachment() << "\n";
const auto subParts = messagePart.subParts();
for (const auto &subPart : subParts) {
print(stream, *subPart, pre + " ");
}
}
QString ObjectTreeParser::structureAsString() const
{
QString string;
QTextStream stream{&string};
if (mTopLevelContent) {
::print(stream, mTopLevelContent);
}
if (mParsedPart) {
::print(stream, *mParsedPart);
}
return string;
}
void ObjectTreeParser::print()
{
qInfo().noquote() << structureAsString();
}
static KMime::Content *find(KMime::Content *node, const std::function<bool(KMime::Content *)> &select)
{
QByteArray mediaType("text");
QByteArray subType("plain");
if (node->contentType(false) && !node->contentType()->mediaType().isEmpty() && !node->contentType()->subType().isEmpty()) {
mediaType = node->contentType()->mediaType();
subType = node->contentType()->subType();
}
if (select(node)) {
return node;
}
const auto contents = node->contents();
for (const auto nodeContent : contents) {
if (const auto content = find(nodeContent, select)) {
return content;
}
}
return nullptr;
}
KMime::Content *ObjectTreeParser::find(const std::function<bool(KMime::Content *)> &select)
{
return ::find(mTopLevelContent, select);
}
MessagePart::List ObjectTreeParser::collectContentParts()
{
return collectContentParts(mParsedPart);
}
MessagePart::List ObjectTreeParser::collectContentParts(MessagePart::Ptr start)
{
return ::collect(
start,
[start](const MessagePart::Ptr &part) {
// Ignore the top-level
if (start.data() == part.data()) {
return true;
}
if (auto encapsulatedPart = part.dynamicCast<MimeTreeParser::EncapsulatedRfc822MessagePart>()) {
return false;
}
return true;
},
[start](const MessagePart::Ptr &part) {
if (const auto attachment = dynamic_cast<MimeTreeParser::AttachmentMessagePart *>(part.data())) {
return attachment->mimeType() == QByteArrayLiteral("text/calendar");
} else if (const auto text = dynamic_cast<MimeTreeParser::TextMessagePart *>(part.data())) {
auto enc = dynamic_cast<MimeTreeParser::EncryptedMessagePart *>(text->parentPart());
if (enc && enc->error()) {
return false;
}
return true;
} else if (dynamic_cast<MimeTreeParser::AlternativeMessagePart *>(part.data())) {
return true;
} else if (dynamic_cast<MimeTreeParser::HtmlMessagePart *>(part.data())) {
// Don't if we have an alternative part as parent
return true;
} else if (dynamic_cast<MimeTreeParser::EncapsulatedRfc822MessagePart *>(part.data())) {
if (start.data() == part.data()) {
return false;
}
return true;
} else if (const auto enc = dynamic_cast<MimeTreeParser::EncryptedMessagePart *>(part.data())) {
if (enc->error()) {
return true;
}
// If we have a textpart with encrypted and unencrypted subparts we want to return the textpart
if (dynamic_cast<MimeTreeParser::TextMessagePart *>(enc->parentPart())) {
return false;
}
} else if (const auto sig = dynamic_cast<MimeTreeParser::SignedMessagePart *>(part.data())) {
// Signatures without subparts already contain the text
return !sig->hasSubParts();
}
return false;
});
}
MessagePart::List ObjectTreeParser::collectAttachmentParts()
{
MessagePart::List contentParts = ::collect(
mParsedPart,
[](const MessagePart::Ptr &) {
return true;
},
[](const MessagePart::Ptr &part) {
return part->isAttachment();
});
return contentParts;
}
/*
* This naive implementation assumes that there is an encrypted part wrapping a signature.
* For other cases we would have to process both recursively (I think?)
*/
void ObjectTreeParser::decryptAndVerify()
{
// We first decrypt
::collect(
mParsedPart,
[](const MessagePart::Ptr &) {
return true;
},
[](const MessagePart::Ptr &part) {
if (const auto enc = dynamic_cast<MimeTreeParser::EncryptedMessagePart *>(part.data())) {
enc->startDecryption();
}
return false;
});
// And then verify the available signatures
::collect(
mParsedPart,
[](const MessagePart::Ptr &) {
return true;
},
[](const MessagePart::Ptr &part) {
if (const auto enc = dynamic_cast<MimeTreeParser::SignedMessagePart *>(part.data())) {
enc->startVerification();
}
return false;
});
}
QString ObjectTreeParser::resolveCidLinks(const QString &html)
{
auto text = html;
static const auto regex = QRegularExpression(QLatin1StringView("(src)\\s*=\\s*(\"|')(cid:[^\"']+)\\2"));
auto it = regex.globalMatch(text);
while (it.hasNext()) {
const auto match = it.next();
const auto link = QUrl(match.captured(3));
auto cid = link.path();
auto mailMime = const_cast<KMime::Content *>(find([=](KMime::Content *content) {
if (!content || !content->contentID(false)) {
return false;
}
return QString::fromLatin1(content->contentID(false)->identifier()) == cid;
}));
if (mailMime) {
const auto contentType = mailMime->contentType(false);
if (!contentType) {
qWarning() << "No content type, skipping";
continue;
}
QMimeDatabase mimeDb;
const auto mimetype = mimeDb.mimeTypeForName(QString::fromLatin1(contentType->mimeType())).name();
if (mimetype.startsWith(QLatin1StringView("image/"))) {
// We reencode to base64 below.
const auto data = mailMime->decodedContent();
if (data.isEmpty()) {
qWarning() << "Attachment is empty.";
continue;
}
text.replace(match.captured(0), QString::fromLatin1("src=\"data:%1;base64,%2\"").arg(mimetype, QString::fromLatin1(data.toBase64())));
}
} else {
qWarning() << "Failed to find referenced attachment: " << cid;
}
}
return text;
}
//-----------------------------------------------------------------------------
void ObjectTreeParser::parseObjectTree(const QByteArray &mimeMessage)
{
const auto mailData = KMime::CRLFtoLF(mimeMessage);
mMsg = KMime::Message::Ptr(new KMime::Message);
mMsg->setContent(mailData);
mMsg->parse();
// We avoid using mMsg->contentType()->charset(), because that will just return kmime's defaultCharset(), ISO-8859-1
const auto charset = mMsg->contentType()->parameter(QStringLiteral("charset")).toLatin1();
if (charset.isEmpty()) {
mMsg->contentType()->setCharset("us-ascii");
}
parseObjectTree(mMsg.data());
}
void ObjectTreeParser::parseObjectTree(KMime::Content *node)
{
mTopLevelContent = node;
mParsedPart = parseObjectTreeInternal(node, false);
}
MessagePart::Ptr ObjectTreeParser::parsedPart() const
{
return mParsedPart;
}
/*
* This will lookup suitable formatters based on the type,
* and let them generate a list of parts.
* If the formatter generated a list of parts, then those are taken, otherwise we move on to the next match.
*/
MessagePart::List ObjectTreeParser::processType(KMime::Content *node, const QByteArray &mediaType, const QByteArray &subType)
{
static MimeTreeParser::BodyPartFormatterBaseFactory factory;
const auto sub = factory.subtypeRegistry(mediaType.constData());
const auto range = sub.equal_range(subType.constData());
for (auto it = range.first; it != range.second; ++it) {
const auto formatter = it->second;
if (!formatter) {
continue;
}
const auto list = formatter->processList(this, node);
if (!list.isEmpty()) {
return list;
}
}
return {};
}
MessagePart::Ptr ObjectTreeParser::parseObjectTreeInternal(KMime::Content *node, bool onlyOneMimePart)
{
if (!node) {
return MessagePart::Ptr();
}
auto parsedPart = MessagePart::Ptr(new MessagePartList(this, node));
parsedPart->setIsRoot(node->isTopLevel());
const auto contents = node->parent() ? node->parent()->contents() : KMime::Content::List{node};
for (int i = contents.indexOf(node); i < contents.size(); ++i) {
node = contents.at(i);
QByteArray mediaType("text");
QByteArray subType("plain");
if (node->contentType(false) && !node->contentType()->mediaType().isEmpty() && !node->contentType()->subType().isEmpty()) {
mediaType = node->contentType()->mediaType();
subType = node->contentType()->subType();
}
auto messageParts = [&] {
// Try the specific type handler
{
auto list = processType(node, mediaType, subType);
if (!list.isEmpty()) {
return list;
}
}
// Fallback to the generic handler
{
auto list = processType(node, mediaType, QByteArrayLiteral("*"));
if (!list.isEmpty()) {
return list;
}
}
// Fallback to the default handler
return defaultHandling(node);
}();
for (const auto &part : messageParts) {
parsedPart->appendSubPart(part);
}
if (onlyOneMimePart) {
break;
}
}
return parsedPart;
}
QList<MessagePart::Ptr> ObjectTreeParser::defaultHandling(KMime::Content *node)
{
if (node->contentType()->mimeType() == QByteArrayLiteral("application/octet-stream")
&& (node->contentType()->name().endsWith(QLatin1StringView("p7m")) || node->contentType()->name().endsWith(QLatin1StringView("p7s"))
|| node->contentType()->name().endsWith(QLatin1StringView("p7c")))) {
auto list = processType(node, "application", "pkcs7-mime");
if (!list.isEmpty()) {
return list;
}
}
return {AttachmentMessagePart::Ptr(new AttachmentMessagePart(this, node))};
}
QByteArray ObjectTreeParser::codecNameFor(KMime::Content *node) const
{
if (!node) {
return QByteArrayLiteral("UTF-8");
}
QByteArray charset = node->contentType()->charset().toLower();
// utf-8 is a superset of us-ascii, so we don't lose anything if we use it instead
// utf-8 is used so widely nowadays that it is a good idea to use it to fix issues with broken clients.
if (charset == QByteArrayLiteral("us-ascii")) {
charset = QByteArrayLiteral("utf-8");
}
if (!charset.isEmpty()) {
if (const QStringDecoder c(charset.constData()); c.isValid()) {
return charset;
}
}
// no charset means us-ascii (RFC 2045), so using local encoding should
// be okay
return QByteArrayLiteral("UTF-8");
}
diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt
index 3636d15..8abf9e6 100644
--- a/src/widgets/CMakeLists.txt
+++ b/src/widgets/CMakeLists.txt
@@ -1,157 +1,156 @@
# SPDX-FileCopyrightText: 2023 g10 Code GmbH
# SPDX-FileContributor: Carl Schwan <carlschwan@kde.org>
# SPDX-License-Identifier: BSD-3-Clause
ecm_setup_version(PROJECT
VARIABLE_PREFIX MIMETREEPARSER_WIDGETS
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/mimetreeparser_widgets_version.h"
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KPim6MimeTreeParserWidgetsConfigVersion.cmake"
SOVERSION 6
)
add_library(KPim6MimeTreeParserWidgets)
add_library(KPim6::MimeTreeParserWidgets
ALIAS KPim6MimeTreeParserWidgets)
target_sources(KPim6MimeTreeParserWidgets PRIVATE
attachmentview_p.h
attachmentview.cpp
messagecontainerwidget_p.h
messagecontainerwidget.cpp
messageviewer.h
messageviewer.cpp
messageviewerdialog.h
messageviewerdialog.cpp
urlhandler_p.h
urlhandler.cpp
)
ecm_qt_declare_logging_category(KPim6MimeTreeParserWidgets
HEADER mimetreeparser_widgets_debug.h
IDENTIFIER MIMETREEPARSER_WIDGET_LOG
CATEGORY_NAME org.kde.pim.mimetreeparser.widgets
DESCRIPTION "mimetreeparser (pim lib)"
EXPORT MIMETREEPARSER
)
if (COMPILE_WITH_UNITY_CMAKE_SUPPORT)
set_target_properties(KPim6MimeTreeParserWidgets PROPERTIES UNITY_BUILD ON)
endif()
generate_export_header(KPim6MimeTreeParserWidgets BASE_NAME mimetreeparser_widgets)
target_include_directories(KPim6MimeTreeParserWidgets INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR}/KPim6/MimeTreeParserWidgets>")
target_link_libraries(KPim6MimeTreeParserWidgets
PUBLIC
Qt::Widgets
KPim6::MimeTreeParserCore
PRIVATE
Qt::PrintSupport
- KF6::Codecs
KF6::I18n
KF6::CalendarCore
KF6::WidgetsAddons
KPim6::Libkleo
Gpgmepp
)
set_target_properties(KPim6MimeTreeParserWidgets PROPERTIES
VERSION ${MIMETREEPARSER_WIDGETS_VERSION}
SOVERSION ${MIMETREEPARSER_WIDGETS_SOVERSION}
EXPORT_NAME MimeTreeParserWidgets
)
ecm_generate_pri_file(BASE_NAME MimeTreeParserWidgets
LIB_NAME KPim6MimeTreeParserWidgets
DEPS "MimeTreeParserWidgets"
FILENAME_VAR PRI_FILENAME
)
install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR})
install(TARGETS
KPim6MimeTreeParserWidgets
EXPORT KPim6MimeTreeParserWidgetsTargets ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}
)
ecm_generate_headers(MimeTreeParserWidgets_CamelCase_HEADERS
HEADER_NAMES
MessageViewer
MessageViewerDialog
REQUIRED_HEADERS MimeTreeParserWidgets_HEADERS
PREFIX MimeTreeParserWidgets
)
install(FILES
${MimeTreeParserWidgets_CamelCase_HEADERS}
DESTINATION ${KDE_INSTALL_INCLUDEDIR}/KPim6/MimeTreeParserWidgets/MimeTreeParserWidgets
COMPONENT Devel
)
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/mimetreeparser_widgets_export.h
${MimeTreeParserWidgets_HEADERS}
DESTINATION ${KDE_INSTALL_INCLUDEDIR}/KPim6/MimeTreeParserWidgets/mimetreeparserwidgets
COMPONENT Devel
)
if (BUILD_QCH)
ecm_add_qch(
KPim6MimeTreeParserWidgets_QCH
NAME MimeTreeParserWidgets
BASE_NAME KPim6MimeTreeParserWidgets
VERSION ${PIM_VERSION}
ORG_DOMAIN org.kde
# using only public headers, to cover only public API
SOURCES ${MimeTreeParserWidgets_HEADERS}
MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md"
LINK_QCHS
Qt6Core_QCH
Qt6Widgets_QCH
INCLUDE_DIRS
${CMAKE_CURRENT_BINARY_DIR}
BLANK_MACROS
MIMETREEPARSER_WIDGETS_EXPORT
TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
COMPONENT Devel
)
endif()
########### CMake Config Files ###########
set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KPim6MimeTreeParserWidgets")
if (BUILD_QCH)
ecm_install_qch_export(
TARGETS KPim6MimeTreeParserWidgets_QCH
FILE KPim6MimeTreeParserWidgetsQchTargets.cmake
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
COMPONENT Devel
)
set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KPim6MimeTreeParserWidgetsQchTargets.cmake\")")
endif()
configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/KPimMimeTreeParserWidgetsConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/KPim6MimeTreeParserWidgetsConfig.cmake"
INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/KPim6MimeTreeParserWidgetsConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/KPim6MimeTreeParserWidgetsConfigVersion.cmake"
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
COMPONENT Devel
)
install(EXPORT KPim6MimeTreeParserWidgetsTargets
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
FILE KPim6MimeTreeParserWidgetsTargets.cmake
NAMESPACE KPim6::
)
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/mimetreeparser_widgets_version.h
DESTINATION ${KDE_INSTALL_INCLUDEDIR}/KPim6/MimeTreeParserWidgets
COMPONENT Devel
)
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Jan 4, 5:46 AM (1 d, 20 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
50/16/b33b336e9c98c989f94a268da083
Attached To
rMTP MIME Tree Parser
Event Timeline
Log In to Comment