Page MenuHome GnuPG

No OneTemporary

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

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

Event Timeline