diff --git a/messagecomposer/autotests/setupenv.h b/messagecomposer/autotests/setupenv.h index 4720b8bd..a6660fa0 100644 --- a/messagecomposer/autotests/setupenv.h +++ b/messagecomposer/autotests/setupenv.h @@ -1,75 +1,76 @@ /* Copyright (C) 2010 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Copyright (c) 2010 Leo Franchi 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. */ #ifndef MESSAGECORE_TESTS_UTIL_H #define MESSAGECORE_TESTS_UTIL_H #include #include +#include namespace MessageComposer { namespace Test { /** * setup a environment variables for tests: * * set LC_ALL to C * * set KDEHOME * * verify that Kleo has correctly loaded all backends */ void setupEnv(); /** * Returns list of keys used in various crypto routines */ std::vector getKeys(bool smime = false); // We can't use EmptySource, since that doesn't provide a HTML writer. Therefore, derive // from EmptySource so we can provide our own HTML writer. // This is only needed because ObjectTreeParser has a bug and doesn't decrypt inline PGP messages // when there is no HTML writer, see FIXME comment in ObjectTreeParser::writeBodyString(). class TestObjectTreeSource : public MessageViewer::EmptySource { public: TestObjectTreeSource(MimeTreeParser::HtmlWriter *writer, - MimeTreeParser::CSSHelperBase *cssHelper) + MessageViewer::CSSHelperBase *cssHelper) : mWriter(writer), mCSSHelper(cssHelper) { } MimeTreeParser::HtmlWriter *htmlWriter() Q_DECL_OVERRIDE { return mWriter; } - MimeTreeParser::CSSHelperBase *cssHelper() Q_DECL_OVERRIDE { + MessageViewer::CSSHelperBase *cssHelper() Q_DECL_OVERRIDE { return mCSSHelper; } private: MimeTreeParser::HtmlWriter *mWriter; - MimeTreeParser::CSSHelperBase *mCSSHelper; + MessageViewer::CSSHelperBase *mCSSHelper; }; } } #endif diff --git a/messageviewer/autotests/CMakeLists.txt b/messageviewer/autotests/CMakeLists.txt index 678761a5..e872b4e5 100644 --- a/messageviewer/autotests/CMakeLists.txt +++ b/messageviewer/autotests/CMakeLists.txt @@ -1,45 +1,42 @@ set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) -include(${CMAKE_SOURCE_DIR}/cmake/modules/kdepim_add_gpg_crypto_test.cmake) - # convenience macro to add qtest unit tests macro(add_messageviewer_unittest _source) get_filename_component(_name ${_source} NAME_WE) - ecm_add_test(${_source} setupenv.cpp testcsshelper.cpp + ecm_add_test(${_source} TEST_NAME ${_name} NAME_PREFIX "messageviewer-" LINK_LIBRARIES KF5::MessageViewer KF5::Libkleo KF5::QGpgme Qt5::Test Qt5::WebKitWidgets KF5::KIOCore KF5::Mime KF5::AkonadiCore KF5::AkonadiNotes KF5::CalendarCore ) endmacro () macro(add_messageviewer_class_unittest _source _additionalSource) get_filename_component(_name ${_source} NAME_WE) ecm_add_test(${_source} ${_additionalSource} TEST_NAME ${_name} NAME_PREFIX "messageviewer-" LINK_LIBRARIES KF5::MessageViewer Qt5::Test KF5::IconThemes KF5::XmlGui Qt5::WebKitWidgets KF5::I18n ) endmacro () add_messageviewer_unittest( messagedisplayformatattributetest.cpp ) # convenience macro to add qtest unit tests macro(add_messageviewer_mailsourceviewbrowserwidget_unittest _source) - set(_test ${_source} ) get_filename_component(_name ${_source} NAME_WE) ecm_add_test(${_source} ../src/widgets/mailsourceviewtextbrowserwidget.cpp ../src/findbar/findbarsourceview.cpp TEST_NAME ${_name} NAME_PREFIX "messageviewer-" LINK_LIBRARIES Qt5::Test Qt5::Gui Qt5::Widgets KF5::KIOCore KF5::Mime KF5::AkonadiCore KF5::CalendarCore KF5::PimTextEdit KF5::PimCommon KF5::MessageViewer KF5::WebEngineViewer ) endmacro () add_messageviewer_mailsourceviewbrowserwidget_unittest( mailsourceviewtextbrowserwidgettest.cpp ) ########### viewertest_gui ############### set(KDEPIMLIBS_RUN_ISOLATED_TESTS TRUE) set(KDEPIMLIBS_RUN_SQLITE_ISOLATED_TESTS TRUE) add_akonadi_isolated_test_advanced(viewertest.cpp "" "KF5::MessageViewer;KF5::XmlGui") diff --git a/messageviewer/autotests/setupenv.h b/messageviewer/autotests/setupenv.h index ecff82b3..21bcb93f 100644 --- a/messageviewer/autotests/setupenv.h +++ b/messageviewer/autotests/setupenv.h @@ -1,119 +1,46 @@ /* Copyright (C) 2010 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Copyright (c) 2010 Leo Franchi 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. */ #ifndef MESSAGECORE_TESTS_UTIL_H #define MESSAGECORE_TESTS_UTIL_H #include #include #include namespace MessageViewer { namespace Test { /** * setup a environment variables for tests: * * set LC_ALL to C * * set KDEHOME */ void setupEnv(); -// We can't use EmptySource, since we need to control some emelnets of the source for tests to also test -// loadExternal and htmlMail. -class TestObjectTreeSource : public MessageViewer::EmptySource -{ -public: - TestObjectTreeSource(MimeTreeParser::HtmlWriter *writer, - MimeTreeParser::CSSHelperBase *cssHelper) - : mWriter(writer) - , mCSSHelper(cssHelper) - , mAttachmentStrategy(QStringLiteral("smart")) - , mHtmlLoadExternal(false) - , mHtmlMail(true) - { - } - - MimeTreeParser::HtmlWriter *htmlWriter() Q_DECL_OVERRIDE { - return mWriter; - } - MimeTreeParser::CSSHelperBase *cssHelper() Q_DECL_OVERRIDE { - return mCSSHelper; - } - - bool htmlLoadExternal() const Q_DECL_OVERRIDE - { - return mHtmlLoadExternal; - } - - void setHtmlLoadExternal(bool loadExternal) - { - mHtmlLoadExternal = loadExternal; - } - - bool htmlMail() const Q_DECL_OVERRIDE - { - return mHtmlMail; - } - - void setHtmlMail(bool htmlMail) - { - mHtmlMail = htmlMail; - } - - void setAttachmentStrategy(QString strategy) - { - mAttachmentStrategy = strategy; - } - - const MimeTreeParser::AttachmentStrategy *attachmentStrategy() Q_DECL_OVERRIDE { - return MimeTreeParser::AttachmentStrategy::create(mAttachmentStrategy); - } - - bool autoImportKeys() const Q_DECL_OVERRIDE - { - return true; - } - - bool showEmoticons() const Q_DECL_OVERRIDE - { - return false; - } - - bool showExpandQuotesMark() const Q_DECL_OVERRIDE - { - return false; - } - -private: - MimeTreeParser::HtmlWriter *mWriter; - MimeTreeParser::CSSHelperBase *mCSSHelper; - QString mAttachmentStrategy; - bool mHtmlLoadExternal; - bool mHtmlMail; -}; } } #endif diff --git a/messageviewer/autotests/testcsshelper.cpp b/messageviewer/autotests/testcsshelper.cpp deleted file mode 100644 index 128479e3..00000000 --- a/messageviewer/autotests/testcsshelper.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - testcsshelper.cpp - - This file is part of KMail, the KDE mail client. - Copyright (c) 2013 Sandro Knauß - - KMail is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License, version 2, as - published by the Free Software Foundation. - - KMail 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - In addition, as a special exception, the copyright holders give - permission to link the code of this program with any edition of - the Qt library by Trolltech AS, Norway (or with modified versions - of Qt that use the same license as Qt), and distribute linked - combinations including the two. You must obey the GNU General - Public License in all respects for all of the code used other than - Qt. If you modify this file, you may extend this exception to - your version of the file, but you are not obligated to do so. If - you do not wish to do so, delete this exception statement from - your version. -*/ - -#include "testcsshelper.h" - -#include -#include -#include -#include - -namespace MessageViewer -{ - -TestCSSHelper::TestCSSHelper(const QPaintDevice *pd) : - MimeTreeParser::CSSHelperBase(pd) -{ - mRecycleQuoteColors = false; - mBackgroundColor = QColor(0xff, 0xff, 0xff); - mForegroundColor = QColor(0x1f, 0x1c, 0x1b); - mLinkColor = QColor(0x00, 0x57, 0xae); - cPgpEncrH = QColor(0x00, 0x80, 0xff); - cPgpOk1H = QColor(0x40, 0xff, 0x40); - cPgpOk0H = QColor(0xff, 0xff, 0x40); - cPgpWarnH = QColor(0xff, 0xff, 0x40); - cPgpErrH = QColor(0xff, 0x00, 0x00); - - cPgpEncrHT = QColor(0xff, 0xff, 0xff); - cPgpOk1HT = QColor(0x27, 0xae, 0x60); - cPgpOk0HT = QColor(0xf6, 0x74, 0x00); - cPgpWarnHT = QColor(0xf6, 0x74, 0x00); - cPgpErrHT = QColor(0xda, 0x44, 0x53); - - cHtmlWarning = QColor(0xff, 0x40, 0x40); - for (int i = 0; i < 3; ++i) { - mQuoteColor[i] = QColor(0x00, 0x80 - i * 0x10, 0x00); - } - - QFont defaultFont = QFont(QStringLiteral("Sans Serif"), 9); - mBodyFont = defaultFont; - mPrintFont = defaultFont; - mFixedFont = defaultFont; - mFixedPrintFont = defaultFont; - defaultFont.setItalic(true); - for (int i = 0; i < 3; ++i) { - mQuoteFont[i] = defaultFont; - } - - mShrinkQuotes = false; - - QPalette pal; - - pal.setColor(QPalette::Background, QColor(0xd6, 0xd2, 0xd0)); - pal.setColor(QPalette::Foreground, QColor(0x22, 0x1f, 0x1e)); - pal.setColor(QPalette::Highlight, QColor(0x43, 0xac, 0xe8)); - pal.setColor(QPalette::HighlightedText, QColor(0xff, 0xff, 0xff)); - pal.setColor(QPalette::Mid, QColor(0xb3, 0xab, 0xa7)); - - QApplication::setPalette(pal); - - recalculatePGPColors(); -} - -TestCSSHelper::~TestCSSHelper() -{ - -} - -QString TestCSSHelper::htmlHead(bool fixed) const -{ - Q_UNUSED(fixed); - return - QStringLiteral("\n" - "\n" - "\n"); -} - -} - diff --git a/messageviewer/autotests/testcsshelper.h b/messageviewer/autotests/testcsshelper.h deleted file mode 100644 index f9da7562..00000000 --- a/messageviewer/autotests/testcsshelper.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -*- c++ -*- - testcsshelper.h - - This file is part of KMail, the KDE mail client. - Copyright (c) 2013 Sandro Knauß - - KMail is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License, version 2, as - published by the Free Software Foundation. - - KMail 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - In addition, as a special exception, the copyright holders give - permission to link the code of this program with any edition of - the Qt library by Trolltech AS, Norway (or with modified versions - of Qt that use the same license as Qt), and distribute linked - combinations including the two. You must obey the GNU General - Public License in all respects for all of the code used other than - Qt. If you modify this file, you may extend this exception to - your version of the file, but you are not obligated to do so. If - you do not wish to do so, delete this exception statement from - your version. -*/ - -#ifndef __MESSAGEVIEWER_TESTCSSHELPER_H__ -#define __MESSAGEVIEWER_TESTCSSHELPER_H__ - -#include "viewer/csshelperbase.h" - -namespace MessageViewer -{ - -class TestCSSHelper : public MimeTreeParser::CSSHelperBase -{ -public: - explicit TestCSSHelper(const QPaintDevice *pd); - virtual ~TestCSSHelper(); - QString htmlHead(bool fixed) const Q_DECL_OVERRIDE; -}; - -} - -#endif // __MESSAGEVIEWER_TESTCSSHELPER_H__ diff --git a/messageviewer/src/CMakeLists.txt b/messageviewer/src/CMakeLists.txt index a9251fa9..ec35c74f 100644 --- a/messageviewer/src/CMakeLists.txt +++ b/messageviewer/src/CMakeLists.txt @@ -1,417 +1,419 @@ add_definitions( -DQT_NO_CAST_FROM_ASCII ) add_definitions( -DQT_NO_CAST_TO_ASCII ) add_definitions(-DTRANSLATION_DOMAIN=\"libmessageviewer\") # KCFG files: # The main messageviewer.kcfg is configured by CMake and put in the build directory. if(KDEPIM_ENTERPRISE_BUILD) set(LEGACY_MANGLE_FROM_TO_HEADERS true) set(LEGACY_BODY_INVITES true) set(EXCHANGE_COMPATIBLE_INVITATIONS true) else() set(LEGACY_MANGLE_FROM_TO_HEADERS false) set(LEGACY_BODY_INVITES false) set(EXCHANGE_COMPATIBLE_INVITATIONS false) endif() configure_file(settings/messageviewer.kcfg.cmake ${CMAKE_CURRENT_BINARY_DIR}/messageviewer.kcfg) include(CheckIncludeFiles) check_include_files(sys/inotify.h SYS_INOTIFY_H_FOUND) macro_bool_to_01(SYS_INOTIFY_H_FOUND HAVE_SYS_INOTIFY_H) configure_file(config-messageviewer.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-messageviewer.h) # target_include_directories does not handle empty include paths include_directories(${GPGME_INCLUDES}) if(BUILD_TESTING) add_subdirectory(scamdetection/autotests) #add_subdirectory(findbar/autotests) add_subdirectory(scamdetection/tests) add_subdirectory(viewerplugins/tests/) add_subdirectory(htmlwriter/autotests/) add_subdirectory(viewer/webengine/tests) add_subdirectory(messageviewerheaderplugins/autotests) add_subdirectory(messagepartthemes/default/autotests) endif() add_subdirectory(pics) add_subdirectory(kconf_update) add_subdirectory(about) add_subdirectory(messageviewerheaderplugins) if(DEBUG_SIGNATURE) add_definitions(-DDEBUG_SIGNATURE) endif() set(libmessageviewer_mailviewer_SRCS viewer/webengine/mailwebengineview.cpp viewer/webengine/mailwebenginepage.cpp viewer/webengine/loadexternalreferencesurlinterceptor/loadexternalreferencesurlinterceptor.cpp viewer/webengine/cidreferencesurlinterceptor/cidreferencesurlinterceptor.cpp viewer/webengine/mailwebenginescript.cpp ) set(libmessageviewer_viewer_SRCS viewer/bodypartformatterfactory.cpp viewer/bodypartformatterfactorysingleton.cpp viewer/csshelper.cpp + viewer/csshelperbase.cpp viewer/editorwatcher.cpp viewer/objecttreeemptysource.cpp viewer/objecttreeviewersource.cpp viewer/pluginloaderbase.cpp viewer/viewer.cpp viewer/viewer_p.cpp viewer/messagedisplayformatattribute.cpp viewer/urlhandlermanager.cpp viewer/mimeparttree/mimeparttreeview.cpp viewer/mimeparttree/mimetreemodel.cpp ) set(libmessageviewer_widgets_SRCS widgets/attachmentdialog.cpp widgets/configurewidget.cpp widgets/printingsettings.cpp widgets/htmlstatusbar.cpp widgets/vcardviewer.cpp widgets/invitationsettings.cpp widgets/openattachmentfolderwidget.cpp widgets/mailsourceviewer.cpp widgets/mailsourceviewtextbrowserwidget.cpp ) set(libmessageviewer_widgets_webengine_SRCS widgets/mailsourcewebengineviewer.cpp ) set(libmessageviewer_header_SRCS header/contactdisplaymessagememento.cpp header/headerstrategy.cpp header/richheaderstrategy.cpp header/headerstyle.cpp header/grantleeheaderstyle.cpp header/plainheaderstyle.cpp header/headerstyle_util.cpp header/grantleeheaderformatter.cpp header/grantleeheaderteststyle.cpp header/kxface.cpp header/headerstyleplugin.cpp header/headerstylepluginmanager.cpp header/headerstyleinterface.cpp header/headerstylemenumanager.cpp ) set(libmessageviewer_scamdetection_SRCS scamdetection/scamdetectionwarningwidget.cpp scamdetection/scamdetectiondetailsdialog.cpp scamdetection/scamattribute.cpp scamdetection/scamcheckshorturl.cpp scamdetection/scamexpandurljob.cpp scamdetection/scamcheckshorturlmanager.cpp ) set(libmessageviewer_scamdetection_webengine_SRCS scamdetection/scamdetectionwebengine.cpp ) set(libmessageviewer_findbar_SRCS findbar/findbarsourceview.cpp ) set(libmessageviewer_utils_SRCS utils/iconnamecache.cpp utils/markmessagereadhandler.cpp utils/messageviewerutil.cpp utils/mimetype.cpp ) set(libmessageviewer_htmlwriter_webengine_SRCS htmlwriter/webengineparthtmlwriter.cpp htmlwriter/webengineembedpart.cpp ) set(libmessageviewer_htmlwriter_SRCS htmlwriter/teehtmlwriter.cpp ${libmessageviewer_htmlwriter_webengine_SRCS} ) set(libmessageviewer_antispam_SRCS antispam/spamheaderanalyzer.cpp antispam/antispamconfig.cpp ) set(libmessageviewer_job_SRCS job/attachmenteditjob.cpp job/modifymessagedisplayformatjob.cpp ) set(libmessageviewer_viewerplugins_SRCS viewerplugins/viewerpluginmanager.cpp viewerplugins/viewerplugin.cpp viewerplugins/viewerplugininterface.cpp viewerplugins/viewerplugintoolmanager.cpp ) set(libmessageviewer_messagepartthemes_default_SRCS messagepartthemes/default/converthtmltoplaintext.cpp messagepartthemes/default/defaultrenderer.cpp messagepartthemes/default/htmlblock.cpp ) FILE(GLOB themesfiles_default_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/messagepartthemes/default/templates/*.html") install(FILES ${themesfiles_default_SRCS} DESTINATION ${DATA_INSTALL_DIR}/messageviewer/messagepartthemes/default) set(libmessageviewer_messagepartthemes_SRCS ${libmessageviewer_messagepartthemes_default_SRCS} ) set(libmessageviewer_SRCS ${libmessageviewer_messagepartthemes_SRCS} ${libmessageviewer_scamdetection_webengine_SRCS} ${libmessageviewer_widgets_webengine_SRCS} ${libmessageviewer_viewer_SRCS} ${libmessageviewer_widgets_SRCS} ${libmessageviewer_header_SRCS} ${libmessageviewer_scamdetection_SRCS} ${libmessageviewer_findbar_SRCS} ${libmessageviewer_utils_SRCS} ${libmessageviewer_htmlwriter_SRCS} ${libmessageviewer_antispam_SRCS} ${libmessageviewer_job_SRCS} ${libmessageviewer_viewerplugins_SRCS} settings/messageviewersettings.cpp ${libmessageviewer_mailviewer_SRCS} ) ecm_qt_declare_logging_category(libmessageviewer_SRCS HEADER messageviewer_debug.h IDENTIFIER MESSAGEVIEWER_LOG CATEGORY_NAME log_messageviewer) kconfig_add_kcfg_files(libmessageviewer_SRCS settings/globalsettings_messageviewer.kcfgc ) ki18n_wrap_ui(libmessageviewer_SRCS ui/settings.ui ui/invitationsettings.ui ui/printingsettings.ui ) add_library(KF5MessageViewer ${libmessageviewer_SRCS}) generate_export_header(KF5MessageViewer BASE_NAME messageviewer) add_library(KF5::MessageViewer ALIAS KF5MessageViewer) target_include_directories(KF5MessageViewer INTERFACE "$") target_include_directories(KF5MessageViewer PUBLIC "$") target_link_libraries(KF5MessageViewer PUBLIC KF5::MessageCore KF5::PimCommon KF5::AkonadiCore KF5::AkonadiMime KF5::Contacts KF5::Libkleo KF5::MimeTreeParser PRIVATE KF5::ItemViews Qt5::Network Qt5::WebKitWidgets KF5::WebEngineViewer KF5::Libkdepim KF5::GrantleeTheme KF5::KaddressbookGrantlee Grantlee5::Templates KF5::MailTransport KF5::Mime KF5::Mbox KF5::AkonadiNotes KF5::PimTextEdit KF5::CalendarCore KF5::Gravatar KF5::IconThemes Grantlee5::TextDocument Grantlee5::Templates ) if (WIN32) target_link_libraries(KF5MessageViewer PUBLIC KF5::Gpgmepp) else() target_link_libraries(KF5MessageViewer PUBLIC KF5::Gpgmepp-pthread) endif() target_include_directories(KF5MessageViewer PUBLIC $) set_target_properties(KF5MessageViewer PROPERTIES VERSION ${MESSAGEVIEWER_VERSION_STRING} SOVERSION ${MESSAGEVIEWER_SOVERSION} EXPORT_NAME MessageViewer ) install(TARGETS KF5MessageViewer EXPORT KF5MessageViewerTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS} ${LIBRARY_NAMELINK} ) ecm_generate_headers(MessageViewer_Camelcasewebengine_HEADERS HEADER_NAMES MailWebEnginePage MailWebEngineView REQUIRED_HEADERS MessageViewer_webengine_HEADERS PREFIX MessageViewer RELATIVE viewer/webengine ) ecm_generate_headers(MessageViewer_Camelcasescam_HEADERS HEADER_NAMES ScamExpandUrlJob ScamCheckShortUrlManager ScamCheckShortUrl REQUIRED_HEADERS MessageViewer_scam_HEADERS PREFIX MessageViewer RELATIVE scamdetection ) ecm_generate_headers(MessageViewer_Camelcaseviewer_HEADERS HEADER_NAMES Viewer + CSSHelperBase CSSHelper ObjectTreeEmptySource EditorWatcher Stl_Util BodyPartFormatterFactory REQUIRED_HEADERS MessageViewer_viewer_HEADERS PREFIX MessageViewer RELATIVE viewer ) ecm_generate_headers(MessageViewer_Camelcasewidgets_HEADERS HEADER_NAMES InvitationSettings PrintingSettings ConfigureWidget REQUIRED_HEADERS MessageViewer_widgets_HEADERS PREFIX MessageViewer RELATIVE widgets ) ecm_generate_headers(MessageViewer_Camelcaseutils_HEADERS HEADER_NAMES IconNameCache MarkMessageReadHandler MessageViewerUtil MimeType REQUIRED_HEADERS MessageViewer_utils_HEADERS PREFIX MessageViewer RELATIVE utils ) ecm_generate_headers(MessageViewer_Camelcaseantispam_HEADERS HEADER_NAMES SpamHeaderAnalyzer REQUIRED_HEADERS MessageViewer_antispam_HEADERS PREFIX MessageViewer RELATIVE antispam ) ecm_generate_headers(MessageViewer_Camelcaseinterfaces_HEADERS HEADER_NAMES BodyPartURLHandler URLHandler REQUIRED_HEADERS MessageViewer_interfaces_HEADERS PREFIX MessageViewer RELATIVE interfaces ) ecm_generate_headers(MessageViewer_Camelcasesettings_HEADERS HEADER_NAMES MessageViewerSettings REQUIRED_HEADERS MessageViewer_settings_HEADERS PREFIX MessageViewer RELATIVE settings ) ecm_generate_headers(MessageViewer_Camelcaseheader_HEADERS HEADER_NAMES HeaderStrategy GrantleeHeaderTestStyle GrantleeHeaderStyle HeaderStyle KXFace HeaderStyle_Util HeaderStylePlugin HeaderStyleInterface PlainHeaderStyle RichHeaderStrategy HeaderStylePluginManager HeaderStyleMenuManager REQUIRED_HEADERS MessageViewer_header_HEADERS PREFIX MessageViewer RELATIVE header ) ecm_generate_headers(MessageViewer_Camelcaseviewerplugin_HEADERS HEADER_NAMES ViewerPluginManager ViewerPlugin ViewerPluginInterface ViewerPluginToolManager REQUIRED_HEADERS MessageViewer_viewerplugin_HEADERS PREFIX MessageViewer RELATIVE viewerplugins ) ecm_generate_pri_file(BASE_NAME MessageViewer LIB_NAME KF5MessageViewer DEPS "PimCommon MessageCore AkonadiCore AkonadiMime Contacts Libkleo MimeTreeParser" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/MessageViewer ) install(FILES ${MessageViewer_Camelcasewebengine_HEADERS} ${MessageViewer_Camelcaseheader_HEADERS} ${MessageViewer_Camelcaseviewerplugin_HEADERS} ${MessageViewer_Camelcasesettings_HEADERS} ${MessageViewer_Camelcaseutils_HEADERS} ${MessageViewer_Camelcaseinterfaces_HEADERS} ${MessageViewer_Camelcaseviewer_HEADERS} ${MessageViewer_Camelcasewidgets_HEADERS} ${MessageViewer_Camelcaseantispam_HEADERS} ${MessageViewer_Camelfindbar_HEADERS} ${MessageViewer_Camelcasescam_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/MessageViewer COMPONENT Devel ) install(FILES ${MessageViewer_webengine_HEADERS} ${MessageViewer_scam_HEADERS} ${MessageViewer_viewerplugin_HEADERS} ${MessageViewer_settings_HEADERS} ${MessageViewer_header_HEADERS} ${MessageViewer_utils_HEADERS} ${MessageViewer_interfaces_HEADERS} ${MessageViewer_HEADERS} ${MessageViewer_viewer_HEADERS} ${MessageViewer_widgets_HEADERS} ${MessageViewer_antispam_HEADERS} ${MessageViewer_findbar_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/messageviewer_export.h ${CMAKE_CURRENT_BINARY_DIR}/globalsettings_messageviewer.h ${CMAKE_CURRENT_BINARY_DIR}/messageviewer_debug.h ${CMAKE_CURRENT_BINARY_DIR}/config-messageviewer.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/messageviewer COMPONENT Devel ) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) install(FILES header/data/messageviewer_header_themes.knsrc DESTINATION ${KDE_INSTALL_CONFDIR} ) install(FILES notify/messageviewer.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFY5RCDIR} ) install(FILES scamdetection/data/longurlServices.json DESTINATION ${KDE_INSTALL_DATADIR}/messageviewer ) diff --git a/messageviewer/src/messagepartthemes/default/autotests/objecttreeparsertest.cpp b/messageviewer/src/messagepartthemes/default/autotests/objecttreeparsertest.cpp index 14434849..335d5d05 100644 --- a/messageviewer/src/messagepartthemes/default/autotests/objecttreeparsertest.cpp +++ b/messageviewer/src/messagepartthemes/default/autotests/objecttreeparsertest.cpp @@ -1,355 +1,355 @@ /* Copyright 2009 Thomas McGuire This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "objecttreeparsertest.h" #include "util.h" #include "setupenv.h" #include #include -#include +#include #include using namespace MessageViewer; using namespace MimeTreeParser; QTEST_MAIN(ObjectTreeParserTester) void ObjectTreeParserTester::initTestCase() { Test::setupEnv(); } void ObjectTreeParserTester::test_parsePlainMessage() { KMime::Message::Ptr msg(new KMime::Message()); QByteArray content( "From: Thomas McGuire \n" "Subject: Plain Message Test\n" "Date: Wed, 5 Aug 2009 10:58:27 +0200\n" "MIME-Version: 1.0\n" "Content-Type: text/plain;\n" " charset=\"iso-8859-15\"\n" "\n" "This is the message text.\n"); msg->setContent(content); msg->parse(); QCOMPARE(msg->subject()->as7BitString(false).constData(), "Plain Message Test"); QCOMPARE(msg->contents().size(), 0); // Parse the message Test::ObjectTreeSource emptySource(Q_NULLPTR, Q_NULLPTR); ObjectTreeParser otp(&emptySource); otp.parseObjectTree(msg.data()); // Check that the textual content and the charset have the expected values QCOMPARE(otp.plainTextContent(), QStringLiteral("This is the message text.\n")); QVERIFY(otp.htmlContent().isEmpty()); QCOMPARE(otp.plainTextContentCharset().toLower(), QByteArray("iso-8859-15")); // Check that the message was not modified in any way QCOMPARE(msg->encodedContent().constData(), content.constData()); // Test that the charset of messages without an explicit charset declaration // is correct content = "From: Thomas McGuire \n" "Subject: Plain Message Test\n" "Date: Wed, 5 Aug 2009 10:58:27 +0200\n" "MIME-Version: 1.0\n" "Content-Type: text/plain;\n" "\n" "This is the message text.\n"; msg->setContent(content); msg->parse(); ObjectTreeParser otp2(&emptySource); otp2.parseObjectTree(msg.data()); QCOMPARE(otp2.plainTextContentCharset().constData(), msg->defaultCharset().constData()); } void ObjectTreeParserTester::test_parseEncapsulatedMessage() { KMime::Message::Ptr msg = Test::readAndParseMail(QStringLiteral("encapsulated-with-attachment.mbox")); QCOMPARE(msg->subject()->as7BitString(false).constData(), "Fwd: Test with attachment"); QCOMPARE(msg->contents().size(), 2); // Parse the message Test::HtmlWriter testWriter; Test::CSSHelper testCSSHelper; NodeHelper nodeHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource, &nodeHelper); otp.parseObjectTree(msg.data()); // Check that the OTP didn't modify the message in weird ways QCOMPARE(msg->contents().size(), 2); QCOMPARE(msg->contents().at(0)->contents().size(), 0); QCOMPARE(msg->contents().at(1)->contents().size(), 1); QCOMPARE(msg->contents().at(1)->contents().first()->contents().size(), 2); QCOMPARE(msg->contents().at(1)->contents().first()->contents().at(0)->contents().size(), 0); QCOMPARE(msg->contents().at(1)->contents().first()->contents().at(1)->contents().size(), 0); // Check that the textual content and the charset have the expected values QCOMPARE(otp.plainTextContent(), QStringLiteral("This is the first encapsulating message.\n")); QCOMPARE(otp.plainTextContentCharset().toLower(), QByteArray("iso-8859-15")); QVERIFY(otp.htmlContent().isEmpty()); // Check that the objecttreeparser did process the encapsulated message KMime::Message::Ptr encapsulated = msg->contents().at(1)->bodyAsMessage(); QVERIFY(encapsulated.data()); QVERIFY(nodeHelper.nodeProcessed(encapsulated.data())); QVERIFY(nodeHelper.nodeProcessed(encapsulated->contents().at(0))); QVERIFY(nodeHelper.nodeProcessed(encapsulated->contents().at(1))); QVERIFY(nodeHelper.partMetaData(msg->contents().at(1)).isEncapsulatedRfc822Message); } void ObjectTreeParserTester::test_missingContentTypeHeader() { KMime::Message::Ptr msg = Test::readAndParseMail(QStringLiteral("no-content-type.mbox")); QCOMPARE(msg->subject()->as7BitString(false).constData(), "Simple Mail Without Content-Type Header"); QCOMPARE(msg->contents().size(), 0); Test::HtmlWriter testWriter; Test::CSSHelper testCSSHelper; NodeHelper nodeHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource, &nodeHelper); otp.parseObjectTree(msg.data()); QCOMPARE(otp.plainTextContent().toLatin1().data(), "asdfasdf"); QVERIFY(otp.htmlContent().isEmpty()); } void ObjectTreeParserTester::test_inlinePGPDecryption() { KMime::Message::Ptr msg = Test::readAndParseMail(QStringLiteral("inlinepgpencrypted.mbox")); QCOMPARE(msg->subject()->as7BitString(false).constData(), "inlinepgpencrypted"); QCOMPARE(msg->contents().size(), 0); Test::HtmlWriter testWriter; Test::CSSHelper testCSSHelper; NodeHelper nodeHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource, &nodeHelper); emptySource.setAllowDecryption(true); otp.parseObjectTree(msg.data()); QCOMPARE(otp.plainTextContent().toLatin1().data(), "some random text"); // This test is only a workaround, till we can set the memento to the propper node of the mail. KMime::Content *content = new KMime::Content; QVERIFY(nodeHelper.bodyPartMemento(content, "decryptverify")); QVERIFY(otp.htmlContent().isEmpty()); } void ObjectTreeParserTester::test_inlinePGPSigned() { KMime::Message::Ptr msg = Test::readAndParseMail(QStringLiteral("openpgp-inline-signed.mbox")); QCOMPARE(msg->subject()->as7BitString(false).constData(), "test"); QCOMPARE(msg->contents().size(), 0); Test::HtmlWriter testWriter; Test::CSSHelper testCSSHelper; NodeHelper nodeHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource, &nodeHelper); emptySource.setAllowDecryption(true); otp.parseObjectTree(msg.data()); // This test is only a workaround, till we can set the memento to the propper node of the mail. QVERIFY(nodeHelper.bodyPartMemento(0, "verification")); } void ObjectTreeParserTester::test_HTML() { KMime::Message::Ptr msg = Test::readAndParseMail(QStringLiteral("html.mbox")); QCOMPARE(msg->subject()->as7BitString(false).constData(), "HTML test"); QCOMPARE(msg->contents().size(), 2); Test::ObjectTreeSource emptySource(Q_NULLPTR, Q_NULLPTR); ObjectTreeParser otp(&emptySource); otp.parseObjectTree(msg.data()); QCOMPARE(otp.plainTextContent().toLatin1().data(), "Some HTML text"); QVERIFY(otp.htmlContent().contains(QStringLiteral("Some HTML text"))); QCOMPARE(otp.htmlContentCharset().data(), "windows-1252"); } void ObjectTreeParserTester::test_HTMLasText() { KMime::Message::Ptr msg = Test::readAndParseMail(QStringLiteral("html.mbox")); QCOMPARE(msg->subject()->as7BitString(false).constData(), "HTML test"); QCOMPARE(msg->contents().size(), 2); Test::HtmlWriter testWriter; Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource); emptySource.setHtmlMail(false); otp.parseObjectTree(msg.data()); QCOMPARE(otp.htmlContent().toLatin1().constData(), ""); QCOMPARE(otp.htmlContentCharset().constData(), ""); QCOMPARE(otp.plainTextContent().toLatin1().constData(), "Some HTML text"); QCOMPARE(otp.plainTextContentCharset().constData(), "windows-1252"); } void ObjectTreeParserTester::test_HTMLOnly() { KMime::Message::Ptr msg = Test::readAndParseMail(QStringLiteral("htmlonly.mbox")); QCOMPARE(msg->subject()->as7BitString(false).constData(), "HTML test"); QCOMPARE(msg->contents().size(), 0); Test::ObjectTreeSource emptySource(Q_NULLPTR, Q_NULLPTR); ObjectTreeParser otp(&emptySource); otp.parseObjectTree(msg.data()); QVERIFY(otp.plainTextContent().isEmpty()); QVERIFY(otp.htmlContent().contains(QStringLiteral("SOME HTML text."))); } void ObjectTreeParserTester::test_HTMLOnlyText() { KMime::Message::Ptr msg = Test::readAndParseMail(QStringLiteral("htmlonly.mbox")); QCOMPARE(msg->subject()->as7BitString(false).constData(), "HTML test"); QCOMPARE(msg->contents().size(), 0); Test::HtmlWriter testWriter; Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource); emptySource.setHtmlMail(false); otp.parseObjectTree(msg.data()); QVERIFY(otp.plainTextContent().isEmpty()); QVERIFY(otp.htmlContent().contains(QStringLiteral("SOME HTML text."))); QVERIFY(testWriter.html.contains(QStringLiteral("This is an HTML message. For security reasons, only the raw HTML code is shown."))); QVERIFY(testWriter.html.contains(QStringLiteral("*SOME* HTML text.
"))); } void ObjectTreeParserTester::test_HTMLExternal() { KMime::Message::Ptr msg = Test::readAndParseMail(QStringLiteral("htmlonlyexternal.mbox")); QCOMPARE(msg->subject()->as7BitString(false).constData(), "HTML test"); QCOMPARE(msg->contents().size(), 0); { Test::HtmlWriter testWriter; Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource); otp.parseObjectTree(msg.data()); QVERIFY(otp.plainTextContent().isEmpty()); QVERIFY(otp.htmlContent().contains(QStringLiteral("SOME HTML text."))); QVERIFY(testWriter.html.contains(QStringLiteral("SOME HTML text."))); QVERIFY(testWriter.html.contains(QStringLiteral("This HTML message may contain external references to images etc. For security/privacy reasons external references are not loaded."))); } { Test::HtmlWriter testWriter; Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource); emptySource.setHtmlLoadExternal(true); otp.parseObjectTree(msg.data()); QVERIFY(otp.htmlContent().contains(QStringLiteral("SOME HTML text."))); QVERIFY(testWriter.html.contains(QStringLiteral("SOME HTML text."))); QVERIFY(!testWriter.html.contains(QStringLiteral("This HTML message may contain external references to images etc. For security/privacy reasons external references are not loaded."))); } } void ObjectTreeParserTester::test_Alternative() { KMime::Message::Ptr msg = Test::readAndParseMail(QStringLiteral("alternative.mbox")); QCOMPARE(msg->contents().size(), 2); { Test::HtmlWriter testWriter; Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource); emptySource.setHtmlMail(false); otp.parseObjectTree(msg.data()); QVERIFY(otp.htmlContent().isEmpty()); QVERIFY(otp.plainTextContent().contains(QStringLiteral("If you can see this text it means that your email client couldn't display our newsletter properly."))); QVERIFY(testWriter.html.contains(QStringLiteral("If you can see this text it means that your email client couldn't display our newsletter properly."))); } { Test::HtmlWriter testWriter; Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource); emptySource.setHtmlMail(true); otp.parseObjectTree(msg.data()); QVERIFY(otp.plainTextContent().contains(QStringLiteral("If you can see this text it means that your email client couldn't display our newsletter properly."))); QVERIFY(otp.htmlContent().contains(QStringLiteral("Some HTML text

"))); QVERIFY(testWriter.html.contains(QStringLiteral("Some HTML text

"))); } msg = Test::readAndParseMail(QStringLiteral("alternative-notext.mbox")); QCOMPARE(msg->contents().size(), 1); { Test::HtmlWriter testWriter; Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource); emptySource.setHtmlMail(false); otp.parseObjectTree(msg.data()); QVERIFY(otp.plainTextContent().isEmpty()); QVERIFY(otp.htmlContent().isEmpty()); QVERIFY(testWriter.html.contains(QStringLiteral("Some *HTML* text"))); } { Test::HtmlWriter testWriter; Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource); emptySource.setHtmlMail(true); otp.parseObjectTree(msg.data()); QVERIFY(otp.plainTextContent().isEmpty()); QVERIFY(otp.htmlContent().contains(QStringLiteral("Some HTML text

"))); QVERIFY(testWriter.html.contains(QStringLiteral("Some HTML text

"))); } } diff --git a/messageviewer/src/messagepartthemes/default/autotests/quotehtmltest.cpp b/messageviewer/src/messagepartthemes/default/autotests/quotehtmltest.cpp index 87d6678c..80bf8277 100644 --- a/messageviewer/src/messagepartthemes/default/autotests/quotehtmltest.cpp +++ b/messageviewer/src/messagepartthemes/default/autotests/quotehtmltest.cpp @@ -1,64 +1,64 @@ /* Copyright 2009 Thomas McGuire This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "quotehtmltest.h" #include "../defaultrenderer.h" #include "util.h" #include "setupenv.h" #include #include -#include +#include #include #include using namespace MessageViewer; QTEST_GUILESS_MAIN(QuoteHtmlTest) void QuoteHtmlTest::initTestCase() { MessageViewer::Test::setupEnv(); } void QuoteHtmlTest::testQuoteHtml_data() { QTest::addColumn("data"); QTest::addColumn("result"); QTest::newRow("simpletext") << QStringLiteral("http") << QStringLiteral("
http
"); QTest::newRow("simplequote") << QStringLiteral(">") << QStringLiteral("
>
"); QTest::newRow("doublequotewithtext") << QStringLiteral(">> sddf") << QStringLiteral("
>> sddf
"); QTest::newRow("doublequote") << QStringLiteral(">>") << QStringLiteral("
>>
"); QTest::newRow("simplespace") << QStringLiteral(" ") << QStringLiteral("
 
"); QTest::newRow("multispace") << QStringLiteral(" Bug ID: 358324") << QStringLiteral("
            Bug ID: 358324
"); } void QuoteHtmlTest::testQuoteHtml() { QFETCH(QString, data); QFETCH(QString, result); Test::HtmlWriter testWriter; Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); MimeTreeParser::ObjectTreeParser otp(&emptySource); MimeTreeParser::MessagePart::Ptr part(new MimeTreeParser::MessagePart(&otp, data)); - DefaultRenderer renderer(part); + DefaultRenderer renderer(part, &testCSSHelper); QCOMPARE(renderer.html(), result); } diff --git a/messageviewer/src/messagepartthemes/default/autotests/setupenv.h b/messageviewer/src/messagepartthemes/default/autotests/setupenv.h index a667fc6e..8f0cbb99 100644 --- a/messageviewer/src/messagepartthemes/default/autotests/setupenv.h +++ b/messageviewer/src/messagepartthemes/default/autotests/setupenv.h @@ -1,174 +1,175 @@ /* Copyright (C) 2010 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Copyright (c) 2010 Leo Franchi 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. */ #ifndef __MESSAGEVIEWER_TESTS_SETUPENV_H__ #define __MESSAGEVIEWER_TESTS_SETUPENV_H__ #include #include #include #include #include namespace MessageViewer { namespace Test { /** * setup a environment variables for tests: * * set LC_ALL to C * * set KDEHOME */ void setupEnv(); // We can't use EmptySource, since we need to control some emelnets of the source for tests to also test // loadExternal and htmlMail. class ObjectTreeSource : public MessageViewer::EmptySource { public: ObjectTreeSource(MimeTreeParser::HtmlWriter *writer, - MimeTreeParser::CSSHelperBase *cssHelper) + MessageViewer::CSSHelperBase *cssHelper) : mWriter(writer) , mCSSHelper(cssHelper) , mAttachmentStrategy(QStringLiteral("smart")) , mHtmlLoadExternal(false) , mHtmlMail(true) , mDecryptMessage(false) { } MimeTreeParser::HtmlWriter *htmlWriter() Q_DECL_OVERRIDE { return mWriter; } - MimeTreeParser::CSSHelperBase *cssHelper() Q_DECL_OVERRIDE { + + CSSHelperBase *cssHelper() Q_DECL_OVERRIDE { return mCSSHelper; } bool htmlLoadExternal() const Q_DECL_OVERRIDE { return mHtmlLoadExternal; } void setHtmlLoadExternal(bool loadExternal) { mHtmlLoadExternal = loadExternal; } bool htmlMail() const Q_DECL_OVERRIDE { return mHtmlMail; } void setHtmlMail(bool htmlMail) { mHtmlMail = htmlMail; } void setAttachmentStrategy(QString strategy) { mAttachmentStrategy = strategy; } const MimeTreeParser::AttachmentStrategy *attachmentStrategy() Q_DECL_OVERRIDE { return MimeTreeParser::AttachmentStrategy::create(mAttachmentStrategy); } bool autoImportKeys() const Q_DECL_OVERRIDE { return true; } bool showEmoticons() const Q_DECL_OVERRIDE { return false; } bool showExpandQuotesMark() const Q_DECL_OVERRIDE { return false; } const MimeTreeParser::BodyPartFormatterBaseFactory *bodyPartFormatterFactory() Q_DECL_OVERRIDE { return &mBodyPartFormatterBaseFactory; } bool decryptMessage() const Q_DECL_OVERRIDE { return mDecryptMessage; } void setAllowDecryption(bool allowDecryption) { mDecryptMessage = allowDecryption; } void setShowSignatureDetails(bool showSignatureDetails) { mShowSignatureDetails = showSignatureDetails; } bool showSignatureDetails() const Q_DECL_OVERRIDE { return mShowSignatureDetails; } void setHtmlMode(MimeTreeParser::Util::HtmlMode mode) Q_DECL_OVERRIDE { Q_UNUSED(mode); } int levelQuote() const Q_DECL_OVERRIDE { return 1; } const QTextCodec *overrideCodec() Q_DECL_OVERRIDE { return Q_NULLPTR; } QString createMessageHeader(KMime::Message *message) Q_DECL_OVERRIDE { Q_UNUSED(message); return QString(); //do nothing } QObject *sourceObject() Q_DECL_OVERRIDE { return Q_NULLPTR; } private: MimeTreeParser::HtmlWriter *mWriter; - MimeTreeParser::CSSHelperBase *mCSSHelper; + MessageViewer::CSSHelperBase *mCSSHelper; QString mAttachmentStrategy; MimeTreeParser::BodyPartFormatterBaseFactory mBodyPartFormatterBaseFactory; bool mHtmlLoadExternal; bool mHtmlMail; bool mDecryptMessage; bool mShowSignatureDetails; }; } } #endif //__MESSAGEVIEWER_TESTS_SETUPENV_H__ diff --git a/messageviewer/src/messagepartthemes/default/autotests/testcsshelper.cpp b/messageviewer/src/messagepartthemes/default/autotests/testcsshelper.cpp index f451e83c..1f34fdeb 100644 --- a/messageviewer/src/messagepartthemes/default/autotests/testcsshelper.cpp +++ b/messageviewer/src/messagepartthemes/default/autotests/testcsshelper.cpp @@ -1,90 +1,90 @@ /* Copyright (c) 2013 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 "testcsshelper.h" #include #include #include #include using namespace MessageViewer::Test; TestCSSHelper::TestCSSHelper(const QPaintDevice *pd) : - MimeTreeParser::CSSHelperBase(pd) + MessageViewer::CSSHelperBase(pd) { mRecycleQuoteColors = false; mBackgroundColor = QColor(0xff, 0xff, 0xff); mForegroundColor = QColor(0x1f, 0x1c, 0x1b); mLinkColor = QColor(0x00, 0x57, 0xae); cPgpEncrH = QColor(0x00, 0x80, 0xff); cPgpOk1H = QColor(0x40, 0xff, 0x40); cPgpOk0H = QColor(0xff, 0xff, 0x40); cPgpWarnH = QColor(0xff, 0xff, 0x40); cPgpErrH = QColor(0xff, 0x00, 0x00); cPgpEncrHT = QColor(0xff, 0xff, 0xff); cPgpOk1HT = QColor(0x27, 0xae, 0x60); cPgpOk0HT = QColor(0xf6, 0x74, 0x00); cPgpWarnHT = QColor(0xf6, 0x74, 0x00); cPgpErrHT = QColor(0xda, 0x44, 0x53); cHtmlWarning = QColor(0xff, 0x40, 0x40); for (int i = 0; i < 3; ++i) { mQuoteColor[i] = QColor(0x00, 0x80 - i * 0x10, 0x00); } QFont defaultFont = QFont(QStringLiteral("Sans Serif"), 9); mBodyFont = defaultFont; mPrintFont = defaultFont; mFixedFont = defaultFont; mFixedPrintFont = defaultFont; defaultFont.setItalic(true); for (int i = 0; i < 3; ++i) { mQuoteFont[i] = defaultFont; } mShrinkQuotes = false; QPalette pal; pal.setColor(QPalette::Background, QColor(0xd6, 0xd2, 0xd0)); pal.setColor(QPalette::Foreground, QColor(0x22, 0x1f, 0x1e)); pal.setColor(QPalette::Highlight, QColor(0x43, 0xac, 0xe8)); pal.setColor(QPalette::HighlightedText, QColor(0xff, 0xff, 0xff)); pal.setColor(QPalette::Mid, QColor(0xb3, 0xab, 0xa7)); QApplication::setPalette(pal); recalculatePGPColors(); } TestCSSHelper::~TestCSSHelper() { } QString TestCSSHelper::htmlHead(bool fixed) const { Q_UNUSED(fixed); return QStringLiteral("\n" "\n" "\n"); } \ No newline at end of file diff --git a/messageviewer/src/messagepartthemes/default/autotests/testcsshelper.h b/messageviewer/src/messagepartthemes/default/autotests/testcsshelper.h index 52457ee0..a47c662f 100644 --- a/messageviewer/src/messagepartthemes/default/autotests/testcsshelper.h +++ b/messageviewer/src/messagepartthemes/default/autotests/testcsshelper.h @@ -1,41 +1,41 @@ /* Copyright (c) 2013 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. */ #ifndef __MESSSAGEVIEWER_TESTCSSHELPER_H__ #define __MESSSAGEVIEWER_TESTCSSHELPER_H__ -#include +#include namespace MessageViewer { namespace Test { -class TestCSSHelper : public MimeTreeParser::CSSHelperBase +class TestCSSHelper : public MessageViewer::CSSHelperBase { public: explicit TestCSSHelper(const QPaintDevice *pd); virtual ~TestCSSHelper(); QString htmlHead(bool fixed) const Q_DECL_OVERRIDE; }; } } #endif // __MESSSAGEVIEWER_TESTCSSHELPER_H__ diff --git a/messageviewer/src/messagepartthemes/default/autotests/util.h b/messageviewer/src/messagepartthemes/default/autotests/util.h index c1c21cc3..b7f5770d 100644 --- a/messageviewer/src/messagepartthemes/default/autotests/util.h +++ b/messageviewer/src/messagepartthemes/default/autotests/util.h @@ -1,81 +1,81 @@ /* Copyright (c) 2010 Thomas McGuire 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. */ #ifndef __MESSAGEVIEWER_TESTS_UTIL_H__ #define __MESSAGEVIEWER_TESTS_UTIL_H__ #include -#include +#include #include namespace MessageViewer { namespace Test { class HtmlWriter : public MimeTreeParser::HtmlWriter { public: explicit HtmlWriter() {} virtual ~HtmlWriter() {} void begin(const QString &) Q_DECL_OVERRIDE {} void write(const QString &) Q_DECL_OVERRIDE {} void end() Q_DECL_OVERRIDE {} void reset() Q_DECL_OVERRIDE {} void queue(const QString &str) Q_DECL_OVERRIDE { html.append(str); } void flush() Q_DECL_OVERRIDE {} void embedPart(const QByteArray &, const QString &) Q_DECL_OVERRIDE {} void extraHead(const QString &) Q_DECL_OVERRIDE {} QString html; }; -class CSSHelper : public MimeTreeParser::CSSHelperBase +class CSSHelper : public MessageViewer::CSSHelperBase { public: - CSSHelper() : MimeTreeParser::CSSHelperBase(0) + CSSHelper() : MessageViewer::CSSHelperBase(0) { for (int i = 0; i < 3; ++i) { mQuoteColor[i] = QColor(0x00, 0x80 - i * 0x10, 0x00); } } virtual ~CSSHelper() {} QString nonQuotedFontTag() const { return QStringLiteral("<"); } QString quoteFontTag(int) const { return QStringLiteral("<"); } }; KMime::Message::Ptr readAndParseMail(const QString &mailFile); } } #endif //__MESSAGEVIEWER_TESTS_UTIL_H__ \ No newline at end of file diff --git a/messageviewer/src/messagepartthemes/default/defaultrenderer.cpp b/messageviewer/src/messagepartthemes/default/defaultrenderer.cpp index e1912845..b712502f 100644 --- a/messageviewer/src/messagepartthemes/default/defaultrenderer.cpp +++ b/messageviewer/src/messagepartthemes/default/defaultrenderer.cpp @@ -1,1388 +1,1390 @@ /* 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 "defaultrenderer.h" #include "messageviewer_debug.h" #include "converthtmltoplaintext.h" #include "htmlblock.h" #include "utils/iconnamecache.h" #include "utils/mimetype.h" +#include "viewer/csshelperbase.h" #include -#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace MimeTreeParser; using namespace MessageViewer; Q_DECLARE_METATYPE(GpgME::DecryptionResult::Recipient) Q_DECLARE_METATYPE(const Kleo::CryptoBackend::Protocol *) // Read-only introspection of GpgME::DecryptionResult::Recipient object. GRANTLEE_BEGIN_LOOKUP(GpgME::DecryptionResult::Recipient) if (property == QStringLiteral("keyID")) { return QString::fromLatin1(object.keyID()); } GRANTLEE_END_LOOKUP // Read-only introspection of Kleo::CryptoBackend::Protocol object. namespace Grantlee { template<> inline QVariant TypeAccessor::lookUp(const Kleo::CryptoBackend::Protocol *const object, const QString &property) { if (property == QStringLiteral("name")) { return object->name(); } else if (property == QStringLiteral("displayName")) { return object->displayName(); } return QVariant(); } } static QString iconToDataUrl(const QString &iconPath) { QFile f(iconPath); if (!f.open(QIODevice::ReadOnly)) { return QString(); } const QByteArray ba = f.readAll(); return QStringLiteral("data:image/png;base64,%1").arg(QLatin1String(ba.toBase64().constData())); } /** Check if the newline at position @p newLinePos in string @p s seems to separate two paragraphs (important for correct BiDi behavior, but is heuristic because paragraphs are not well-defined) */ // Guesstimate if the newline at newLinePos actually separates paragraphs in the text s // We use several heuristics: // 1. If newLinePos points after or before (=at the very beginning of) text, it is not between paragraphs // 2. If the previous line was longer than the wrap size, we want to consider it a paragraph on its own // (some clients, notably Outlook, send each para as a line in the plain-text version). // 3. Otherwise, we check if the newline could have been inserted for wrapping around; if this // was the case, then the previous line will be shorter than the wrap size (which we already // know because of item 2 above), but adding the first word from the next line will make it // longer than the wrap size. bool looksLikeParaBreak(const QString &s, unsigned int newLinePos) { const unsigned int WRAP_COL = 78; unsigned int length = s.length(); // 1. Is newLinePos at an end of the text? if (newLinePos >= length - 1 || newLinePos == 0) { return false; } // 2. Is the previous line really a paragraph -- longer than the wrap size? // First char of prev line -- works also for first line unsigned prevStart = s.lastIndexOf(QLatin1Char('\n'), newLinePos - 1) + 1; unsigned prevLineLength = newLinePos - prevStart; if (prevLineLength > WRAP_COL) { return true; } // find next line to delimit search for first word unsigned int nextStart = newLinePos + 1; int nextEnd = s.indexOf(QLatin1Char('\n'), nextStart); if (nextEnd == -1) { nextEnd = length; } QString nextLine = s.mid(nextStart, nextEnd - nextStart); length = nextLine.length(); // search for first word in next line unsigned int wordStart; bool found = false; for (wordStart = 0; !found && wordStart < length; wordStart++) { switch (nextLine[wordStart].toLatin1()) { case '>': case '|': case ' ': // spaces, tabs and quote markers don't count case '\t': case '\r': break; default: found = true; break; } } /* for() */ if (!found) { // next line is essentially empty, it seems -- empty lines are // para separators return true; } //Find end of first word. //Note: flowText (in kmmessage.cpp) separates words for wrap by //spaces only. This should be consistent, which calls for some //refactoring. int wordEnd = nextLine.indexOf(QLatin1Char(' '), wordStart); if (wordEnd == (-1)) { wordEnd = length; } int wordLength = wordEnd - wordStart; // 3. If adding a space and the first word to the prev line don't // make it reach the wrap column, then the break was probably // meaningful return prevLineLength + wordLength + 1 < WRAP_COL; } static const int SIG_FRAME_COL_UNDEF = 99; #define SIG_FRAME_COL_RED -1 #define SIG_FRAME_COL_YELLOW 0 #define SIG_FRAME_COL_GREEN 1 QString sigStatusToString(const Kleo::CryptoBackend::Protocol *cryptProto, int status_code, GpgME::Signature::Summary summary, int &frameColor, bool &showKeyInfos) { // note: At the moment frameColor and showKeyInfos are // used for CMS only but not for PGP signatures // pending(khz): Implement usage of these for PGP sigs as well. showKeyInfos = true; QString result; if (cryptProto) { if (cryptProto == Kleo::CryptoBackendFactory::instance()->openpgp()) { // process enum according to it's definition to be read in // GNU Privacy Guard CVS repository /gpgme/gpgme/gpgme.h switch (status_code) { case 0: // GPGME_SIG_STAT_NONE result = i18n("Error: Signature not verified"); break; case 1: // GPGME_SIG_STAT_GOOD result = i18n("Good signature"); break; case 2: // GPGME_SIG_STAT_BAD result = i18n("Bad signature"); break; case 3: // GPGME_SIG_STAT_NOKEY result = i18n("No public key to verify the signature"); break; case 4: // GPGME_SIG_STAT_NOSIG result = i18n("No signature found"); break; case 5: // GPGME_SIG_STAT_ERROR result = i18n("Error verifying the signature"); break; case 6: // GPGME_SIG_STAT_DIFF result = i18n("Different results for signatures"); break; /* PENDING(khz) Verify exact meaning of the following values: case 7: // GPGME_SIG_STAT_GOOD_EXP return i18n("Signature certificate is expired"); break; case 8: // GPGME_SIG_STAT_GOOD_EXPKEY return i18n("One of the certificate's keys is expired"); break; */ default: result.clear(); // do *not* return a default text here ! break; } } else if (cryptProto == Kleo::CryptoBackendFactory::instance()->smime()) { // process status bits according to SigStatus_... // definitions in kdenetwork/libkdenetwork/cryptplug.h if (summary == GpgME::Signature::None) { result = i18n("No status information available."); frameColor = SIG_FRAME_COL_YELLOW; showKeyInfos = false; return result; } if (summary & GpgME::Signature::Valid) { result = i18n("Good signature."); // Note: // Here we are work differently than KMail did before! // // The GOOD case ( == sig matching and the complete // certificate chain was verified and is valid today ) // by definition does *not* show any key // information but just states that things are OK. // (khz, according to LinuxTag 2002 meeting) frameColor = SIG_FRAME_COL_GREEN; showKeyInfos = false; return result; } // we are still there? OK, let's test the different cases: // we assume green, test for yellow or red (in this order!) frameColor = SIG_FRAME_COL_GREEN; QString result2; if (summary & GpgME::Signature::KeyExpired) { // still is green! result2 += i18n("One key has expired."); } if (summary & GpgME::Signature::SigExpired) { // and still is green! result2 += i18n("The signature has expired."); } // test for yellow: if (summary & GpgME::Signature::KeyMissing) { result2 += i18n("Unable to verify: key missing."); // if the signature certificate is missing // we cannot show information on it showKeyInfos = false; frameColor = SIG_FRAME_COL_YELLOW; } if (summary & GpgME::Signature::CrlMissing) { result2 += i18n("CRL not available."); frameColor = SIG_FRAME_COL_YELLOW; } if (summary & GpgME::Signature::CrlTooOld) { result2 += i18n("Available CRL is too old."); frameColor = SIG_FRAME_COL_YELLOW; } if (summary & GpgME::Signature::BadPolicy) { result2 += i18n("A policy was not met."); frameColor = SIG_FRAME_COL_YELLOW; } if (summary & GpgME::Signature::SysError) { result2 += i18n("A system error occurred."); // if a system error occurred // we cannot trust any information // that was given back by the plug-in showKeyInfos = false; frameColor = SIG_FRAME_COL_YELLOW; } // test for red: if (summary & GpgME::Signature::KeyRevoked) { // this is red! result2 += i18n("One key has been revoked."); frameColor = SIG_FRAME_COL_RED; } if (summary & GpgME::Signature::Red) { if (result2.isEmpty()) // Note: // Here we are work differently than KMail did before! // // The BAD case ( == sig *not* matching ) // by definition does *not* show any key // information but just states that things are BAD. // // The reason for this: In this case ALL information // might be falsificated, we can NOT trust the data // in the body NOT the signature - so we don't show // any key/signature information at all! // (khz, according to LinuxTag 2002 meeting) { showKeyInfos = false; } frameColor = SIG_FRAME_COL_RED; } else { result.clear(); } if (SIG_FRAME_COL_GREEN == frameColor) { result = i18n("Good signature."); } else if (SIG_FRAME_COL_RED == frameColor) { result = i18n("Bad signature."); } else { result.clear(); } if (!result2.isEmpty()) { if (!result.isEmpty()) { result.append(QLatin1String("
")); } result.append(result2); } } /* // add i18n support for 3rd party plug-ins here: else if ( cryptPlug->libName().contains( "yetanotherpluginname", Qt::CaseInsensitive )) { } */ } return result; } /** Checks whether @p str contains external references. To be precise, we only check whether @p str contains 'xxx="http[s]:' where xxx is not href. Obfuscated external references are ignored on purpose. */ bool containsExternalReferences(const QString &str, const QString &extraHead) { const bool hasBaseInHeader = extraHead.contains(QStringLiteral("= 0 || httpsPos >= 0) { // pos = index of next occurrence of "http: or "https: whichever comes first int pos = (httpPos < httpsPos) ? ((httpPos >= 0) ? httpPos : httpsPos) : ((httpsPos >= 0) ? httpsPos : httpPos); // look backwards for "href" if (pos > 5) { int hrefPos = str.lastIndexOf(QLatin1String("href"), pos - 5, Qt::CaseInsensitive); // if no 'href' is found or the distance between 'href' and '"http[s]:' // is larger than 7 (7 is the distance in 'href = "http[s]:') then // we assume that we have found an external reference if ((hrefPos == -1) || (pos - hrefPos > 7)) { // HTML messages created by KMail itself for now contain the following: // // Make sure not to show an external references warning for this string int dtdPos = str.indexOf(QLatin1String("http://www.w3.org/TR/html4/loose.dtd"), pos + 1); if (dtdPos != (pos + 1)) { return true; } } } // find next occurrence of "http: or "https: if (pos == httpPos) { httpPos = str.indexOf(QLatin1String("\"http:"), httpPos + 6, Qt::CaseInsensitive); } else { httpsPos = str.indexOf(QLatin1String("\"https:"), httpsPos + 7, Qt::CaseInsensitive); } } return false; } QString processHtml(const QString &htmlSource, QString &extraHead) { // Create a DOM Document from the HTML source QWebPage page(0); page.settings()->setAttribute(QWebSettings::JavascriptEnabled, false); page.settings()->setAttribute(QWebSettings::JavaEnabled, false); page.settings()->setAttribute(QWebSettings::PluginsEnabled, false); page.settings()->setAttribute(QWebSettings::AutoLoadImages, false); QWebFrame *frame = page.mainFrame(); frame->setHtml(htmlSource); const QWebElement body = frame->documentElement().findFirst(QStringLiteral("body")); const QWebElement header = frame->documentElement().findFirst(QStringLiteral("head")); extraHead = header.toInnerXml(); return body.toInnerXml(); } class CacheHtmlWriter : public MimeTreeParser::HtmlWriter { public: explicit CacheHtmlWriter(MimeTreeParser::HtmlWriter *baseWriter) : mBaseWriter(baseWriter) {} virtual ~CacheHtmlWriter() {} void begin(const QString &text) Q_DECL_OVERRIDE {mBaseWriter->begin(text);} void write(const QString &str) Q_DECL_OVERRIDE { html.append(str); } void end() Q_DECL_OVERRIDE {mBaseWriter->end();} void reset() Q_DECL_OVERRIDE {mBaseWriter->reset();} void queue(const QString &str) Q_DECL_OVERRIDE { html.append(str); } void flush() Q_DECL_OVERRIDE {mBaseWriter->flush();} void embedPart(const QByteArray &contentId, const QString &url) Q_DECL_OVERRIDE {mBaseWriter->embedPart(contentId, url);} void extraHead(const QString &extra) Q_DECL_OVERRIDE {mBaseWriter->extraHead(extra);} QString html; MimeTreeParser::HtmlWriter *mBaseWriter; }; class MimeTreeParser::DefaultRendererPrivate { public: - DefaultRendererPrivate(DefaultRenderer *qPtr, const Interface::MessagePart::Ptr &msgPart) + DefaultRendererPrivate(DefaultRenderer *qPtr, const Interface::MessagePart::Ptr &msgPart, CSSHelperBase *cssHelper) : mMsgPart(msgPart) , q(qPtr) , mOldWriter(msgPart->htmlWriter()) + , mCSSHelper(cssHelper) { initializeGrantleeRenderer(); mHtml = renderFactory(mMsgPart, QSharedPointer()); } ~DefaultRendererPrivate() { delete m_engine; } CSSHelperBase *cssHelper() const { auto mp = mMsgPart.dynamicCast(); if (mp) { - return mp->cssHelper(); + return mCSSHelper; } return Q_NULLPTR; } Interface::ObjectTreeSource *source() const { auto mp = mMsgPart.dynamicCast(); if (mp) { return mp->source(); } return Q_NULLPTR; } void renderSubParts(const MessagePart::Ptr &msgPart, const QSharedPointer &htmlWriter) { foreach (const auto &_m, msgPart->subParts()) { const auto m = _m.dynamicCast(); if (m) { htmlWriter->queue(renderFactory(m, htmlWriter)); } } } QString render(const MessagePartList::Ptr &mp) { auto htmlWriter = QSharedPointer(new CacheHtmlWriter(mOldWriter)); { HTMLBlock::Ptr rBlock; HTMLBlock::Ptr aBlock; if (mp->isRoot()) { rBlock = HTMLBlock::Ptr(new RootBlock(htmlWriter.data())); } if (mp->isAttachment()) { aBlock = HTMLBlock::Ptr(new AttachmentMarkBlock(htmlWriter.data(), mp->attachmentNode())); } mp->setHtmlWriter(htmlWriter.data()); renderSubParts(mp, htmlWriter); mp->setHtmlWriter(mOldWriter); } return htmlWriter->html; } QString render(const MimeMessagePart::Ptr &mp) { auto htmlWriter = QSharedPointer(new CacheHtmlWriter(mOldWriter)); { HTMLBlock::Ptr aBlock; HTMLBlock::Ptr rBlock; if (mp->isAttachment()) { aBlock = HTMLBlock::Ptr(new AttachmentMarkBlock(htmlWriter.data(), mp->attachmentNode())); } if (mp->isRoot()) { rBlock = HTMLBlock::Ptr(new RootBlock(htmlWriter.data())); } renderSubParts(mp, htmlWriter); } return htmlWriter->html; } QString render(const EncapsulatedRfc822MessagePart::Ptr &mp) { if (!mp->hasSubParts()) { return QString(); } Grantlee::Template t = getGrantleeTemplate(QStringLiteral("encapsulatedrfc822messagepart.html")); Grantlee::Context c; QObject block; c.insert(QStringLiteral("block"), &block); block.setProperty("dir", QApplication::isRightToLeft() ? QStringLiteral("rtl") : QStringLiteral("ltr")); block.setProperty("link", mp->mOtp->nodeHelper()->asHREF(mp->mMessage.data(), QStringLiteral("body"))); c.insert(QStringLiteral("msgHeader"), mp->source()->createMessageHeader(mp->mMessage.data())); { auto _htmlWriter = QSharedPointer(new CacheHtmlWriter(mOldWriter)); renderSubParts(mp, _htmlWriter); c.insert(QStringLiteral("content"), _htmlWriter->html); } auto htmlWriter = QSharedPointer(new CacheHtmlWriter(mOldWriter)); { HTMLBlock::Ptr aBlock; if (mp->isAttachment()) { aBlock = HTMLBlock::Ptr(new AttachmentMarkBlock(htmlWriter.data(), mp->attachmentNode())); } const auto html = t->render(&c); htmlWriter->queue(html); } return htmlWriter->html; } QString render(const TextMessagePart::Ptr &mp) { KMime::Content *node = mp->mNode; NodeHelper *nodeHelper = mp->mOtp->nodeHelper(); if (mp->isHidden()) { return QString(); } Grantlee::Template t; Grantlee::Context c; QObject block; c.insert(QStringLiteral("block"), &block); block.setProperty("showTextFrame", mp->mDrawFrame); block.setProperty("label", MessageCore::StringUtil::quoteHtmlChars(NodeHelper::fileName(node), true)); block.setProperty("comment", MessageCore::StringUtil::quoteHtmlChars(node->contentDescription()->asUnicodeString(), true)); block.setProperty("link", nodeHelper->asHREF(node, QStringLiteral("body"))); block.setProperty("showLink", mp->mShowLink); block.setProperty("dir", QApplication::isRightToLeft() ? QStringLiteral("rtl") : QStringLiteral("ltr")); if (mp->mAsIcon != MimeTreeParser::NoIcon) { t = getGrantleeTemplate(QStringLiteral("asiconpart.html")); block.setProperty("iconSize", KIconLoader::global()->currentSize(KIconLoader::Desktop)); block.setProperty("inline", (mp->mAsIcon == MimeTreeParser::IconInline)); QString iconPath; if (mp->mAsIcon == MimeTreeParser::IconInline) { iconPath = nodeHelper->writeNodeToTempFile(node); } else { iconPath = MessageViewer::Util::iconPathForContent(node, KIconLoader::Desktop); if (iconPath.right(14) == QLatin1String("mime_empty.png")) { nodeHelper->magicSetType(node); iconPath = MessageViewer::Util::iconPathForContent(node, KIconLoader::Desktop); } } block.setProperty("iconPath", QUrl::fromLocalFile(iconPath).url()); const QString name = node->contentType()->name(); QString label = name.isEmpty() ? NodeHelper::fileName(node) : name; QString comment = node->contentDescription()->asUnicodeString(); if (label.isEmpty()) { label = i18nc("display name for an unnamed attachment", "Unnamed"); } label = MessageCore::StringUtil::quoteHtmlChars(label, true); comment = MessageCore::StringUtil::quoteHtmlChars(comment, true); if (label == comment) { comment.clear(); } block.setProperty("label", label); block.setProperty("comment", comment); } else { t = getGrantleeTemplate(QStringLiteral("textmessagepart.html")); auto _htmlWriter = QSharedPointer(new CacheHtmlWriter(mOldWriter)); renderSubParts(mp, _htmlWriter); c.insert(QStringLiteral("content"), _htmlWriter->html); } auto htmlWriter = QSharedPointer(new CacheHtmlWriter(mOldWriter)); { HTMLBlock::Ptr aBlock; if (mp->isAttachment()) { aBlock = HTMLBlock::Ptr(new AttachmentMarkBlock(htmlWriter.data(), mp->attachmentNode())); } const auto html = t->render(&c); htmlWriter->queue(html); } return htmlWriter->html; } QString quotedHTML(const QString &s, bool decorate) { assert(cssHelper()); KTextToHTML::Options convertFlags = KTextToHTML::PreserveSpaces | KTextToHTML::HighlightText; if (decorate && source()->showEmoticons()) { convertFlags |= KTextToHTML::ReplaceSmileys; } QString htmlStr; const QString normalStartTag = cssHelper()->nonQuotedFontTag(); QString quoteFontTag[3]; QString deepQuoteFontTag[3]; for (int i = 0; i < 3; ++i) { quoteFontTag[i] = cssHelper()->quoteFontTag(i); deepQuoteFontTag[i] = cssHelper()->quoteFontTag(i + 3); } const QString normalEndTag = QStringLiteral(""); const QString quoteEnd = QStringLiteral(""); const unsigned int length = s.length(); bool paraIsRTL = false; bool startNewPara = true; unsigned int pos, beg; // skip leading empty lines for (pos = 0; pos < length && s[pos] <= QLatin1Char(' '); ++pos) ; while (pos > 0 && (s[pos - 1] == QLatin1Char(' ') || s[pos - 1] == QLatin1Char('\t'))) { pos--; } beg = pos; int currQuoteLevel = -2; // -2 == no previous lines bool curHidden = false; // no hide any block if (source()->showExpandQuotesMark()) { // Cache Icons if (mCollapseIcon.isEmpty()) { mCollapseIcon = iconToDataUrl(IconNameCache::instance()->iconPath(QStringLiteral("quotecollapse"), 0)); } if (mExpandIcon.isEmpty()) { mExpandIcon = iconToDataUrl(IconNameCache::instance()->iconPath(QStringLiteral("quoteexpand"), 0)); } } int previousQuoteDepth = -1; while (beg < length) { /* search next occurrence of '\n' */ pos = s.indexOf(QLatin1Char('\n'), beg, Qt::CaseInsensitive); if (pos == (unsigned int)(-1)) { pos = length; } QString line(s.mid(beg, pos - beg)); beg = pos + 1; bool foundQuote = false; /* calculate line's current quoting depth */ int actQuoteLevel = -1; const int numberOfCaracters(line.length()); int quoteLength = 0; for (int p = 0; p < numberOfCaracters; ++p) { switch (line[p].toLatin1()) { case '>': case '|': actQuoteLevel++; quoteLength = p; foundQuote = true; break; case ' ': // spaces and tabs are allowed between the quote markers case '\t': case '\r': quoteLength = p; break; default: // stop quoting depth calculation p = numberOfCaracters; break; } } /* for() */ if (!foundQuote) { quoteLength = 0; } bool actHidden = false; // This quoted line needs be hidden if (source()->showExpandQuotesMark() && source()->levelQuote() >= 0 && source()->levelQuote() <= (actQuoteLevel)) { actHidden = true; } if (actQuoteLevel != currQuoteLevel) { /* finish last quotelevel */ if (currQuoteLevel == -1) { htmlStr.append(normalEndTag); } else if (currQuoteLevel >= 0 && !curHidden) { htmlStr.append(quoteEnd); } //Close blockquote if (previousQuoteDepth > actQuoteLevel) { htmlStr += cssHelper()->addEndBlockQuote((previousQuoteDepth - actQuoteLevel)); } /* start new quotelevel */ if (actQuoteLevel == -1) { htmlStr += normalStartTag; } else { if (source()->showExpandQuotesMark()) { if (actHidden) { //only show the QuoteMark when is the first line of the level hidden if (!curHidden) { //Expand all quotes htmlStr += QLatin1String("
"); htmlStr += QStringLiteral("" "") .arg(-1) .arg(mExpandIcon); htmlStr += QLatin1String("

"); htmlStr += quoteEnd; } } else { htmlStr += QLatin1String("
"); htmlStr += QStringLiteral("" "") .arg(actQuoteLevel) .arg(mCollapseIcon); htmlStr += QLatin1String("
"); if (actQuoteLevel < 3) { htmlStr += quoteFontTag[actQuoteLevel]; } else { htmlStr += deepQuoteFontTag[actQuoteLevel % 3]; } } } else { // Add blockquote if (previousQuoteDepth < actQuoteLevel) { htmlStr += cssHelper()->addStartBlockQuote(actQuoteLevel - previousQuoteDepth); } if (actQuoteLevel < 3) { htmlStr += quoteFontTag[actQuoteLevel]; } else { htmlStr += deepQuoteFontTag[actQuoteLevel % 3]; } } } currQuoteLevel = actQuoteLevel; } curHidden = actHidden; if (!actHidden) { // don't write empty
blocks (they have zero height) // ignore ^M DOS linebreaks if (!line.remove(QLatin1Char('\015')).isEmpty()) { if (startNewPara) { paraIsRTL = line.isRightToLeft(); } htmlStr += QStringLiteral("
").arg(paraIsRTL ? QStringLiteral("rtl") : QStringLiteral("ltr")); // if quoteLengh == 0 && foundQuote => a simple quote if (foundQuote) { quoteLength++; htmlStr += QStringLiteral("%1").arg(line.left(quoteLength)); const int rightString = (line.length()) - quoteLength; if (rightString > 0) { htmlStr += QStringLiteral("").arg(cssHelper()->quoteColorName(actQuoteLevel)) + KTextToHTML::convertToHtml(line.right(rightString), convertFlags) + QStringLiteral(""); } } else { htmlStr += KTextToHTML::convertToHtml(line, convertFlags); } htmlStr += QLatin1String("
"); startNewPara = looksLikeParaBreak(s, pos); } else { htmlStr += QLatin1String("
"); // after an empty line, always start a new paragraph startNewPara = true; } } previousQuoteDepth = actQuoteLevel; } /* while() */ /* really finish the last quotelevel */ if (currQuoteLevel == -1) { htmlStr.append(normalEndTag); } else { htmlStr += quoteEnd + cssHelper()->addEndBlockQuote(currQuoteLevel + 1); } // qCDebug(MESSAGEVIEWER_LOG) << "========================================\n" // << htmlStr // << "\n======================================\n"; return htmlStr; } QString render(const MessagePart::Ptr mp) { auto htmlWriter = QSharedPointer(new CacheHtmlWriter(mOldWriter)); { HTMLBlock::Ptr aBlock; if (mp->isAttachment()) { aBlock = HTMLBlock::Ptr(new AttachmentMarkBlock(htmlWriter.data(), mp->attachmentNode())); } htmlWriter->queue(quotedHTML(mp->text(), false)); } return htmlWriter->html; } QString render(const HtmlMessagePart::Ptr &mp) { Grantlee::Template t = getGrantleeTemplate(QStringLiteral("htmlmessagepart.html")); Grantlee::Context c; QObject block; c.insert(QStringLiteral("block"), &block); block.setProperty("htmlMail", mp->source()->htmlMail()); block.setProperty("loadExternal", mp->source()->htmlLoadExternal()); { QString extraHead; QString bodyText = processHtml(mp->mBodyHTML, extraHead); if (mp->source()->htmlMail()) { mp->mOtp->nodeHelper()->setNodeDisplayedEmbedded(mp->mNode, true); mOldWriter->extraHead(extraHead); } block.setProperty("containsExternalReferences", containsExternalReferences(bodyText, extraHead)); c.insert(QStringLiteral("content"), bodyText); } { ConvertHtmlToPlainText convert; convert.setHtmlString(mp->mBodyHTML); QString plaintext = convert.generatePlainText(); plaintext.replace(QLatin1String("\n"), QStringLiteral("
")); c.insert(QStringLiteral("plaintext"), plaintext); } mp->source()->setHtmlMode(Util::Html); auto htmlWriter = QSharedPointer(new CacheHtmlWriter(mOldWriter)); { HTMLBlock::Ptr aBlock; if (mp->isAttachment()) { aBlock = HTMLBlock::Ptr(new AttachmentMarkBlock(htmlWriter.data(), mp->attachmentNode())); } const auto html = t->render(&c); htmlWriter->queue(html); } return htmlWriter->html; } QString renderEncrypted(const CryptoMessagePart::Ptr &mp) { KMime::Content *node = mp->mNode; const auto metaData = mp->mMetaData; Grantlee::Template t = getGrantleeTemplate(QStringLiteral("encryptedmessagepart.html")); Grantlee::Context c; QObject block; if (metaData.isSigned) { c.insert(QStringLiteral("content"), renderSigned(mp)); } else if (node) { auto _htmlWriter = QSharedPointer(new CacheHtmlWriter(mOldWriter)); { HTMLBlock::Ptr rBlock; if (mp->isRoot()) { rBlock = HTMLBlock::Ptr(new RootBlock(_htmlWriter.data())); } renderSubParts(mp, _htmlWriter); } c.insert(QStringLiteral("content"), _htmlWriter->html); } else { c.insert(QStringLiteral("content"), render(mp.dynamicCast())); } c.insert(QStringLiteral("cryptoProto"), QVariant::fromValue(mp->mCryptoProto)); if (mp->mDecryptRecipients.size() > 0) { c.insert(QStringLiteral("decryptedRecipients"), QVariant::fromValue(mp->mDecryptRecipients)); } c.insert(QStringLiteral("block"), &block); block.setProperty("dir", QApplication::isRightToLeft() ? QStringLiteral("rtl") : QStringLiteral("ltr")); block.setProperty("inProgress", metaData.inProgress); block.setProperty("isDecrypted", mp->decryptMessage()); block.setProperty("isDecryptable", metaData.isDecryptable); block.setProperty("decryptIcon", QUrl::fromLocalFile(IconNameCache::instance()->iconPath(QStringLiteral("document-decrypt"), KIconLoader::Small)).url()); block.setProperty("errorText", metaData.errorText); block.setProperty("noSecKey", mp->mNoSecKey); const auto html = t->render(&c); return html; } QString renderSigned(const CryptoMessagePart::Ptr &mp) { KMime::Content *node = mp->mNode; const auto metaData = mp->mMetaData; auto cryptoProto = mp->mCryptoProto; const bool isSMIME = cryptoProto && (cryptoProto == Kleo::CryptoBackendFactory::instance()->smime()); Grantlee::Template t = getGrantleeTemplate(QStringLiteral("signedmessagepart.html")); Grantlee::Context c; QObject block; if (node) { auto _htmlWriter = QSharedPointer(new CacheHtmlWriter(mOldWriter)); { HTMLBlock::Ptr rBlock; if (mp->isRoot()) { rBlock = HTMLBlock::Ptr(new RootBlock(_htmlWriter.data())); } renderSubParts(mp, _htmlWriter); } c.insert(QStringLiteral("content"), _htmlWriter->html); } else { c.insert(QStringLiteral("content"), render(mp.dynamicCast())); } c.insert(QStringLiteral("cryptoProto"), QVariant::fromValue(cryptoProto)); c.insert(QStringLiteral("block"), &block); block.setProperty("dir", QApplication::isRightToLeft() ? QStringLiteral("rtl") : QStringLiteral("ltr")); block.setProperty("inProgress", metaData.inProgress); block.setProperty("errorText", metaData.errorText); block.setProperty("detailHeader", mp->source()->showSignatureDetails()); block.setProperty("printing", false); block.setProperty("addr", metaData.signerMailAddresses); block.setProperty("technicalProblem", metaData.technicalProblem); block.setProperty("keyId", metaData.keyId); if (metaData.creationTime.isValid()) { //should be handled inside grantlee but currently not possible see: https://bugs.kde.org/363475 block.setProperty("creationTime", QLocale().toString(metaData.creationTime, QLocale::ShortFormat)); } block.setProperty("isGoodSignature", metaData.isGoodSignature); block.setProperty("isSMIME", isSMIME); if (metaData.keyTrust == GpgME::Signature::Unknown) { block.setProperty("keyTrust", QStringLiteral("unknown")); } else if (metaData.keyTrust == GpgME::Signature::Marginal) { block.setProperty("keyTrust", QStringLiteral("marginal")); } else if (metaData.keyTrust == GpgME::Signature::Full) { block.setProperty("keyTrust", QStringLiteral("full")); } else if (metaData.keyTrust == GpgME::Signature::Ultimate) { block.setProperty("keyTrust", QStringLiteral("ultimate")); } else { block.setProperty("keyTrust", QStringLiteral("untrusted")); } QString startKeyHREF; { QString keyWithWithoutURL; if (cryptoProto) { startKeyHREF = QStringLiteral("") .arg(cryptoProto->displayName(), cryptoProto->name(), QString::fromLatin1(metaData.keyId)); keyWithWithoutURL = QStringLiteral("%1%2").arg(startKeyHREF, QString::fromLatin1(QByteArray(QByteArray("0x") + metaData.keyId))); } else { keyWithWithoutURL = QStringLiteral("0x") + QString::fromUtf8(metaData.keyId); } block.setProperty("keyWithWithoutURL", keyWithWithoutURL); } bool onlyShowKeyURL = false; bool showKeyInfos = false; bool cannotCheckSignature = true; QString signer = metaData.signer; QString statusStr; QString mClass; QString greenCaseWarning; if (metaData.inProgress) { mClass = QStringLiteral("signInProgress"); } else { const QStringList &blockAddrs(metaData.signerMailAddresses); // note: At the moment frameColor and showKeyInfos are // used for CMS only but not for PGP signatures // pending(khz): Implement usage of these for PGP sigs as well. int frameColor = SIG_FRAME_COL_UNDEF; statusStr = sigStatusToString(cryptoProto, metaData.status_code, metaData.sigSummary, frameColor, showKeyInfos); // if needed fallback to english status text // that was reported by the plugin if (statusStr.isEmpty()) { statusStr = metaData.status; } if (metaData.technicalProblem) { frameColor = SIG_FRAME_COL_YELLOW; } switch (frameColor) { case SIG_FRAME_COL_RED: cannotCheckSignature = false; break; case SIG_FRAME_COL_YELLOW: cannotCheckSignature = true; break; case SIG_FRAME_COL_GREEN: cannotCheckSignature = false; break; } // temporary hack: always show key information! showKeyInfos = true; if (isSMIME && (SIG_FRAME_COL_UNDEF != frameColor)) { switch (frameColor) { case SIG_FRAME_COL_RED: mClass = QStringLiteral("signErr"); onlyShowKeyURL = true; break; case SIG_FRAME_COL_YELLOW: if (metaData.technicalProblem) { mClass = QStringLiteral("signWarn"); } else { mClass = QStringLiteral("signOkKeyBad"); } break; case SIG_FRAME_COL_GREEN: mClass = QStringLiteral("signOkKeyOk"); // extra hint for green case // that email addresses in DN do not match fromAddress QString msgFrom(KEmailAddress::extractEmailAddress(mp->mFromAddress)); QString certificate; if (metaData.keyId.isEmpty()) { certificate = i18n("certificate"); } else { certificate = startKeyHREF + i18n("certificate") + QStringLiteral(""); } if (!blockAddrs.empty()) { if (!blockAddrs.contains(msgFrom, Qt::CaseInsensitive)) { greenCaseWarning = QStringLiteral("") + i18nc("Start of warning message.", "Warning:") + QStringLiteral(" ") + i18n("Sender's mail address is not stored in the %1 used for signing.", certificate) + QStringLiteral("
") + i18n("sender: ") + msgFrom + QStringLiteral("
") + i18n("stored: "); // We cannot use Qt's join() function here but // have to join the addresses manually to // extract the mail addresses (without '<''>') // before including it into our string: bool bStart = true; for (QStringList::ConstIterator it = blockAddrs.constBegin(); it != blockAddrs.constEnd(); ++it) { if (!bStart) { greenCaseWarning.append(QStringLiteral(",
   ")); } bStart = false; greenCaseWarning.append(KEmailAddress::extractEmailAddress(*it)); } } } else { greenCaseWarning = QStringLiteral("") + i18nc("Start of warning message.", "Warning:") + QStringLiteral(" ") + i18n("No mail address is stored in the %1 used for signing, " "so we cannot compare it to the sender's address %2.", certificate, msgFrom); } break; } if (showKeyInfos && !cannotCheckSignature) { if (metaData.signer.isEmpty()) { signer.clear(); } else { if (!blockAddrs.empty()) { const QUrl address = KEmailAddress::encodeMailtoUrl(blockAddrs.first()); signer = QStringLiteral("%2").arg(QLatin1String(QUrl::toPercentEncoding(address.path())), signer); } } } } else { if (metaData.signer.isEmpty() || metaData.technicalProblem) { mClass = QStringLiteral("signWarn"); } else { // HTMLize the signer's user id and create mailto: link signer = MessageCore::StringUtil::quoteHtmlChars(signer, true); signer = QStringLiteral("%1").arg(signer); if (metaData.isGoodSignature) { if (metaData.keyTrust < GpgME::Signature::Marginal) { mClass = QStringLiteral("signOkKeyBad"); } else { mClass = QStringLiteral("signOkKeyOk"); } } else { mClass = QStringLiteral("signErr"); } } } } block.setProperty("onlyShowKeyURL", onlyShowKeyURL); block.setProperty("showKeyInfos", showKeyInfos); block.setProperty("cannotCheckSignature", cannotCheckSignature); block.setProperty("signer", signer); block.setProperty("statusStr", statusStr); block.setProperty("signClass", mClass); block.setProperty("greenCaseWarning", greenCaseWarning); const auto html = t->render(&c); return html; } QString render(const CryptoMessagePart::Ptr &mp) { auto htmlWriter = QSharedPointer(new CacheHtmlWriter(mOldWriter)); const auto metaData = mp->mMetaData; if (metaData.isEncrypted) { { HTMLBlock::Ptr aBlock; if (mp->isAttachment()) { aBlock = HTMLBlock::Ptr(new AttachmentMarkBlock(htmlWriter.data(), mp->attachmentNode())); } htmlWriter->queue(renderEncrypted(mp)); } return htmlWriter->html; } if (metaData.isSigned) { { HTMLBlock::Ptr aBlock; if (mp->isAttachment()) { aBlock = HTMLBlock::Ptr(new AttachmentMarkBlock(htmlWriter.data(), mp->attachmentNode())); } htmlWriter->queue(renderSigned(mp)); } return htmlWriter->html; } { HTMLBlock::Ptr aBlock; if (mp->isAttachment()) { aBlock = HTMLBlock::Ptr(new AttachmentMarkBlock(htmlWriter.data(), mp->attachmentNode())); } if (mp->mNode) { renderSubParts(mp, htmlWriter); } else { htmlWriter->queue(render(mp.dynamicCast())); } } return htmlWriter->html; } QString render(const AlternativeMessagePart::Ptr &mp) { auto htmlWriter = QSharedPointer(new CacheHtmlWriter(mOldWriter)); { HTMLBlock::Ptr aBlock; if (mp->isAttachment()) { aBlock = HTMLBlock::Ptr(new AttachmentMarkBlock(htmlWriter.data(), mp->attachmentNode())); } MimeMessagePart::Ptr part(mp->mTextPart); if (mp->viewHtml() && mp->mHTMLPart) { part = mp->mHTMLPart; } else if (mp->text().trimmed().isEmpty()) { part = mp->mHTMLPart; } htmlWriter->queue(render(part)); } return htmlWriter->html; } QString render(const CertMessagePart::Ptr &mp) { const GpgME::ImportResult &importResult(mp->mImportResult); Grantlee::Template t = getGrantleeTemplate(QStringLiteral("certmessagepart.html")); Grantlee::Context c; QObject block; c.insert(QStringLiteral("block"), &block); block.setProperty("importError", QString::fromLocal8Bit(importResult.error().asString())); block.setProperty("nImp", importResult.numImported()); block.setProperty("nUnc", importResult.numUnchanged()); block.setProperty("nSKImp", importResult.numSecretKeysImported()); block.setProperty("nSKUnc", importResult.numSecretKeysUnchanged()); QVariantList keylist; const auto imports = importResult.imports(); auto end(imports.end()); for (auto it = imports.begin(); it != end; ++it) { QObject *key(new QObject(mp.data())); key->setProperty("error", QString::fromLocal8Bit((*it).error().asString())); key->setProperty("status", (*it).status()); key->setProperty("fingerprint", QLatin1String((*it).fingerprint())); keylist << QVariant::fromValue(key); } auto htmlWriter = QSharedPointer(new CacheHtmlWriter(mOldWriter)); { HTMLBlock::Ptr aBlock; if (mp->isAttachment()) { aBlock = HTMLBlock::Ptr(new AttachmentMarkBlock(htmlWriter.data(), mp->attachmentNode())); } const auto html = t->render(&c); htmlWriter->queue(html); } return htmlWriter->html; } QString renderFactory(const Interface::MessagePart::Ptr &msgPart, const QSharedPointer &htmlWriter) { const QString className = QString::fromUtf8(msgPart->metaObject()->className()); if (className == QStringLiteral("MimeTreeParser::MessagePartList")) { auto mp = msgPart.dynamicCast(); if (mp) { return render(mp); } } else if (className == QStringLiteral("MimeTreeParser::MimeMessagePart")) { auto mp = msgPart.dynamicCast(); if (mp) { return render(mp); } } else if (className == QStringLiteral("MimeTreeParser::EncapsulatedRfc822MessagePart")) { auto mp = msgPart.dynamicCast(); if (mp) { return render(mp); } } else if (className == QStringLiteral("MimeTreeParser::TextMessagePart")) { auto mp = msgPart.dynamicCast(); if (mp) { return render(mp); } } else if (className == QStringLiteral("MimeTreeParser::HtmlMessagePart")) { auto mp = msgPart.dynamicCast(); if (mp) { return render(mp); } } else if (className == QStringLiteral("MimeTreeParser::CryptoMessagePart")) { auto mp = msgPart.dynamicCast(); if (mp) { return render(mp); } } else if (className == QStringLiteral("MimeTreeParser::AlternativeMessagePart")) { auto mp = msgPart.dynamicCast(); if (mp) { return render(mp); } } else if (className == QStringLiteral("MimeTreeParser::CertMessagePart")) { auto mp = msgPart.dynamicCast(); if (mp) { return render(mp); } } else if (className == QStringLiteral("MimeTreeParser::MessagePart")) { auto mp = msgPart.dynamicCast(); if (mp) { return render(mp); } } qDebug(MESSAGEVIEWER_LOG) << "We got a unkonwn classname, using default behaviour for " << className; auto _htmlWriter = htmlWriter; if (!_htmlWriter) { _htmlWriter = QSharedPointer(new CacheHtmlWriter(mOldWriter)); } msgPart->setHtmlWriter(_htmlWriter.data()); msgPart->html(false); msgPart->setHtmlWriter(mOldWriter); if (!htmlWriter) { return _htmlWriter->html; } return QString(); } QString mHtml; Interface::MessagePart::Ptr mMsgPart; private: void initializeGrantleeRenderer() { Grantlee::registerMetaType(); Grantlee::registerMetaType(); m_engine = new Grantlee::Engine; m_engine->setSmartTrimEnabled(true); m_engine->addDefaultLibrary(QStringLiteral("grantlee_i18n")); m_engine->addDefaultLibrary(QStringLiteral("grantlee_scriptabletags")); auto loader = QSharedPointer(new GrantleeTheme::QtResourceTemplateLoader()); loader->setTemplateDirs(QStringList() << QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("/messageviewer/messagepartthemes/default"), QStandardPaths::LocateDirectory)); m_engine->addTemplateLoader(loader); } Grantlee::Template getGrantleeTemplate(const QString &name) { Grantlee::Template t = m_engine->loadByName(name); if (t->error()) { qCWarning(MESSAGEVIEWER_LOG) << t->errorString() << ". Searched in subdir mimetreeparser/themes/default in these locations" << QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); } return t; } DefaultRenderer *q; HtmlWriter *mOldWriter; Grantlee::Engine *m_engine; + CSSHelperBase *mCSSHelper; QString mCollapseIcon; QString mExpandIcon; }; -DefaultRenderer::DefaultRenderer(const MimeTreeParser::Interface::MessagePart::Ptr &msgPart) - : d(new MimeTreeParser::DefaultRendererPrivate(this, msgPart)) +DefaultRenderer::DefaultRenderer(const MimeTreeParser::Interface::MessagePart::Ptr &msgPart, CSSHelperBase *cssHelper) + : d(new MimeTreeParser::DefaultRendererPrivate(this, msgPart, cssHelper)) { } DefaultRenderer::~DefaultRenderer() { delete d; } QString DefaultRenderer::html() const { return d->mHtml; } diff --git a/messageviewer/src/messagepartthemes/default/defaultrenderer.h b/messageviewer/src/messagepartthemes/default/defaultrenderer.h index 695124ac..e06c0d94 100644 --- a/messageviewer/src/messagepartthemes/default/defaultrenderer.h +++ b/messageviewer/src/messagepartthemes/default/defaultrenderer.h @@ -1,54 +1,55 @@ /* 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. */ #ifndef __MESSAGEVIEWER_DEFAULTRENDERER_H__ #define __MESSAGEVIEWER_DEFAULTRENDERER_H__ #include #include namespace MimeTreeParser { class DefaultRendererPrivate; namespace Interface { class MessagePart; typedef QSharedPointer MessagePartPtr; } } namespace MessageViewer { +class CSSHelperBase; class DefaultRendererPrivate; class DefaultRenderer : public MimeTreeParser::Interface::MessagePartRenderer { public: - DefaultRenderer(const MimeTreeParser::Interface::MessagePartPtr& msgPart); + DefaultRenderer(const MimeTreeParser::Interface::MessagePartPtr& msgPart, CSSHelperBase *cssHelder); ~DefaultRenderer(); QString html() const Q_DECL_OVERRIDE; private: MimeTreeParser::DefaultRendererPrivate *d; }; } #endif //__MIMETREEPARSER_MAILRENDERER_H__ diff --git a/messageviewer/src/viewer/csshelper.cpp b/messageviewer/src/viewer/csshelper.cpp index 6f4b232e..9f976d5f 100644 --- a/messageviewer/src/viewer/csshelper.cpp +++ b/messageviewer/src/viewer/csshelper.cpp @@ -1,154 +1,154 @@ /* csshelper.cpp This file is part of KMail, the KDE mail client. Copyright (c) 2003 Marc Mutz KMail is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation. KMail 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "csshelper.h" #include "settings/messageviewersettings.h" #include "MessageCore/MessageCoreSettings" #include #include #include #include #include #include namespace MessageViewer { -CSSHelper::CSSHelper(const QPaintDevice *pd) : - MimeTreeParser::CSSHelperBase(pd) +CSSHelper::CSSHelper(const QPaintDevice *pd) + : CSSHelperBase(pd) { const KColorScheme scheme(QPalette::Active, KColorScheme::View); // initialize with defaults - should match the corresponding application defaults mForegroundColor = QApplication::palette().color(QPalette::Text); mLinkColor = scheme.foreground(KColorScheme::LinkText).color(); mBackgroundColor = QApplication::palette().color(QPalette::Base); cHtmlWarning = QColor(0xFF, 0x40, 0x40); // warning frame color: light red cPgpEncrH = MessageCore::Util::pgpEncryptedMessageColor(); cPgpEncrHT = MessageCore::Util::pgpEncryptedTextColor(); cPgpOk1H = MessageCore::Util::pgpSignedTrustedMessageColor(); cPgpOk1HT = MessageCore::Util::pgpSignedTrustedTextColor(); cPgpOk0H = MessageCore::Util::pgpSignedUntrustedMessageColor(); cPgpOk0HT = MessageCore::Util::pgpSignedUntrustedTextColor(); cPgpWarnH = MessageCore::Util::pgpSignedUntrustedMessageColor(); cPgpWarnHT = MessageCore::Util::pgpSignedUntrustedTextColor(); cPgpErrH = MessageCore::Util::pgpSignedBadMessageColor(); cPgpErrHT = MessageCore::Util::pgpSignedBadTextColor(); if (MessageCore::MessageCoreSettings::self()->useDefaultColors()) { mQuoteColor[0] = MessageCore::Util::quoteLevel1DefaultTextColor(); mQuoteColor[1] = MessageCore::Util::quoteLevel2DefaultTextColor(); mQuoteColor[2] = MessageCore::Util::quoteLevel3DefaultTextColor(); } else { mQuoteColor[0] = MessageCore::MessageCoreSettings::self()->quotedText1(); mQuoteColor[1] = MessageCore::MessageCoreSettings::self()->quotedText2(); mQuoteColor[2] = MessageCore::MessageCoreSettings::self()->quotedText3(); } mRecycleQuoteColors = false; QFont defaultFont = QFontDatabase::systemFont(QFontDatabase::GeneralFont); QFont defaultFixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); mBodyFont = MessageCore::MessageCoreSettings::self()->useDefaultFonts() ? defaultFont : MessageViewer::MessageViewerSettings::self()->bodyFont(); mPrintFont = MessageCore::MessageCoreSettings::self()->useDefaultFonts() ? defaultFont : MessageViewer::MessageViewerSettings::self()->printFont(); mFixedFont = mFixedPrintFont = defaultFixedFont; defaultFont.setItalic(true); for (int i = 0; i < 3; ++i) { mQuoteFont[i] = defaultFont; } KConfig *config = MessageViewer::MessageViewerSettings::self()->config(); KConfigGroup reader(config, "Reader"); KConfigGroup fonts(config, "Fonts"); mRecycleQuoteColors = reader.readEntry("RecycleQuoteColors", false); mForegroundColor = KColorScheme(QPalette::Active).foreground().color(); if (!MessageCore::MessageCoreSettings::self()->useDefaultColors()) { mLinkColor = reader.readEntry("LinkColor", mLinkColor); cPgpEncrH = reader.readEntry("PGPMessageEncr", cPgpEncrH); cPgpOk1H = reader.readEntry("PGPMessageOkKeyOk", cPgpOk1H); cPgpOk0H = reader.readEntry("PGPMessageOkKeyBad", cPgpOk0H); cPgpWarnH = reader.readEntry("PGPMessageWarn", cPgpWarnH); cPgpErrH = reader.readEntry("PGPMessageErr", cPgpErrH); cHtmlWarning = reader.readEntry("HTMLWarningColor", cHtmlWarning); for (int i = 0; i < 3; ++i) { const QString key = QLatin1String("QuotedText") + QString::number(i + 1); mQuoteColor[i] = reader.readEntry(key, mQuoteColor[i]); } } if (!MessageCore::MessageCoreSettings::self()->useDefaultFonts()) { mBodyFont = fonts.readEntry("body-font", mBodyFont); mPrintFont = fonts.readEntry("print-font", mPrintFont); mFixedFont = fonts.readEntry("fixed-font", mFixedFont); mFixedPrintFont = mFixedFont; // FIXME when we have a separate fixed print font QFont defaultFont = mBodyFont; defaultFont.setItalic(true); for (int i = 0; i < 3; ++i) { const QString key = QStringLiteral("quote%1-font").arg(i + 1); mQuoteFont[i] = fonts.readEntry(key, defaultFont); } } mShrinkQuotes = MessageViewer::MessageViewerSettings::self()->shrinkQuotes(); recalculatePGPColors(); } CSSHelper::~CSSHelper() { } QString CSSHelper::htmlHead(bool fixed) const { return QLatin1String("\n" "\n" "\n"); } } diff --git a/messageviewer/src/viewer/csshelper.h b/messageviewer/src/viewer/csshelper.h index 78a7d03b..41684279 100644 --- a/messageviewer/src/viewer/csshelper.h +++ b/messageviewer/src/viewer/csshelper.h @@ -1,55 +1,55 @@ /* -*- c++ -*- csshelper.h This file is part of KMail, the KDE mail client. Copyright (c) 2003 Marc Mutz KMail is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation. KMail 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __MESSAGEVIEWER_CSSHELPER_H__ #define __MESSAGEVIEWER_CSSHELPER_H__ -#include +#include #include "messageviewer_export.h" namespace MessageViewer { -class MESSAGEVIEWER_EXPORT CSSHelper : public MimeTreeParser::CSSHelperBase +class MESSAGEVIEWER_EXPORT CSSHelper : public CSSHelperBase { public: explicit CSSHelper(const QPaintDevice *pd); virtual ~CSSHelper(); /** @return HTML head including style sheet definitions and the >body< tag */ QString htmlHead(bool fixedFont = false) const Q_DECL_OVERRIDE; }; } #endif // __MESSAGEVIEWER_CSSHELPER_H__ diff --git a/mimetreeparser/src/viewer/csshelperbase.cpp b/messageviewer/src/viewer/csshelperbase.cpp similarity index 99% rename from mimetreeparser/src/viewer/csshelperbase.cpp rename to messageviewer/src/viewer/csshelperbase.cpp index 24becb9c..8287e59f 100644 --- a/mimetreeparser/src/viewer/csshelperbase.cpp +++ b/messageviewer/src/viewer/csshelperbase.cpp @@ -1,747 +1,747 @@ /* csshelper.cpp This file is part of KMail, the KDE mail client. Copyright (c) 2003 Marc Mutz KMail is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation. KMail 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "csshelperbase.h" #include #include #include -namespace MimeTreeParser +namespace MessageViewer { namespace { // some QColor manipulators that hide the ugly QColor API w.r.t. HSV: inline QColor darker(const QColor &c) { int h, s, v; c.getHsv(&h, &s, &v); return QColor::fromHsv(h, s, v * 4 / 5); } inline QColor desaturate(const QColor &c) { int h, s, v; c.getHsv(&h, &s, &v); return QColor::fromHsv(h, s / 8, v); } inline QColor fixValue(const QColor &c, int newV) { int h, s, v; c.getHsv(&h, &s, &v); return QColor::fromHsv(h, s, newV); } inline int getValueOf(const QColor &c) { int h, s, v; c.getHsv(&h, &s, &v); return v; } } CSSHelperBase::CSSHelperBase(const QPaintDevice *pd) : mRecycleQuoteColors(false) , mShrinkQuotes(false) , cHtmlWarning(QColor(0xFF, 0x40, 0x40)) , mPaintDevice(pd) { recalculatePGPColors(); } CSSHelperBase::~CSSHelperBase() { } void CSSHelperBase::recalculatePGPColors() { // determine the frame and body color for PGP messages from the header color // if the header color equals the background color then the other colors are // also set to the background color (-> old style PGP message viewing) // else // the brightness of the frame is set to 4/5 of the brightness of the header // and in case of a light background color // the saturation of the body is set to 1/8 of the saturation of the header // while in case of a dark background color // the value of the body is set to the value of the background color // Check whether the user uses a light color scheme const int vBG = getValueOf(mBackgroundColor); const bool lightBG = vBG >= 128; if (cPgpOk1H == mBackgroundColor) { cPgpOk1F = mBackgroundColor; cPgpOk1B = mBackgroundColor; } else { cPgpOk1F = darker(cPgpOk1H); cPgpOk1B = lightBG ? desaturate(cPgpOk1H) : fixValue(cPgpOk1H, vBG); } if (cPgpOk0H == mBackgroundColor) { cPgpOk0F = mBackgroundColor; cPgpOk0B = mBackgroundColor; } else { cPgpOk0F = darker(cPgpOk0H); cPgpOk0B = lightBG ? desaturate(cPgpOk0H) : fixValue(cPgpOk0H, vBG); } if (cPgpWarnH == mBackgroundColor) { cPgpWarnF = mBackgroundColor; cPgpWarnB = mBackgroundColor; } else { cPgpWarnF = darker(cPgpWarnH); cPgpWarnB = lightBG ? desaturate(cPgpWarnH) : fixValue(cPgpWarnH, vBG); } if (cPgpErrH == mBackgroundColor) { cPgpErrF = mBackgroundColor; cPgpErrB = mBackgroundColor; } else { cPgpErrF = darker(cPgpErrH); cPgpErrB = lightBG ? desaturate(cPgpErrH) : fixValue(cPgpErrH, vBG); } if (cPgpEncrH == mBackgroundColor) { cPgpEncrF = mBackgroundColor; cPgpEncrB = mBackgroundColor; } else { cPgpEncrF = darker(cPgpEncrH); cPgpEncrB = lightBG ? desaturate(cPgpEncrH) : fixValue(cPgpEncrH, vBG); } } QString CSSHelperBase::addEndBlockQuote(int numberBlock) const { QString blockQuote; for (int i = 0; i < numberBlock; ++i) { blockQuote += QLatin1String(""); } return blockQuote; } QString CSSHelperBase::addStartBlockQuote(int numberBlock) const { QString blockQuote; for (int i = 0; i < numberBlock; ++i) { blockQuote += QLatin1String("
"); } return blockQuote; } QString CSSHelperBase::cssDefinitions(bool fixed) const { return commonCssDefinitions() + QLatin1String("@media screen {\n\n") + screenCssDefinitions(this, fixed) + QLatin1String("}\n" "@media print {\n\n") + printCssDefinitions(fixed) + QLatin1String("}\n"); } QString CSSHelperBase::htmlHead(bool fixedFont) const { Q_UNUSED(fixedFont); return QStringLiteral("\n" "\n" "\n"); } QString CSSHelperBase::quoteFontTag(int level) const { if (level < 0) { level = 0; } static const int numQuoteLevels = sizeof mQuoteFont / sizeof * mQuoteFont; const int effectiveLevel = mRecycleQuoteColors ? level % numQuoteLevels + 1 : qMin(level + 1, numQuoteLevels); if (level >= numQuoteLevels) { return QStringLiteral("
").arg(effectiveLevel); } else { return QStringLiteral("
").arg(effectiveLevel); } } QString CSSHelperBase::nonQuotedFontTag() const { return QStringLiteral("
"); } QFont CSSHelperBase::bodyFont(bool fixed, bool print) const { return fixed ? (print ? mFixedPrintFont : mFixedFont) : (print ? mPrintFont : mBodyFont); } int CSSHelperBase::fontSize(bool fixed, bool print) const { return bodyFont(fixed, print).pointSize(); } namespace { int pointsToPixel(const QPaintDevice *pd, int pointSize) { return (pointSize * pd->logicalDpiY() + 36) / 72; } } static const char *const quoteFontSizes[] = { "85", "80", "75" }; QString CSSHelperBase::printCssDefinitions(bool fixed) const { const QString headerFont = QStringLiteral(" font-family: \"%1\" ! important;\n" " font-size: %2pt ! important;\n") .arg(mPrintFont.family()) .arg(mPrintFont.pointSize()); const QPalette &pal = QApplication::palette(); const QFont printFont = bodyFont(fixed, true /* print */); QString quoteCSS; if (printFont.italic()) { quoteCSS += QLatin1String(" font-style: italic ! important;\n"); } if (printFont.bold()) { quoteCSS += QLatin1String(" font-weight: bold ! important;\n"); } if (!quoteCSS.isEmpty()) { quoteCSS = QLatin1String("div.noquote {\n") + quoteCSS + QLatin1String("}\n\n"); } quoteCSS += quoteCssDefinition(); return QStringLiteral("body {\n" " font-family: \"%1\" ! important;\n" " font-size: %2pt ! important;\n" " color: #000000 ! important;\n" " background-color: #ffffff ! important\n" "}\n\n") .arg(printFont.family(), QString::number(printFont.pointSize())) + QStringLiteral("tr.textAtmH,\n" "tr.signInProgressH,\n" "tr.rfc822H,\n" "tr.encrH,\n" "tr.signOkKeyOkH,\n" "tr.signOkKeyBadH,\n" "tr.signWarnH,\n" "tr.signErrH,\n" "div.header {\n" "%1" "}\n\n" "div.fancy.header > div {\n" " background-color: %2 ! important;\n" " color: %3 ! important;\n" " padding: 4px ! important;\n" " border: solid %3 1px ! important;\n" " line-height: normal;\n" "}\n\n" "div.fancy.header > div a[href] { color: %3 ! important; }\n\n" "div.fancy.header > table.outer{\n" " background-color: %2 ! important;\n" " color: %3 ! important;\n" " border-bottom: solid %3 1px ! important;\n" " border-left: solid %3 1px ! important;\n" " border-right: solid %3 1px ! important;\n" "}\n\n" "div.spamheader {\n" " display:none ! important;\n" "}\n\n" "div.htmlWarn {\n" " border: 2px solid #ffffff ! important;\n" " line-height: normal;\n" "}\n\n" "div.senderpic{\n" " font-size:0.8em ! important;\n" " border:1px solid black ! important;\n" " background-color:%2 ! important;\n" "}\n\n" "div.senderstatus{\n" " text-align:center ! important;\n" "}\n\n" "div.noprint {\n" " display:none ! important;\n" "}\n\n" ) .arg(headerFont, pal.color(QPalette::Background).name(), pal.color(QPalette::Foreground).name()) + quoteCSS; } QString CSSHelperBase::quoteCssDefinition() const { QString quoteCSS; QString blockQuote; for (int i = 0; i < 9; ++i) { blockQuote += QLatin1String("blockquote "); quoteCSS += QString::fromLatin1("%2{\n" " margin: 4pt 0 4pt 0;\n" " padding: 0 0 0 1em;\n" " border-left: 2px solid %1;\n" " unicode-bidi: -webkit-plaintext\n" "}\n\n").arg(quoteColorName(i)).arg(blockQuote); } quoteCSS += QLatin1String(".quotemarks{\n" " color:transparent;\n" " font-size:0px;\n" "}\n\n"); return quoteCSS; } QString CSSHelperBase::screenCssDefinitions(const CSSHelperBase *helper, bool fixed) const { const QString fgColor = mForegroundColor.name(); const QString bgColor = mBackgroundColor.name(); const QString linkColor = mLinkColor.name(); const QString headerFont = QStringLiteral(" font-family: \"%1\" ! important;\n" " font-size: %2px ! important;\n") .arg(mBodyFont.family()) .arg(pointsToPixel(helper->mPaintDevice, mBodyFont.pointSize())); const QString background = QStringLiteral(" background-color: %1 ! important;\n").arg(bgColor); const QString bodyFontSize = QString::number(pointsToPixel(helper->mPaintDevice, fontSize(fixed))) + QLatin1String("px"); const QPalette &pal = QApplication::palette(); QString quoteCSS; if (bodyFont(fixed).italic()) { quoteCSS += QLatin1String(" font-style: italic ! important;\n"); } if (bodyFont(fixed).bold()) { quoteCSS += QLatin1String(" font-weight: bold ! important;\n"); } if (!quoteCSS.isEmpty()) { quoteCSS = QLatin1String("div.noquote {\n") + quoteCSS + QLatin1String("}\n\n"); } // CSS definitions for quote levels 1-3 for (int i = 0; i < 3; ++i) { quoteCSS += QStringLiteral("div.quotelevel%1 {\n" " color: %2 ! important;\n") .arg(QString::number(i + 1), quoteColorName(i)); if (mQuoteFont[i].italic()) { quoteCSS += QLatin1String(" font-style: italic ! important;\n"); } if (mQuoteFont[i].bold()) { quoteCSS += QLatin1String(" font-weight: bold ! important;\n"); } if (mShrinkQuotes) quoteCSS += QLatin1String(" font-size: ") + QString::fromLatin1(quoteFontSizes[i]) + QLatin1String("% ! important;\n"); quoteCSS += QLatin1String("}\n\n"); } // CSS definitions for quote levels 4+ for (int i = 0; i < 3; ++i) { quoteCSS += QStringLiteral("div.deepquotelevel%1 {\n" " color: %2 ! important;\n") .arg(QString::number(i + 1), quoteColorName(i)); if (mQuoteFont[i].italic()) { quoteCSS += QLatin1String(" font-style: italic ! important;\n"); } if (mQuoteFont[i].bold()) { quoteCSS += QLatin1String(" font-weight: bold ! important;\n"); } if (mShrinkQuotes) { quoteCSS += QLatin1String(" font-size: 70% ! important;\n"); } quoteCSS += QLatin1String("}\n\n"); } quoteCSS += quoteCssDefinition(); return QStringLiteral("body {\n" " font-family: \"%1\" ! important;\n" " font-size: %2 ! important;\n" " color: %3 ! important;\n" "%4" "}\n\n") .arg(bodyFont(fixed).family(), bodyFontSize, fgColor, background) + /* This shouldn't be necessary because font properties are inherited automatically and causes wrong font settings with QTextBrowser because it doesn't understand the inherit statement QString::fromLatin1( "table {\n" " font-family: inherit ! important;\n" " font-size: inherit ! important;\n" " font-weight: inherit ! important;\n" "}\n\n" ) + */ QStringLiteral("a {\n" " color: %1 ! important;\n" " text-decoration: none ! important;\n" "}\n\n" "a.white {\n" " color: white ! important;\n" "}\n\n" "a.black {\n" " color: black ! important;\n" "}\n\n" "table.textAtm { background-color: %2 ! important; }\n\n" "tr.textAtmH {\n" " background-color: %3 ! important;\n" "%4" "}\n\n" "tr.textAtmB {\n" " background-color: %3 ! important;\n" "}\n\n" "table.signInProgress,\n" "table.rfc822 {\n" " background-color: %3 ! important;\n" "}\n\n" "tr.signInProgressH,\n" "tr.rfc822H {\n" "%4" "}\n\n") .arg(linkColor, fgColor, bgColor, headerFont) + QStringLiteral("table.encr {\n" " background-color: %1 ! important;\n" "}\n\n" "tr.encrH {\n" " background-color: %2 ! important;\n" " color: %3 ! important;\n" "%4" "}\n\n" "tr.encrB { background-color: %5 ! important; }\n\n") .arg(cPgpEncrF.name(), cPgpEncrH.name(), cPgpEncrHT.name(), headerFont, cPgpEncrB.name()) + QStringLiteral("table.signOkKeyOk {\n" " background-color: %1 ! important;\n" "}\n\n" "tr.signOkKeyOkH {\n" " background-color: %2 ! important;\n" " color: %3 ! important;\n" "%4" "}\n\n" "tr.signOkKeyOkB { background-color: %5 ! important; }\n\n") .arg(cPgpOk1F.name(), cPgpOk1H.name(), cPgpOk1HT.name(), headerFont, cPgpOk1B.name()) + QStringLiteral("table.signOkKeyBad {\n" " background-color: %1 ! important;\n" "}\n\n" "tr.signOkKeyBadH {\n" " background-color: %2 ! important;\n" " color: %3 ! important;\n" "%4" "}\n\n" "tr.signOkKeyBadB { background-color: %5 ! important; }\n\n") .arg(cPgpOk0F.name(), cPgpOk0H.name(), cPgpOk0HT.name(), headerFont, cPgpOk0B.name()) + QStringLiteral("table.signWarn {\n" " background-color: %1 ! important;\n" "}\n\n" "tr.signWarnH {\n" " background-color: %2 ! important;\n" " color: %3 ! important;\n" "%4" "}\n\n" "tr.signWarnB { background-color: %5 ! important; }\n\n") .arg(cPgpWarnF.name(), cPgpWarnH.name(), cPgpWarnHT.name(), headerFont, cPgpWarnB.name()) + QStringLiteral("table.signErr {\n" " background-color: %1 ! important;\n" "}\n\n" "tr.signErrH {\n" " background-color: %2 ! important;\n" " color: %3 ! important;\n" "%4" "}\n\n" "tr.signErrB { background-color: %5 ! important; }\n\n") .arg(cPgpErrF.name(), cPgpErrH.name(), cPgpErrHT.name(), headerFont, cPgpErrB.name()) + QStringLiteral("div.htmlWarn {\n" " border: 2px solid %1 ! important;\n" " line-height: normal;\n" "}\n\n") .arg(cHtmlWarning.name()) + QStringLiteral("div.header {\n" "%1" "}\n\n" "div.fancy.header > div {\n" " background-color: %2 ! important;\n" " color: %3 ! important;\n" " border: solid %4 1px ! important;\n" " line-height: normal;\n" "}\n\n" "div.fancy.header > div a[href] { color: %3 ! important; }\n\n" "div.fancy.header > div a[href]:hover { text-decoration: underline ! important; }\n\n" "div.fancy.header > div.spamheader {\n" " background-color: #cdcdcd ! important;\n" " border-top: 0px ! important;\n" " padding: 3px ! important;\n" " color: black ! important;\n" " font-weight: bold ! important;\n" " font-size: smaller ! important;\n" "}\n\n" "div.fancy.header > table.outer {\n" " background-color: %5 ! important;\n" " color: %4 ! important;\n" " border-bottom: solid %4 1px ! important;\n" " border-left: solid %4 1px ! important;\n" " border-right: solid %4 1px ! important;\n" "}\n\n" "div.senderpic{\n" " padding: 0px ! important;\n" " font-size:0.8em ! important;\n" " border:1px solid %6 ! important;\n" // FIXME: InfoBackground crashes KHTML //" background-color:InfoBackground ! important;\n" " background-color:%5 ! important;\n" "}\n\n" "div.senderstatus{\n" " text-align:center ! important;\n" "}\n\n" ) .arg(headerFont) .arg(pal.color(QPalette::Highlight).name(), pal.color(QPalette::HighlightedText).name(), pal.color(QPalette::Foreground).name(), pal.color(QPalette::Background).name()) .arg(pal.color(QPalette::Mid).name()) + quoteCSS; } QString CSSHelperBase::commonCssDefinitions() const { const QPalette &pal = QApplication::palette(); const QString headerFont = QStringLiteral("font-family: \"%1\" ! important;\n" " font-size: %2px ! important;\n") .arg(mBodyFont.family()) .arg(pointsToPixel(this->mPaintDevice, mBodyFont.pointSize())); return QStringLiteral("div.header {\n" " margin-bottom: 10pt ! important;\n" "}\n\n" "table.textAtm {\n" " margin-top: 10pt ! important;\n" " margin-bottom: 10pt ! important;\n" "}\n\n" "tr.textAtmH,\n" "tr.textAtmB,\n" "tr.rfc822B {\n" " font-weight: normal ! important;\n" "}\n\n" "tr.signInProgressH,\n" "tr.rfc822H,\n" "tr.encrH,\n" "tr.signOkKeyOkH,\n" "tr.signOkKeyBadH,\n" "tr.signWarnH,\n" "tr.signErrH {\n" " font-weight: bold ! important;\n" "}\n\n" "tr.textAtmH td,\n" "tr.textAtmB td {\n" " padding: 3px ! important;\n" "}\n\n" "table.rfc822 {\n" " width: 100% ! important;\n" " border: solid 1px black ! important;\n" " margin-top: 10pt ! important;\n" " margin-bottom: 10pt ! important;\n" "}\n\n" "table.textAtm,\n" "table.encr,\n" "table.signWarn,\n" "table.signErr,\n" "table.signOkKeyBad,\n" "table.signOkKeyOk,\n" "table.signInProgress,\n" "div.fancy.header table {\n" " width: 100% ! important;\n" " border-width: 0px ! important;\n" " line-height: normal;\n" "}\n\n" "div.htmlWarn {\n" " margin: 0px 5% ! important;\n" " padding: 10px ! important;\n" " text-align: left ! important;\n" " line-height: normal;\n" "}\n\n" "div.fancy.header > div {\n" " font-weight: bold ! important;\n" " padding: 4px ! important;\n" " line-height: normal;\n" "}\n\n" "div.fancy.header table {\n" " padding: 2px ! important;\n" // ### khtml bug: this is ignored " text-align: left ! important;\n" " border-collapse: separate ! important;\n" "}\n\n" "div.fancy.header table th {\n" " %3\n" " padding: 0px ! important;\n" " white-space: nowrap ! important;\n" " border-spacing: 0px ! important;\n" " text-align: left ! important;\n" " vertical-align: top ! important;\n" " background-color: %1 ! important;\n" " color: %2 ! important;\n" " border: 1px ! important;\n" "}\n\n" "div.fancy.header table td {\n" " %3\n" " padding: 0px ! important;\n" " border-spacing: 0px ! important;\n" " text-align: left ! important;\n" " vertical-align: top ! important;\n" " width: 100% ! important;\n" " background-color: %1 ! important;\n" " color: %2 ! important;\n" " border: 1px ! important;\n" "}\n\n" "div.fancy.header table a:hover {\n" " background-color: transparent ! important;\n" "}\n\n" "span.pimsmileytext {\n" " position: absolute;\n" " top: 0px;\n" " left: 0px;\n" " visibility: hidden;\n" "}\n\n" "img.pimsmileyimg {\n" "}\n\n" "div.quotelevelmark {\n" " position: absolute;\n" " margin-left:-10px;\n" "}\n\n").arg(pal.color(QPalette::Background).name()).arg(pal.color(QPalette::Foreground).name()).arg(headerFont) ; } void CSSHelperBase::setBodyFont(const QFont &font) { mBodyFont = font; } void CSSHelperBase::setPrintFont(const QFont &font) { mPrintFont = font; } QString CSSHelperBase::quoteColorName(int level) const { return quoteColor(level).name(); } QColor CSSHelperBase::quoteColor(int level) const { const int actualLevel = qMax(level, 0) % 3; return mQuoteColor[actualLevel]; } QColor CSSHelperBase::pgpWarnColor() const { return cPgpWarnH; } } diff --git a/mimetreeparser/src/viewer/csshelperbase.h b/messageviewer/src/viewer/csshelperbase.h similarity index 97% rename from mimetreeparser/src/viewer/csshelperbase.h rename to messageviewer/src/viewer/csshelperbase.h index 27e24730..6a88e26d 100644 --- a/mimetreeparser/src/viewer/csshelperbase.h +++ b/messageviewer/src/viewer/csshelperbase.h @@ -1,141 +1,141 @@ /* -*- c++ -*- csshelper.h This file is part of KMail, the KDE mail client. Copyright (c) 2003 Marc Mutz KMail is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation. KMail 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __MIMETREEPARSER_CSSHELPERBASE_H__ #define __MIMETREEPARSER_CSSHELPERBASE_H__ -#include "mimetreeparser_export.h" +#include "messageviewer_export.h" #include #include class QString; class QPaintDevice; -namespace MimeTreeParser +namespace MessageViewer { -class MIMETREEPARSER_EXPORT CSSHelperBase +class MESSAGEVIEWER_EXPORT CSSHelperBase { public: /** Construct a CSSHelper object and set its font and color settings to default values. Sub-Classes should put their config loading here. */ explicit CSSHelperBase(const QPaintDevice *pd); virtual ~CSSHelperBase(); /** @return HTML head including style sheet definitions and the >body< tag */ virtual QString htmlHead(bool fixedFont = false) const; /** @return The collected CSS definitions as a string */ QString cssDefinitions(bool fixedFont = false) const; /** @return a <div> start tag with embedded style information suitable for quoted text with quote level @p level */ QString quoteFontTag(int level) const; /** @return a <div> start tag with embedded style information suitable for non-quoted text */ QString nonQuotedFontTag() const; QFont bodyFont(bool fixedFont = false, bool printing = false) const; void setBodyFont(const QFont &font); void setPrintFont(const QFont &font); /** @return the quote color for the given level, where level ranges from 0 to 2 **/ QColor quoteColor(int level) const; QString quoteColorName(int level) const; QColor pgpWarnColor() const; QString addEndBlockQuote(int numberBlock) const; QString addStartBlockQuote(int numberBlock) const; protected: /** Recalculate PGP frame and body colors (should be called after changing color settings) */ void recalculatePGPColors(); protected: QFont mBodyFont; QFont mPrintFont; QFont mFixedFont; QFont mFixedPrintFont; QFont mQuoteFont[3]; QColor mQuoteColor[3]; bool mRecycleQuoteColors; bool mShrinkQuotes; QColor mForegroundColor; QColor mLinkColor; QColor mBackgroundColor; // colors for PGP (Frame, Header, HeaderText, Body) QColor cPgpOk1F; QColor cPgpOk1H; QColor cPgpOk1HT; QColor cPgpOk1B; QColor cPgpOk0F; QColor cPgpOk0H; QColor cPgpOk0HT; QColor cPgpOk0B; QColor cPgpWarnF; QColor cPgpWarnH; QColor cPgpWarnHT; QColor cPgpWarnB; QColor cPgpErrF; QColor cPgpErrH; QColor cPgpErrHT; QColor cPgpErrB; QColor cPgpEncrF; QColor cPgpEncrH; QColor cPgpEncrHT; QColor cPgpEncrB; // color of frame of warning preceding the source of HTML messages QColor cHtmlWarning; private: QString quoteCssDefinition() const; int fontSize(bool fixed, bool print = false) const; // returns CSS rules specific to the print media type QString printCssDefinitions(bool fixed) const; // returns CSS rules specific to the screen media type QString screenCssDefinitions(const CSSHelperBase *helper, bool fixed) const; // returns CSS rules common to both screen and print media types QString commonCssDefinitions() const; private: const QPaintDevice *mPaintDevice; }; } #endif diff --git a/messageviewer/src/viewer/objecttreeemptysource.cpp b/messageviewer/src/viewer/objecttreeemptysource.cpp index 16f243dd..a2c08dab 100644 --- a/messageviewer/src/viewer/objecttreeemptysource.cpp +++ b/messageviewer/src/viewer/objecttreeemptysource.cpp @@ -1,149 +1,150 @@ /* Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net Copyright (c) 2009 Andras Mantia This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "objecttreeemptysource.h" #include "viewer/viewer_p.h" +#include "viewer/csshelperbase.h" #include #include #include "messagepartthemes/default/defaultrenderer.h" #include "bodypartformatterfactorysingleton.h" using namespace MessageViewer; namespace MessageViewer { class EmptySourcePrivate { public: EmptySourcePrivate() : mAllowDecryption(false) { } bool mAllowDecryption; }; } EmptySource::EmptySource() : MimeTreeParser::Interface::ObjectTreeSource(), d(new MessageViewer::EmptySourcePrivate) { } EmptySource::~EmptySource() { delete d; } bool EmptySource::htmlMail() const { return true; } bool EmptySource::decryptMessage() const { return d->mAllowDecryption; } bool EmptySource::htmlLoadExternal() const { return false; } bool EmptySource::showSignatureDetails() const { return false; } void EmptySource::setHtmlMode(MimeTreeParser::Util::HtmlMode mode) { Q_UNUSED(mode); } void EmptySource::setAllowDecryption(bool allowDecryption) { d->mAllowDecryption = allowDecryption; } int EmptySource::levelQuote() const { return 1; } const QTextCodec *EmptySource::overrideCodec() { return 0; } QString EmptySource::createMessageHeader(KMime::Message *message) { Q_UNUSED(message); return QString(); //do nothing } QObject *EmptySource::sourceObject() { return 0; } const MimeTreeParser::AttachmentStrategy *EmptySource::attachmentStrategy() { return MimeTreeParser::AttachmentStrategy::smart(); } MimeTreeParser::HtmlWriter *EmptySource::htmlWriter() { return 0; } -MimeTreeParser::CSSHelperBase *EmptySource::cssHelper() +CSSHelperBase *EmptySource::cssHelper() { return 0; } bool EmptySource::autoImportKeys() const { return true; } bool EmptySource::showEmoticons() const { return false; } bool EmptySource::showExpandQuotesMark() const { return false; } const MimeTreeParser::BodyPartFormatterBaseFactory *EmptySource::bodyPartFormatterFactory() { return bodyPartFormatterBaseFactoryInstance(); } MimeTreeParser::Interface::MessagePartRendererPtr EmptySource::messagePartTheme(MimeTreeParser::Interface::MessagePart::Ptr msgPart) { - return MimeTreeParser::Interface::MessagePartRenderer::Ptr(new DefaultRenderer(msgPart)); + return MimeTreeParser::Interface::MessagePartRenderer::Ptr(new DefaultRenderer(msgPart, cssHelper())); } diff --git a/messageviewer/src/viewer/objecttreeemptysource.h b/messageviewer/src/viewer/objecttreeemptysource.h index be1e47f3..4cd4d5d3 100644 --- a/messageviewer/src/viewer/objecttreeemptysource.h +++ b/messageviewer/src/viewer/objecttreeemptysource.h @@ -1,63 +1,64 @@ /* Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net Copyright (c) 2009 Andras Mantia This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef MAILVIEWER_OBJECTTREEEMPTYSOURCE_H #define MAILVIEWER_OBJECTTREEEMPTYSOURCE_H #include #include "messageviewer_export.h" class QString; namespace MessageViewer { +class CSSHelperBase; /** An ObjectTreeSource that does not work on anything */ class EmptySourcePrivate; class MESSAGEVIEWER_EXPORT EmptySource : public MimeTreeParser::Interface::ObjectTreeSource { public: EmptySource(); ~EmptySource(); bool htmlMail() const Q_DECL_OVERRIDE; bool decryptMessage() const Q_DECL_OVERRIDE; bool htmlLoadExternal() const Q_DECL_OVERRIDE; bool showSignatureDetails() const Q_DECL_OVERRIDE; void setHtmlMode(MimeTreeParser::Util::HtmlMode mode) Q_DECL_OVERRIDE; void setAllowDecryption(bool allowDecryption); int levelQuote() const Q_DECL_OVERRIDE; const QTextCodec *overrideCodec() Q_DECL_OVERRIDE; QString createMessageHeader(KMime::Message *message) Q_DECL_OVERRIDE; const MimeTreeParser::AttachmentStrategy *attachmentStrategy() Q_DECL_OVERRIDE; MimeTreeParser::HtmlWriter *htmlWriter() Q_DECL_OVERRIDE; - MimeTreeParser::CSSHelperBase *cssHelper() Q_DECL_OVERRIDE; + virtual CSSHelperBase *cssHelper(); QObject *sourceObject() Q_DECL_OVERRIDE; bool autoImportKeys() const Q_DECL_OVERRIDE; bool showEmoticons() const Q_DECL_OVERRIDE; bool showExpandQuotesMark() const Q_DECL_OVERRIDE; const MimeTreeParser::BodyPartFormatterBaseFactory *bodyPartFormatterFactory() Q_DECL_OVERRIDE; MimeTreeParser::Interface::MessagePartRendererPtr messagePartTheme(MimeTreeParser::Interface::MessagePartPtr msgPart) Q_DECL_OVERRIDE; private: EmptySourcePrivate *const d; }; } #endif diff --git a/messageviewer/src/viewer/objecttreeviewersource.cpp b/messageviewer/src/viewer/objecttreeviewersource.cpp index 26b4ce9d..8861d858 100644 --- a/messageviewer/src/viewer/objecttreeviewersource.cpp +++ b/messageviewer/src/viewer/objecttreeviewersource.cpp @@ -1,125 +1,120 @@ /* Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net Copyright (c) 2009 Andras Mantia This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "objecttreeviewersource.h" #include "csshelper.h" #include "bodypartformatterfactorysingleton.h" #include #include "messagepartthemes/default/defaultrenderer.h" #include "viewer/viewer_p.h" #include "widgets/htmlstatusbar.h" #include "settings/messageviewersettings.h" using namespace MessageViewer; MailViewerSource::MailViewerSource(ViewerPrivate *viewer) : MimeTreeParser::Interface::ObjectTreeSource(), mViewer(viewer) { } MailViewerSource::~MailViewerSource() { } bool MailViewerSource::htmlMail() const { return mViewer->htmlMail(); } bool MailViewerSource::decryptMessage() const { return mViewer->decryptMessage(); } bool MailViewerSource::htmlLoadExternal() const { return mViewer->htmlLoadExternal(); } bool MailViewerSource::showSignatureDetails() const { return mViewer->mShowSignatureDetails; } void MailViewerSource::setHtmlMode(MimeTreeParser::Util::HtmlMode mode) { mViewer->mColorBar->setMode(mode); } int MailViewerSource::levelQuote() const { return mViewer->mLevelQuote; } const QTextCodec *MailViewerSource::overrideCodec() { return mViewer->overrideCodec(); } QString MailViewerSource::createMessageHeader(KMime::Message *message) { return mViewer->writeMsgHeader(message); } QObject *MailViewerSource::sourceObject() { return mViewer; } const MimeTreeParser::AttachmentStrategy *MailViewerSource::attachmentStrategy() { return mViewer->attachmentStrategy(); } MimeTreeParser::HtmlWriter *MailViewerSource::htmlWriter() { return mViewer->htmlWriter(); } -MimeTreeParser::CSSHelperBase *MailViewerSource::cssHelper() -{ - return mViewer->cssHelper(); -} - bool MailViewerSource::autoImportKeys() const { return MessageViewer::MessageViewerSettings::self()->autoImportKeys(); } bool MailViewerSource::showEmoticons() const { return MessageViewer::MessageViewerSettings::self()->showEmoticons(); } bool MailViewerSource::showExpandQuotesMark() const { return MessageViewer::MessageViewerSettings::self()->showExpandQuotesMark(); } const MimeTreeParser::BodyPartFormatterBaseFactory *MailViewerSource::bodyPartFormatterFactory() { return bodyPartFormatterBaseFactoryInstance(); } MimeTreeParser::Interface::MessagePartRendererPtr MailViewerSource::messagePartTheme(MimeTreeParser::Interface::MessagePart::Ptr msgPart) { - return MimeTreeParser::Interface::MessagePartRenderer::Ptr(new DefaultRenderer(msgPart)); + return MimeTreeParser::Interface::MessagePartRenderer::Ptr(new DefaultRenderer(msgPart, mViewer->cssHelper())); } \ No newline at end of file diff --git a/messageviewer/src/viewer/objecttreeviewersource.h b/messageviewer/src/viewer/objecttreeviewersource.h index b1cc6b20..6b0b3405 100644 --- a/messageviewer/src/viewer/objecttreeviewersource.h +++ b/messageviewer/src/viewer/objecttreeviewersource.h @@ -1,63 +1,62 @@ /* Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net Copyright (c) 2009 Andras Mantia This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef MAILVIEWER_OBJECTTREEVIEWERSOURCE_H #define MAILVIEWER_OBJECTTREEVIEWERSOURCE_H #include class QString; namespace MessageViewer { class ViewerPrivate; /** An ObjectTreeParser source working on a MailViewer object */ class MailViewerSource : public MimeTreeParser::Interface::ObjectTreeSource { public: explicit MailViewerSource(ViewerPrivate *viewer); ~MailViewerSource(); bool htmlMail() const Q_DECL_OVERRIDE; bool decryptMessage() const Q_DECL_OVERRIDE; bool htmlLoadExternal() const Q_DECL_OVERRIDE; bool showSignatureDetails() const Q_DECL_OVERRIDE; void setHtmlMode(MimeTreeParser::Util::HtmlMode mode) Q_DECL_OVERRIDE; int levelQuote() const Q_DECL_OVERRIDE; const QTextCodec *overrideCodec() Q_DECL_OVERRIDE; QString createMessageHeader(KMime::Message *message) Q_DECL_OVERRIDE; const MimeTreeParser::AttachmentStrategy *attachmentStrategy() Q_DECL_OVERRIDE; MimeTreeParser::HtmlWriter *htmlWriter() Q_DECL_OVERRIDE; - MimeTreeParser::CSSHelperBase *cssHelper() Q_DECL_OVERRIDE; QObject *sourceObject() Q_DECL_OVERRIDE; bool autoImportKeys() const Q_DECL_OVERRIDE; bool showEmoticons() const Q_DECL_OVERRIDE; bool showExpandQuotesMark() const Q_DECL_OVERRIDE; const MimeTreeParser::BodyPartFormatterBaseFactory *bodyPartFormatterFactory() Q_DECL_OVERRIDE; MimeTreeParser::Interface::MessagePartRendererPtr messagePartTheme(MimeTreeParser::Interface::MessagePartPtr msgPart) Q_DECL_OVERRIDE; private: ViewerPrivate *mViewer; }; } #endif diff --git a/mimetreeparser/autotests/CMakeLists.txt b/mimetreeparser/autotests/CMakeLists.txt index 39537694..71372bbe 100644 --- a/mimetreeparser/autotests/CMakeLists.txt +++ b/mimetreeparser/autotests/CMakeLists.txt @@ -1,42 +1,40 @@ set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) add_definitions( -DMAIL_DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data" ) include(${CMAKE_SOURCE_DIR}/cmake/modules/kdepim_add_gpg_crypto_test.cmake) # convenience macro to add qtest unit tests macro(add_mimetreeparser_unittest _source) get_filename_component(_name ${_source} NAME_WE) - ecm_add_test(${_source} util.cpp setupenv.cpp testcsshelper.cpp + ecm_add_test(${_source} util.cpp setupenv.cpp TEST_NAME ${_name} NAME_PREFIX "mimetreeparser-" - LINK_LIBRARIES KF5::MimeTreeParser Qt5::Test KF5::IconThemes KF5::Mime + LINK_LIBRARIES KF5::MimeTreeParser Qt5::Test KF5::Mime ) endmacro () macro(add_mimetreeparser_class_unittest _source _additionalSource) get_filename_component(_name ${_source} NAME_WE) ecm_add_test(${_source} ${_additionalSource} TEST_NAME ${_name} NAME_PREFIX "mimetreeparser-" - LINK_LIBRARIES KF5::MimeTreeParser KF5::MessageCore Qt5::Test KF5::IconThemes KF5::Codecs KF5::I18n KF5::CoreAddons KF5::Mime Grantlee5::TextDocument Grantlee5::Templates + LINK_LIBRARIES KF5::MimeTreeParser Qt5::Test KF5::Mime ) endmacro () macro(add_mimetreeparser_crypto_unittest _source) set(_test ${_source} util.cpp) get_filename_component(_name ${_source} NAME_WE) - add_executable( ${_name} ${_test} setupenv.cpp testcsshelper.cpp ) + add_executable( ${_name} ${_test} setupenv.cpp) ecm_mark_as_test(mimetreeparser-${_name}) target_link_libraries( ${_name} KF5::MimeTreeParser Qt5::Test - KF5::IconThemes KF5::Mime ) add_gpg_crypto_test(${_name} mimetreeparser-${_name}) endmacro () add_mimetreeparser_crypto_unittest(attachmenttest.cpp) add_mimetreeparser_unittest(nodehelpertest.cpp) -add_mimetreeparser_unittest(csshelpertest.cpp) add_mimetreeparser_class_unittest( cryptohelpertest.cpp "../src/viewer/cryptohelper.cpp") \ No newline at end of file diff --git a/mimetreeparser/autotests/attachmenttest.cpp b/mimetreeparser/autotests/attachmenttest.cpp index 73d45045..48f401cd 100644 --- a/mimetreeparser/autotests/attachmenttest.cpp +++ b/mimetreeparser/autotests/attachmenttest.cpp @@ -1,68 +1,68 @@ /* Copyright (c) 2015 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 "viewer/objecttreeparser.h" #include "util.h" #include "setupenv.h" #include using namespace MimeTreeParser; class AttachmentTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void testEncryptedAttachment_data(); void testEncryptedAttachment(); }; QTEST_MAIN(AttachmentTest) void AttachmentTest::initTestCase() { MimeTreeParser::Test::setupEnv(); } void AttachmentTest::testEncryptedAttachment_data() { QTest::addColumn("mbox"); QTest::newRow("encrypted") << "openpgp-encrypted-two-attachments.mbox"; QTest::newRow("signed") << "openpgp-signed-two-attachments.mbox"; QTest::newRow("signed+encrypted") << "openpgp-signed-encrypted-two-attachments.mbox"; QTest::newRow("encrypted+partial signed") << "openpgp-encrypted-partially-signed-attachments.mbox"; } void AttachmentTest::testEncryptedAttachment() { QFETCH(QString, mbox); auto msg = readAndParseMail(mbox); NodeHelper nodeHelper; - Test::TestObjectTreeSource testSource(Q_NULLPTR, Q_NULLPTR); + Test::TestObjectTreeSource testSource(Q_NULLPTR); testSource.setAllowDecryption(true); ObjectTreeParser otp(&testSource, &nodeHelper); otp.parseObjectTree(msg.data()); auto attachments = msg->attachments(); auto encAtts = nodeHelper.attachmentsOfExtraContents(); QCOMPARE(attachments.size() + encAtts.size(), 2); } #include "attachmenttest.moc" diff --git a/mimetreeparser/autotests/csshelpertest.cpp b/mimetreeparser/autotests/csshelpertest.cpp deleted file mode 100644 index 08938889..00000000 --- a/mimetreeparser/autotests/csshelpertest.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - 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 "csshelpertest.h" -#include "testcsshelper.h" - -#include - -using namespace MimeTreeParser; - -QTEST_APPLESS_MAIN(CSSHelperTest) - -void CSSHelperTest::testCssDefinition() -{ - // load css header - QFile cssFile(QStringLiteral(MAIL_DATA_DIR) + QStringLiteral("/mailheader.css")); - QVERIFY(cssFile.open(QIODevice::ReadOnly)); - - QImage paintDevice; - TestCSSHelper cssHelper(&paintDevice); - - QCOMPARE(cssHelper.cssDefinitions(false).trimmed(), QString::fromUtf8(cssFile.readAll().trimmed())); -} diff --git a/mimetreeparser/autotests/csshelpertest.h b/mimetreeparser/autotests/csshelpertest.h deleted file mode 100644 index 10b80527..00000000 --- a/mimetreeparser/autotests/csshelpertest.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - 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. -*/ - -#ifndef CSSHELPERTEST_H -#define CSSHELPERTEST_H - -#include - -class CSSHelperTest : public QObject -{ - Q_OBJECT - -private Q_SLOTS: - void testCssDefinition(); -}; - -#endif \ No newline at end of file diff --git a/mimetreeparser/autotests/setupenv.h b/mimetreeparser/autotests/setupenv.h index 72e59aeb..f8a1c216 100644 --- a/mimetreeparser/autotests/setupenv.h +++ b/mimetreeparser/autotests/setupenv.h @@ -1,176 +1,170 @@ /* Copyright (C) 2010 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com Copyright (c) 2010 Leo Franchi 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. */ #ifndef MESSAGECORE_TESTS_UTIL_H #define MESSAGECORE_TESTS_UTIL_H #include #include #include #include #include #include namespace MimeTreeParser { namespace Test { /** * setup a environment variables for tests: * * set LC_ALL to C * * set KDEHOME */ void setupEnv(); // We can't use EmptySource, since we need to control some emelnets of the source for tests to also test // loadExternal and htmlMail. class TestObjectTreeSource : public MimeTreeParser::Interface::ObjectTreeSource { public: - TestObjectTreeSource(MimeTreeParser::HtmlWriter *writer, - MimeTreeParser::CSSHelperBase *cssHelper) + TestObjectTreeSource(MimeTreeParser::HtmlWriter *writer) : mWriter(writer) - , mCSSHelper(cssHelper) , mAttachmentStrategy(QStringLiteral("smart")) , mHtmlLoadExternal(false) , mHtmlMail(true) , mDecryptMessage(false) { } MimeTreeParser::HtmlWriter *htmlWriter() Q_DECL_OVERRIDE { return mWriter; } - MimeTreeParser::CSSHelperBase *cssHelper() Q_DECL_OVERRIDE { - return mCSSHelper; - } bool htmlLoadExternal() const Q_DECL_OVERRIDE { return mHtmlLoadExternal; } void setHtmlLoadExternal(bool loadExternal) { mHtmlLoadExternal = loadExternal; } bool htmlMail() const Q_DECL_OVERRIDE { return mHtmlMail; } void setHtmlMail(bool htmlMail) { mHtmlMail = htmlMail; } void setAttachmentStrategy(QString strategy) { mAttachmentStrategy = strategy; } const AttachmentStrategy *attachmentStrategy() Q_DECL_OVERRIDE { return AttachmentStrategy::create(mAttachmentStrategy); } bool autoImportKeys() const Q_DECL_OVERRIDE { return true; } bool showEmoticons() const Q_DECL_OVERRIDE { return false; } bool showExpandQuotesMark() const Q_DECL_OVERRIDE { return false; } const BodyPartFormatterBaseFactory *bodyPartFormatterFactory() Q_DECL_OVERRIDE { return &mBodyPartFormatterBaseFactory; } bool decryptMessage() const Q_DECL_OVERRIDE { return mDecryptMessage; } void setAllowDecryption(bool allowDecryption) { mDecryptMessage = allowDecryption; } void setShowSignatureDetails(bool showSignatureDetails) { mShowSignatureDetails = showSignatureDetails; } bool showSignatureDetails() const Q_DECL_OVERRIDE { return mShowSignatureDetails; } void setHtmlMode(MimeTreeParser::Util::HtmlMode mode) Q_DECL_OVERRIDE { Q_UNUSED(mode); } int levelQuote() const Q_DECL_OVERRIDE { return 1; } const QTextCodec *overrideCodec() Q_DECL_OVERRIDE { return Q_NULLPTR; } QString createMessageHeader(KMime::Message *message) Q_DECL_OVERRIDE { Q_UNUSED(message); return QString(); //do nothing } QObject *sourceObject() Q_DECL_OVERRIDE { return Q_NULLPTR; } Interface::MessagePartRenderer::Ptr messagePartTheme(Interface::MessagePart::Ptr msgPart) Q_DECL_OVERRIDE { Q_UNUSED(msgPart); return Interface::MessagePartRenderer::Ptr(); } private: MimeTreeParser::HtmlWriter *mWriter; - MimeTreeParser::CSSHelperBase *mCSSHelper; QString mAttachmentStrategy; BodyPartFormatterBaseFactory mBodyPartFormatterBaseFactory; bool mHtmlLoadExternal; bool mHtmlMail; bool mDecryptMessage; bool mShowSignatureDetails; }; } } #endif diff --git a/mimetreeparser/autotests/util.h b/mimetreeparser/autotests/util.h index b321ce50..39fde69b 100644 --- a/mimetreeparser/autotests/util.h +++ b/mimetreeparser/autotests/util.h @@ -1,66 +1,43 @@ /* Copyright (c) 2010 Thomas McGuire 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 "interfaces/htmlwriter.h" -#include "viewer/csshelperbase.h" #include class TestHtmlWriter : public MimeTreeParser::HtmlWriter { public: explicit TestHtmlWriter() {} virtual ~TestHtmlWriter() {} void begin(const QString &) Q_DECL_OVERRIDE {} void write(const QString &) Q_DECL_OVERRIDE {} void end() Q_DECL_OVERRIDE {} void reset() Q_DECL_OVERRIDE {} void queue(const QString &str) Q_DECL_OVERRIDE { html.append(str); } void flush() Q_DECL_OVERRIDE {} void embedPart(const QByteArray &, const QString &) Q_DECL_OVERRIDE {} void extraHead(const QString &) Q_DECL_OVERRIDE {} QString html; }; -class TestCSSHelper : public MimeTreeParser::CSSHelperBase -{ -public: - TestCSSHelper() : MimeTreeParser::CSSHelperBase(0) - { - for (int i = 0; i < 3; ++i) { - mQuoteColor[i] = QColor(0x00, 0x80 - i * 0x10, 0x00); - } - } - virtual ~TestCSSHelper() {} - - QString nonQuotedFontTag() const - { - return QStringLiteral("<"); - } - - QString quoteFontTag(int) const - { - return QStringLiteral("<"); - } -}; - KMime::Message::Ptr readAndParseMail(const QString &mailFile); diff --git a/mimetreeparser/src/CMakeLists.txt b/mimetreeparser/src/CMakeLists.txt index 2dac844e..e96c6d92 100644 --- a/mimetreeparser/src/CMakeLists.txt +++ b/mimetreeparser/src/CMakeLists.txt @@ -1,179 +1,177 @@ add_definitions( -DQT_NO_CAST_FROM_ASCII ) add_definitions( -DQT_NO_CAST_TO_ASCII ) add_definitions(-DTRANSLATION_DOMAIN=\"libmimetreeparser\") # target_include_directories does not handle empty include paths include_directories(${GPGME_INCLUDES}) set(libmimetreeparser_main_SRCS bodyformatter/applicationpgpencrypted.cpp bodyformatter/applicationpkcs7mime.cpp bodyformatter/mailman.cpp bodyformatter/multipartalternative.cpp bodyformatter/multipartencrypted.cpp bodyformatter/multipartmixed.cpp bodyformatter/multipartsigned.cpp bodyformatter/textplain.cpp bodyformatter/texthtml.cpp bodyformatter/utils.cpp interfaces/bodypartformatter.cpp interfaces/objecttreesource.cpp interfaces/bodypart.cpp interfaces/htmlwriter.cpp interfaces/messagepartrenderer.cpp job/kleojobexecutor.cpp utils/util.cpp viewer/attachmentstrategy.cpp viewer/bodypartformatter.cpp viewer/bodypartformatterbasefactory.cpp viewer/cryptohelper.cpp - viewer/csshelperbase.cpp viewer/nodehelper.cpp viewer/objecttreeparser.cpp viewer/messagepart.cpp viewer/partnodebodypart.cpp viewer/memento/cryptobodypartmemento.cpp viewer/memento/decryptverifybodypartmemento.cpp viewer/memento/verifydetachedbodypartmemento.cpp viewer/memento/verifyopaquebodypartmemento.cpp ) set(libmimetreeparser_extra_SRCS #HTML Writer htmlwriter/filehtmlwriter.cpp htmlwriter/queuehtmlwriter.cpp ) set(mimetreeparser_temporaryfile_SRCS temporaryfile/attachmenttemporaryfilesdirs.cpp ) ecm_generate_headers(MimeTreeParser_Camelcaseviewer_HEADERS HEADER_NAMES AttachmentStrategy BodyPartFormatterBaseFactory - CSSHelperBase Enums MessagePart NodeHelper ObjectTreeParser PartMetaData PartNodeBodyPart REQUIRED_HEADERS MimeTreeParser_viewer_HEADERS PREFIX MimeTreeParser RELATIVE viewer ) ecm_generate_headers(MimeTreeParser_Camelcaseutils_HEADERS HEADER_NAMES Util REQUIRED_HEADERS MimeTreeParser_utils_HEADERS PREFIX MimeTreeParser RELATIVE utils ) ecm_generate_headers(MimeTreeParser_Camelcaseinterfaces_HEADERS HEADER_NAMES BodyPartFormatter BodyPart HtmlWriter MessagePartRenderer ObjectTreeSource REQUIRED_HEADERS MimeTreeParser_interfaces_HEADERS PREFIX MimeTreeParser RELATIVE interfaces ) ecm_generate_headers(MimeTreeParser_Camelcasehtmlwriter_HEADERS HEADER_NAMES FileHtmlWriter REQUIRED_HEADERS MimeTreeParser_htmlwriter_HEADERS PREFIX MimeTreeParser RELATIVE htmlwriter ) ecm_generate_headers(MimeTreeParser_Camelcasetemporaryfile_HEADERS HEADER_NAMES AttachmentTemporaryFilesDirs REQUIRED_HEADERS MimeTreeParser_temporaryfile_HEADERS PREFIX MimeTreeParser RELATIVE temporaryfile ) install(FILES ${MimeTreeParser_Camelcasehtmlwriter_HEADERS} ${MimeTreeParser_Camelcaseutils_HEADERS} ${MimeTreeParser_Camelcaseinterfaces_HEADERS} ${MimeTreeParser_Camelcaseviewer_HEADERS} ${MimeTreeParser_Camelcasetemporaryfile_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/MimeTreeParser COMPONENT Devel ) install(FILES ${MimeTreeParser_htmlwriter_HEADERS} ${MimeTreeParser_utils_HEADERS} ${MimeTreeParser_interfaces_HEADERS} ${MimeTreeParser_viewer_HEADERS} ${MimeTreeParser_temporaryfile_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/mimetreeparser_export.h ${CMAKE_CURRENT_BINARY_DIR}/mimetreeparser_debug.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/mimetreeparser COMPONENT Devel ) ecm_generate_pri_file(BASE_NAME MimeTreeParser LIB_NAME KF5MimeTreeParser DEPS "Libkleo" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/MimeTreeParser ) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR} ) set(libmimetreeparser_SRCS ${libmimetreeparser_main_SRCS} ${libmimetreeparser_extra_SRCS} ${mimetreeparser_temporaryfile_SRCS} ) FILE(GLOB themesfiles_default_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/themes/default/templates/*.html") install(FILES ${themesfiles_default_SRCS} DESTINATION ${DATA_INSTALL_DIR}/mimetreeparser/themes/default) ecm_qt_declare_logging_category(libmimetreeparser_SRCS HEADER mimetreeparser_debug.h IDENTIFIER MIMETREEPARSER_LOG CATEGORY_NAME log_mimetreeparser) add_library(KF5MimeTreeParser ${libmimetreeparser_SRCS} ) generate_export_header(KF5MimeTreeParser BASE_NAME mimetreeparser) add_library(KF5::MimeTreeParser ALIAS KF5MimeTreeParser) target_link_libraries(KF5MimeTreeParser PUBLIC KF5::Libkleo PRIVATE KF5::Codecs KF5::I18n KF5::Mime - Qt5::Widgets + Qt5::Gui ) install(TARGETS KF5MimeTreeParser EXPORT KF5MimeTreeParserTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS} ${LIBRARY_NAMELINK} ) set_target_properties(KF5MimeTreeParser PROPERTIES VERSION ${MIMETREEPARSER_VERSION_STRING} SOVERSION ${MIMETREEPARSER_SOVERSION} EXPORT_NAME MimeTreeParser ) target_include_directories(KF5MimeTreeParser INTERFACE "$") target_include_directories(KF5MimeTreeParser PUBLIC "$") diff --git a/mimetreeparser/src/interfaces/objecttreesource.h b/mimetreeparser/src/interfaces/objecttreesource.h index a96c3d9b..3c1b0a8d 100644 --- a/mimetreeparser/src/interfaces/objecttreesource.h +++ b/mimetreeparser/src/interfaces/objecttreesource.h @@ -1,113 +1,109 @@ /* Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net Copyright (c) 2009 Andras Mantia This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __MIMETREEPARSER_OBJECTTREESOURCE_IF_H__ #define __MIMETREEPARSER_OBJECTTREESOURCE_IF_H__ #include "mimetreeparser_export.h" #include #include #include class QTextCodec; namespace MimeTreeParser { class HtmlWriter; -class CSSHelperBase; class AttachmentStrategy; class BodyPartFormatterBaseFactory; namespace Interface { class MessagePart; typedef QSharedPointer MessagePartPtr; class MessagePartRenderer; typedef QSharedPointer MessagePartRendererPtr; } } namespace MimeTreeParser { namespace Interface { /** * Interface for object tree sources. * @author Andras Mantia */ class MIMETREEPARSER_EXPORT ObjectTreeSource { public: virtual ~ObjectTreeSource(); /** * Sets the type of mail that is currently displayed. Applications can display this * information to the user, for example KMail displays a HTML status bar. * Note: This is not called when the mode is "Normal". */ virtual void setHtmlMode(MimeTreeParser::Util::HtmlMode mode) = 0; /** Return true if the mail should be parsed as a html mail */ virtual bool htmlMail() const = 0; /** Return true if an encrypted mail should be decrypted */ virtual bool decryptMessage() const = 0; /** Return true if external sources should be loaded in a html mail */ virtual bool htmlLoadExternal() const = 0; /** Return true to include the signature details in the generated html */ virtual bool showSignatureDetails() const = 0; virtual int levelQuote() const = 0; /** The override codec that should be used for the mail */ virtual const QTextCodec *overrideCodec() = 0; virtual QString createMessageHeader(KMime::Message *message) = 0; /** Return the wanted attachment startegy */ virtual const AttachmentStrategy *attachmentStrategy() = 0; /** Return the html write object */ virtual HtmlWriter *htmlWriter() = 0; - /** Return the css helper object */ - virtual CSSHelperBase *cssHelper() = 0; - /** The source object behind the interface. */ virtual QObject *sourceObject() = 0; /** should keys be imported automatically **/ virtual bool autoImportKeys() const = 0; virtual bool showEmoticons() const = 0; virtual bool showExpandQuotesMark() const = 0; virtual const BodyPartFormatterBaseFactory *bodyPartFormatterFactory() = 0; virtual MessagePartRendererPtr messagePartTheme(MessagePartPtr msgPart) = 0; }; } } #endif diff --git a/mimetreeparser/src/viewer/messagepart.cpp b/mimetreeparser/src/viewer/messagepart.cpp index 593770c4..6ce04a63 100644 --- a/mimetreeparser/src/viewer/messagepart.cpp +++ b/mimetreeparser/src/viewer/messagepart.cpp @@ -1,1082 +1,1075 @@ /* Copyright (c) 2015 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 "messagepart.h" #include "mimetreeparser_debug.h" -#include "csshelperbase.h" #include "cryptohelper.h" #include "objecttreeparser.h" #include "interfaces/htmlwriter.h" #include "job/kleojobexecutor.h" #include "memento/decryptverifybodypartmemento.h" #include "memento/verifydetachedbodypartmemento.h" #include "memento/verifyopaquebodypartmemento.h" #include #include #include #include #include #include #include #include #include #include #include #include using namespace MimeTreeParser; //------MessagePart----------------------- MessagePart::MessagePart(ObjectTreeParser *otp, const QString &text) : mText(text) , mOtp(otp) , mSubOtp(Q_NULLPTR) , mAttachmentNode(Q_NULLPTR) , mRoot(false) { } MessagePart::~MessagePart() { if (mSubOtp) { delete mSubOtp; mSubOtp = Q_NULLPTR; } } PartMetaData *MessagePart::partMetaData() { return &mMetaData; } void MessagePart::setAttachmentFlag(KMime::Content *node) { mAttachmentNode = node; } bool MessagePart::isAttachment() const { return mAttachmentNode; } KMime::Content *MessagePart::attachmentNode() const { return mAttachmentNode; } void MessagePart::setIsRoot(bool root) { mRoot = root; } bool MessagePart::isRoot() const { return mRoot; } QString MessagePart::text() const { return mText; } void MessagePart::setText(const QString &text) { mText = text; } bool MessagePart::isHtml() const { return false; } bool MessagePart::isHidden() const { return false; } -CSSHelperBase *MessagePart::cssHelper() const -{ - Q_ASSERT(mOtp); - return mOtp->cssHelper(); -} - Interface::ObjectTreeSource *MessagePart::source() const { Q_ASSERT(mOtp); return mOtp->mSource; } HtmlWriter *MessagePart::htmlWriter() const { Q_ASSERT(mOtp); return mOtp->htmlWriter(); } void MessagePart::setHtmlWriter(HtmlWriter *htmlWriter) const { mOtp->mHtmlWriter = htmlWriter; } void MessagePart::parseInternal(KMime::Content *node, bool onlyOneMimePart) { mSubOtp = new ObjectTreeParser(mOtp, onlyOneMimePart); mSubOtp->setAllowAsync(mOtp->allowAsync()); auto subMessagePart = mSubOtp->parseObjectTreeInternal(node); mRoot = subMessagePart->isRoot(); foreach (auto part, subMessagePart->subParts()) { appendSubPart(part); } } QString MessagePart::renderInternalText() const { QString text; foreach (const auto &mp, subParts()) { text += mp->text(); } return text; } void MessagePart::copyContentFrom() const { foreach (const auto &mp, subParts()) { const auto m = mp.dynamicCast(); if (m) { m->copyContentFrom(); } } if (hasSubParts() && mSubOtp) { mOtp->copyContentFrom(mSubOtp); } } void MessagePart::fix() const { foreach (const auto &mp, subParts()) { const auto m = mp.dynamicCast(); if (m) { m->fix(); } } } void MessagePart::appendSubPart(const Interface::MessagePart::Ptr &messagePart) { messagePart->setParentPart(this); mBlocks.append(messagePart); } const QVector &MessagePart::subParts() const { return mBlocks; } bool MessagePart::hasSubParts() const { return !mBlocks.isEmpty(); } //-----MessagePartList---------------------- MessagePartList::MessagePartList(ObjectTreeParser *otp) : MessagePart(otp, QString()) { } MessagePartList::~MessagePartList() { } QString MessagePartList::text() const { return renderInternalText(); } QString MessagePartList::plaintextContent() const { return QString(); } QString MessagePartList::htmlContent() const { return QString(); } //-----TextMessageBlock---------------------- TextMessagePart::TextMessagePart(ObjectTreeParser *otp, KMime::Content *node, bool drawFrame, bool showLink, bool decryptMessage, IconType asIcon) : MessagePartList(otp) , mNode(node) , mDrawFrame(drawFrame) , mShowLink(showLink) , mDecryptMessage(decryptMessage) , mIsHidden(false) , mAsIcon(asIcon) { if (!mNode) { qCWarning(MIMETREEPARSER_LOG) << "not a valid node"; return; } mIsHidden = mOtp->nodeHelper()->isNodeDisplayedHidden(mNode); parseContent(); } TextMessagePart::~TextMessagePart() { } bool TextMessagePart::decryptMessage() const { return mDecryptMessage; } void TextMessagePart::parseContent() { const auto aCodec = mOtp->codecFor(mNode); const QString &fromAddress = NodeHelper::fromAsString(mNode); mSignatureState = KMMsgNotSigned; mEncryptionState = KMMsgNotEncrypted; const auto blocks = prepareMessageForDecryption(mNode->decodedContent()); const auto cryptProto = Kleo::CryptoBackendFactory::instance()->openpgp(); if (!blocks.isEmpty()) { /* The (overall) signature/encrypted status is broken * if one unencrypted part is at the beginning or in the middle * because mailmain adds an unencrypted part at the end this should not break the overall status * * That's why we first set the tmp status and if one crypted/signed block comes afterwards, than * the status is set to unencryped */ bool fullySignedOrEncrypted = true; bool fullySignedOrEncryptedTmp = true; Q_FOREACH (const auto &block, blocks) { if (!fullySignedOrEncryptedTmp) { fullySignedOrEncrypted = false; } if (block.type() == NoPgpBlock && !block.text().trimmed().isEmpty()) { fullySignedOrEncryptedTmp = false; appendSubPart(MessagePart::Ptr(new MessagePart(mOtp, aCodec->toUnicode(block.text())))); } else if (block.type() == PgpMessageBlock) { CryptoMessagePart::Ptr mp(new CryptoMessagePart(mOtp, QString(), cryptProto, fromAddress, Q_NULLPTR)); mp->setDecryptMessage(decryptMessage()); mp->setIsEncrypted(true); appendSubPart(mp); if (!decryptMessage()) { continue; } mp->startDecryption(block.text(), aCodec); if (mp->partMetaData()->inProgress) { continue; } } else if (block.type() == ClearsignedBlock) { CryptoMessagePart::Ptr mp(new CryptoMessagePart(mOtp, QString(), cryptProto, fromAddress, Q_NULLPTR)); appendSubPart(mp); mp->startVerification(block.text(), aCodec); } else { continue; } const auto mp = subParts().last().staticCast(); const PartMetaData *messagePart(mp->partMetaData()); if (!messagePart->isEncrypted && !messagePart->isSigned && !block.text().trimmed().isEmpty()) { mp->setText(aCodec->toUnicode(block.text())); } if (messagePart->isEncrypted) { mEncryptionState = KMMsgPartiallyEncrypted; } if (messagePart->isSigned) { mSignatureState = KMMsgPartiallySigned; } } //Do we have an fully Signed/Encrypted Message? if (fullySignedOrEncrypted) { if (mSignatureState == KMMsgPartiallySigned) { mSignatureState = KMMsgFullySigned; } if (mEncryptionState == KMMsgPartiallyEncrypted) { mEncryptionState = KMMsgFullyEncrypted; } } } } KMMsgEncryptionState TextMessagePart::encryptionState() const { return mEncryptionState; } KMMsgSignatureState TextMessagePart::signatureState() const { return mSignatureState; } bool TextMessagePart::isHidden() const { return mIsHidden; } //-----HtmlMessageBlock---------------------- HtmlMessagePart::HtmlMessagePart(ObjectTreeParser *otp, KMime::Content *node, Interface::ObjectTreeSource *source) : MessagePart(otp, QString()) , mNode(node) , mSource(source) { if (!mNode) { qCWarning(MIMETREEPARSER_LOG) << "not a valid node"; return; } const QByteArray partBody(mNode->decodedContent()); mBodyHTML = mOtp->codecFor(mNode)->toUnicode(partBody); mCharset = NodeHelper::charset(mNode); } HtmlMessagePart::~HtmlMessagePart() { } void HtmlMessagePart::fix() const { mOtp->mHtmlContent += mBodyHTML; mOtp->mHtmlContentCharset = mCharset; } QString HtmlMessagePart::text() const { return mBodyHTML; } bool HtmlMessagePart::isHtml() const { return true; } //-----MimeMessageBlock---------------------- MimeMessagePart::MimeMessagePart(ObjectTreeParser *otp, KMime::Content *node, bool onlyOneMimePart) : MessagePart(otp, QString()) , mNode(node) , mOnlyOneMimePart(onlyOneMimePart) { if (!mNode) { qCWarning(MIMETREEPARSER_LOG) << "not a valid node"; return; } parseInternal(mNode, mOnlyOneMimePart); } MimeMessagePart::~MimeMessagePart() { } QString MimeMessagePart::text() const { return renderInternalText(); } QString MimeMessagePart::plaintextContent() const { return QString(); } QString MimeMessagePart::htmlContent() const { return QString(); } //-----AlternativeMessagePart---------------------- AlternativeMessagePart::AlternativeMessagePart(ObjectTreeParser *otp, KMime::Content *textNode, KMime::Content *htmlNode) : MessagePart(otp, QString()) , mTextNode(textNode) , mHTMLNode(htmlNode) , mViewHtml(false) { if (!mTextNode && !mHTMLNode) { qCWarning(MIMETREEPARSER_LOG) << "not a valid nodes"; return; } if (mTextNode) { mTextPart = MimeMessagePart::Ptr(new MimeMessagePart(mOtp, mTextNode, true)); } if (mHTMLNode) { mHTMLPart = MimeMessagePart::Ptr(new MimeMessagePart(mOtp, mHTMLNode, true)); } } AlternativeMessagePart::~AlternativeMessagePart() { } void AlternativeMessagePart::setViewHtml(bool html) { mViewHtml = html; } bool AlternativeMessagePart::viewHtml() const { return mViewHtml; } QString AlternativeMessagePart::text() const { if (mTextPart) { return mTextPart->text(); } return QString(); } void AlternativeMessagePart::fix() const { if (mTextPart) { mTextPart->fix(); } if (viewHtml() && mHTMLPart) { mHTMLPart->fix(); } } void AlternativeMessagePart::copyContentFrom() const { if (mTextPart) { mTextPart->copyContentFrom(); } if (viewHtml() && mHTMLPart) { mHTMLPart->copyContentFrom(); } } bool AlternativeMessagePart::isHtml() const { return (mHTMLNode); } QString AlternativeMessagePart::plaintextContent() const { return mTextPart->text(); } QString AlternativeMessagePart::htmlContent() const { if (mHTMLNode) { return mHTMLPart->text(); } else { return plaintextContent(); } } //-----CertMessageBlock---------------------- CertMessagePart::CertMessagePart(ObjectTreeParser *otp, KMime::Content *node, const Kleo::CryptoBackend::Protocol *cryptoProto, bool autoImport) : MessagePart(otp, QString()) , mNode(node) , mAutoImport(autoImport) , mCryptoProto(cryptoProto) { if (!mNode) { qCWarning(MIMETREEPARSER_LOG) << "not a valid node"; return; } if (!mAutoImport) { return; } const QByteArray certData = node->decodedContent(); Kleo::ImportJob *import = mCryptoProto->importJob(); KleoJobExecutor executor; mImportResult = executor.exec(import, certData); } CertMessagePart::~CertMessagePart() { } QString CertMessagePart::text() const { return QString(); } //-----CryptMessageBlock--------------------- CryptoMessagePart::CryptoMessagePart(ObjectTreeParser *otp, const QString &text, const Kleo::CryptoBackend::Protocol *cryptoProto, const QString &fromAddress, KMime::Content *node) : MessagePart(otp, text) , mPassphraseError(false) , mNoSecKey(false) , mCryptoProto(cryptoProto) , mFromAddress(fromAddress) , mNode(node) , mDecryptMessage(false) { mMetaData.technicalProblem = (mCryptoProto == 0); mMetaData.isSigned = false; mMetaData.isGoodSignature = false; mMetaData.isEncrypted = false; mMetaData.isDecryptable = false; mMetaData.keyTrust = GpgME::Signature::Unknown; mMetaData.status = i18n("Wrong Crypto Plug-In."); mMetaData.status_code = GPGME_SIG_STAT_NONE; } CryptoMessagePart::~CryptoMessagePart() { } void CryptoMessagePart::setDecryptMessage(bool decrypt) { mDecryptMessage = decrypt; } bool CryptoMessagePart::decryptMessage() const { return mDecryptMessage; } void CryptoMessagePart::setIsEncrypted(bool encrypted) { mMetaData.isEncrypted = encrypted; } bool CryptoMessagePart::isEncrypted() const { return mMetaData.isEncrypted; } void CryptoMessagePart::setIsSigned(bool isSigned) { mMetaData.isSigned = isSigned; } bool CryptoMessagePart::isSigned() const { return mMetaData.isSigned; } bool CryptoMessagePart::passphraseError() const { return mPassphraseError; } void CryptoMessagePart::startDecryption(const QByteArray &text, const QTextCodec *aCodec) { KMime::Content *content = new KMime::Content; content->setBody(text); content->parse(); startDecryption(content); if (!mMetaData.inProgress && mMetaData.isDecryptable) { setText(aCodec->toUnicode(mDecryptedData)); } } bool CryptoMessagePart::okDecryptMIME(KMime::Content &data) { mPassphraseError = false; mMetaData.inProgress = false; mMetaData.errorText.clear(); mMetaData.auditLogError = GpgME::Error(); mMetaData.auditLog.clear(); bool bDecryptionOk = false; bool cannotDecrypt = false; Interface::ObjectTreeSource *_source = source(); NodeHelper *nodeHelper = mOtp->nodeHelper(); assert(decryptMessage()); // Check whether the memento contains a result from last time: const DecryptVerifyBodyPartMemento *m = dynamic_cast(nodeHelper->bodyPartMemento(&data, "decryptverify")); assert(!m || mCryptoProto); //No CryptoPlugin and having a bodyPartMemento -> there is something completely wrong if (!m && mCryptoProto) { Kleo::DecryptVerifyJob *job = mCryptoProto->decryptVerifyJob(); if (!job) { cannotDecrypt = true; } else { const QByteArray ciphertext = data.decodedContent(); DecryptVerifyBodyPartMemento *newM = new DecryptVerifyBodyPartMemento(job, ciphertext); if (mOtp->allowAsync()) { QObject::connect(newM, &CryptoBodyPartMemento::update, nodeHelper, &NodeHelper::update); QObject::connect(newM, SIGNAL(update(MimeTreeParser::UpdateMode)), _source->sourceObject(), SLOT(update(MimeTreeParser::UpdateMode))); if (newM->start()) { mMetaData.inProgress = true; mOtp->mHasPendingAsyncJobs = true; } else { m = newM; } } else { newM->exec(); m = newM; } nodeHelper->setBodyPartMemento(&data, "decryptverify", newM); } } else if (m->isRunning()) { mMetaData.inProgress = true; mOtp->mHasPendingAsyncJobs = true; m = Q_NULLPTR; } if (m) { const QByteArray &plainText = m->plainText(); const GpgME::DecryptionResult &decryptResult = m->decryptResult(); const GpgME::VerificationResult &verifyResult = m->verifyResult(); mMetaData.isSigned = verifyResult.signatures().size() > 0; mSignatures = verifyResult.signatures(); mDecryptRecipients = decryptResult.recipients(); bDecryptionOk = !decryptResult.error(); mMetaData.auditLogError = m->auditLogError(); mMetaData.auditLog = m->auditLogAsHtml(); // std::stringstream ss; // ss << decryptResult << '\n' << verifyResult; // qCDebug(MIMETREEPARSER_LOG) << ss.str().c_str(); if (!bDecryptionOk && mMetaData.isSigned) { //Only a signed part mMetaData.isEncrypted = false; bDecryptionOk = true; mDecryptedData = plainText; } else { mPassphraseError = decryptResult.error().isCanceled() || decryptResult.error().code() == GPG_ERR_NO_SECKEY; mMetaData.isEncrypted = decryptResult.error().code() != GPG_ERR_NO_DATA; mMetaData.errorText = QString::fromLocal8Bit(decryptResult.error().asString()); if (mMetaData.isEncrypted && decryptResult.numRecipients() > 0) { mMetaData.keyId = decryptResult.recipient(0).keyID(); } if (bDecryptionOk) { mDecryptedData = plainText; } else { mNoSecKey = true; foreach (const GpgME::DecryptionResult::Recipient &recipient, decryptResult.recipients()) { mNoSecKey &= (recipient.status().code() == GPG_ERR_NO_SECKEY); } } } } if (!bDecryptionOk) { QString cryptPlugLibName; if (mCryptoProto) { cryptPlugLibName = mCryptoProto->name(); } if (!mCryptoProto) { mMetaData.errorText = i18n("No appropriate crypto plug-in was found."); } else if (cannotDecrypt) { mMetaData.errorText = i18n("Crypto plug-in \"%1\" cannot decrypt messages.", cryptPlugLibName); } else if (!passphraseError()) { mMetaData.errorText = i18n("Crypto plug-in \"%1\" could not decrypt the data.", cryptPlugLibName) + QLatin1String("
") + i18n("Error: %1", mMetaData.errorText); } } return bDecryptionOk; } void CryptoMessagePart::startDecryption(KMime::Content *data) { if (!mNode && !data) { return; } if (!data) { data = mNode; } mMetaData.isEncrypted = true; bool bOkDecrypt = okDecryptMIME(*data); if (mMetaData.inProgress) { return; } mMetaData.isDecryptable = bOkDecrypt; if (!mMetaData.isDecryptable) { setText(QString::fromUtf8(mDecryptedData.constData())); } if (mMetaData.isSigned) { sigStatusToMetaData(); mVerifiedText = mDecryptedData; } if (mMetaData.isEncrypted && !decryptMessage()) { mMetaData.isDecryptable = true; } if (mNode) { mOtp->mNodeHelper->setPartMetaData(mNode, mMetaData); if (decryptMessage()) { auto tempNode = new KMime::Content(); tempNode->setContent(KMime::CRLFtoLF(mDecryptedData.constData())); tempNode->parse(); if (!tempNode->head().isEmpty()) { tempNode->contentDescription()->from7BitString("encrypted data"); } mOtp->mNodeHelper->attachExtraContent(mNode, tempNode); parseInternal(tempNode, false); } } } bool CryptoMessagePart::okVerify(const QByteArray &data, const QByteArray &signature) { NodeHelper *nodeHelper = mOtp->nodeHelper(); Interface::ObjectTreeSource *_source = source(); mMetaData.isSigned = false; mMetaData.technicalProblem = (mCryptoProto == 0); mMetaData.keyTrust = GpgME::Signature::Unknown; mMetaData.status = i18n("Wrong Crypto Plug-In."); mMetaData.status_code = GPGME_SIG_STAT_NONE; const QByteArray mementoName = "verification"; CryptoBodyPartMemento *m = dynamic_cast(nodeHelper->bodyPartMemento(mNode, mementoName)); assert(!m || mCryptoProto); //No CryptoPlugin and having a bodyPartMemento -> there is something completely wrong if (!m && mCryptoProto) { if (!signature.isEmpty()) { Kleo::VerifyDetachedJob *job = mCryptoProto->verifyDetachedJob(); if (job) { m = new VerifyDetachedBodyPartMemento(job, mCryptoProto->keyListJob(), signature, data); } } else { Kleo::VerifyOpaqueJob *job = mCryptoProto->verifyOpaqueJob(); if (job) { m = new VerifyOpaqueBodyPartMemento(job, mCryptoProto->keyListJob(), data); } } if (m) { if (mOtp->allowAsync()) { QObject::connect(m, &CryptoBodyPartMemento::update, nodeHelper, &NodeHelper::update); QObject::connect(m, SIGNAL(update(MimeTreeParser::UpdateMode)), _source->sourceObject(), SLOT(update(MimeTreeParser::UpdateMode))); if (m->start()) { mMetaData.inProgress = true; mOtp->mHasPendingAsyncJobs = true; } } else { m->exec(); } nodeHelper->setBodyPartMemento(mNode, mementoName, m); } } else if (m->isRunning()) { mMetaData.inProgress = true; mOtp->mHasPendingAsyncJobs = true; } else { mMetaData.inProgress = false; mOtp->mHasPendingAsyncJobs = false; } if (m && !mMetaData.inProgress) { if (!signature.isEmpty()) { VerifyDetachedBodyPartMemento *vm = dynamic_cast(m); mVerifiedText = data; mSignatures = vm->verifyResult().signatures(); } else { VerifyOpaqueBodyPartMemento *vm = dynamic_cast(m); mVerifiedText = vm->plainText(); mSignatures = vm->verifyResult().signatures(); } mMetaData.auditLogError = m->auditLogError(); mMetaData.auditLog = m->auditLogAsHtml(); mMetaData.isSigned = !mSignatures.empty(); } if (!m && !mMetaData.inProgress) { QString errorMsg; QString cryptPlugLibName; QString cryptPlugDisplayName; if (mCryptoProto) { cryptPlugLibName = mCryptoProto->name(); cryptPlugDisplayName = mCryptoProto->displayName(); } if (!mCryptoProto) { if (cryptPlugDisplayName.isEmpty()) { errorMsg = i18n("No appropriate crypto plug-in was found."); } else { errorMsg = i18nc("%1 is either 'OpenPGP' or 'S/MIME'", "No %1 plug-in was found.", cryptPlugDisplayName); } } else { errorMsg = i18n("Crypto plug-in \"%1\" cannot verify signatures.", cryptPlugLibName); } mMetaData.errorText = i18n("The message is signed, but the " "validity of the signature cannot be " "verified.
" "Reason: %1", errorMsg); } return mMetaData.isSigned; } static int signatureToStatus(const GpgME::Signature &sig) { switch (sig.status().code()) { case GPG_ERR_NO_ERROR: return GPGME_SIG_STAT_GOOD; case GPG_ERR_BAD_SIGNATURE: return GPGME_SIG_STAT_BAD; case GPG_ERR_NO_PUBKEY: return GPGME_SIG_STAT_NOKEY; case GPG_ERR_NO_DATA: return GPGME_SIG_STAT_NOSIG; case GPG_ERR_SIG_EXPIRED: return GPGME_SIG_STAT_GOOD_EXP; case GPG_ERR_KEY_EXPIRED: return GPGME_SIG_STAT_GOOD_EXPKEY; default: return GPGME_SIG_STAT_ERROR; } } void CryptoMessagePart::sigStatusToMetaData() { GpgME::Key key; if (mMetaData.isSigned) { GpgME::Signature signature = mSignatures.front(); mMetaData.status_code = signatureToStatus(signature); mMetaData.isGoodSignature = mMetaData.status_code & GPGME_SIG_STAT_GOOD; // save extended signature status flags mMetaData.sigSummary = signature.summary(); if (mMetaData.isGoodSignature && !key.keyID()) { // Search for the key by it's fingerprint so that we can check for // trust etc. Kleo::KeyListJob *job = mCryptoProto->keyListJob(false); // local, no sigs if (!job) { qCDebug(MIMETREEPARSER_LOG) << "The Crypto backend does not support listing keys. "; } else { std::vector found_keys; // As we are local it is ok to make this synchronous GpgME::KeyListResult res = job->exec(QStringList(QLatin1String(signature.fingerprint())), false, found_keys); if (res.error()) { qCDebug(MIMETREEPARSER_LOG) << "Error while searching key for Fingerprint: " << signature.fingerprint(); } if (found_keys.size() > 1) { // Should not Happen qCDebug(MIMETREEPARSER_LOG) << "Oops: Found more then one Key for Fingerprint: " << signature.fingerprint(); } if (found_keys.size() != 1) { // Should not Happen at this point qCDebug(MIMETREEPARSER_LOG) << "Oops: Found no Key for Fingerprint: " << signature.fingerprint(); } else { key = found_keys[0]; } } } if (key.keyID()) { mMetaData.keyId = key.keyID(); } if (mMetaData.keyId.isEmpty()) { mMetaData.keyId = signature.fingerprint(); } mMetaData.keyTrust = signature.validity(); if (key.numUserIDs() > 0 && key.userID(0).id()) { mMetaData.signer = Kleo::DN(key.userID(0).id()).prettyDN(); } for (uint iMail = 0; iMail < key.numUserIDs(); ++iMail) { // The following if /should/ always result in TRUE but we // won't trust implicitely the plugin that gave us these data. if (key.userID(iMail).email()) { QString email = QString::fromUtf8(key.userID(iMail).email()); // ### work around gpgme 0.3.x / cryptplug bug where the // ### email addresses are specified as angle-addr, not addr-spec: if (email.startsWith(QLatin1Char('<')) && email.endsWith(QLatin1Char('>'))) { email = email.mid(1, email.length() - 2); } if (!email.isEmpty()) { mMetaData.signerMailAddresses.append(email); } } } if (signature.creationTime()) { mMetaData.creationTime.setTime_t(signature.creationTime()); } else { mMetaData.creationTime = QDateTime(); } if (mMetaData.signer.isEmpty()) { if (key.numUserIDs() > 0 && key.userID(0).name()) { mMetaData.signer = Kleo::DN(key.userID(0).name()).prettyDN(); } if (!mMetaData.signerMailAddresses.empty()) { if (mMetaData.signer.isEmpty()) { mMetaData.signer = mMetaData.signerMailAddresses.front(); } else { mMetaData.signer += QLatin1String(" <") + mMetaData.signerMailAddresses.front() + QLatin1Char('>'); } } } } } void CryptoMessagePart::startVerification(const QByteArray &text, const QTextCodec *aCodec) { startVerificationDetached(text, Q_NULLPTR, QByteArray()); if (!mNode && mMetaData.isSigned) { setText(aCodec->toUnicode(mVerifiedText)); } } void CryptoMessagePart::startVerificationDetached(const QByteArray &text, KMime::Content *textNode, const QByteArray &signature) { mMetaData.isEncrypted = false; mMetaData.isDecryptable = false; okVerify(text, signature); if (mMetaData.isSigned) { sigStatusToMetaData(); } else { mMetaData.creationTime = QDateTime(); } if (mNode) { if (textNode && !signature.isEmpty()) { mVerifiedText = text; } else if (!mVerifiedText.isEmpty()) { textNode = new KMime::Content(); textNode->setContent(KMime::CRLFtoLF(mVerifiedText.constData())); textNode->parse(); if (!textNode->head().isEmpty()) { textNode->contentDescription()->from7BitString("opaque signed data"); } mOtp->mNodeHelper->attachExtraContent(mNode, textNode); } if (!mVerifiedText.isEmpty() && textNode) { parseInternal(textNode, false); } } } QString CryptoMessagePart::plaintextContent() const { if (!mNode) { return MessagePart::text(); } else { return QString(); } } QString CryptoMessagePart::htmlContent() const { if (!mNode) { return MessagePart::text(); } else { return QString(); } } EncapsulatedRfc822MessagePart::EncapsulatedRfc822MessagePart(ObjectTreeParser *otp, KMime::Content *node, const KMime::Message::Ptr &message) : MessagePart(otp, QString()) , mMessage(message) , mNode(node) { mMetaData.isEncrypted = false; mMetaData.isSigned = false; mMetaData.isEncapsulatedRfc822Message = true; mOtp->nodeHelper()->setNodeDisplayedEmbedded(mNode, true); mOtp->nodeHelper()->setPartMetaData(mNode, mMetaData); if (!mMessage) { qCWarning(MIMETREEPARSER_LOG) << "Node is of type message/rfc822 but doesn't have a message!"; return; } // The link to "Encapsulated message" is clickable, therefore the temp file needs to exists, // since the user can click the link and expect to have normal attachment operations there. mOtp->nodeHelper()->writeNodeToTempFile(message.data()); parseInternal(message.data(), false); } EncapsulatedRfc822MessagePart::~EncapsulatedRfc822MessagePart() { } QString EncapsulatedRfc822MessagePart::text() const { return renderInternalText(); } void EncapsulatedRfc822MessagePart::copyContentFrom() const { } void EncapsulatedRfc822MessagePart::fix() const { } diff --git a/mimetreeparser/src/viewer/messagepart.h b/mimetreeparser/src/viewer/messagepart.h index 2d1fe610..9e9cb5bf 100644 --- a/mimetreeparser/src/viewer/messagepart.h +++ b/mimetreeparser/src/viewer/messagepart.h @@ -1,347 +1,346 @@ /* Copyright (c) 2015 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. */ #ifndef __MIMETREEPARSER_MESSAGEPART_H__ #define __MIMETREEPARSER_MESSAGEPART_H__ #include "mimetreeparser_export.h" #include "mimetreeparser/bodypartformatter.h" #include #include #include #include #include #include #include class QTextCodec; namespace GpgME { class ImportResult; } namespace KMime { class Content; } namespace MimeTreeParser { class ObjectTreeParser; class HtmlWriter; class NodeHelper; class HTMLBlock; typedef QSharedPointer HTMLBlockPtr; namespace Interface { class ObjectTreeSource; } class MIMETREEPARSER_EXPORT MessagePart : public Interface::MessagePart { Q_OBJECT Q_PROPERTY(bool attachment READ isAttachment) Q_PROPERTY(bool root READ isRoot) Q_PROPERTY(bool isHtml READ isHtml) Q_PROPERTY(bool isHidden READ isHidden) public: typedef QSharedPointer Ptr; MessagePart(ObjectTreeParser *otp, const QString &text); virtual ~MessagePart(); virtual QString text() const Q_DECL_OVERRIDE; void setText(const QString &text); void setAttachmentFlag(KMime::Content *node); bool isAttachment() const; void setIsRoot(bool root); bool isRoot() const; virtual bool isHtml() const; virtual bool isHidden() const; PartMetaData *partMetaData(); /* only a function that should be removed if the refactoring is over */ virtual void fix() const; virtual void copyContentFrom() const; void appendSubPart(const Interface::MessagePart::Ptr &messagePart); const QVector &subParts() const; bool hasSubParts() const; HtmlWriter *htmlWriter() const Q_DECL_OVERRIDE; void setHtmlWriter(HtmlWriter *htmlWriter) const Q_DECL_OVERRIDE; Interface::ObjectTreeSource *source() const; - CSSHelperBase *cssHelper() const; KMime::Content *attachmentNode() const; protected: void parseInternal(KMime::Content *node, bool onlyOneMimePart); QString renderInternalText() const; QString mText; ObjectTreeParser *mOtp; ObjectTreeParser *mSubOtp; PartMetaData mMetaData; private: QVector mBlocks; KMime::Content *mAttachmentNode; bool mRoot; }; class MIMETREEPARSER_EXPORT MimeMessagePart : public MessagePart { Q_OBJECT public: typedef QSharedPointer Ptr; MimeMessagePart(MimeTreeParser::ObjectTreeParser *otp, KMime::Content *node, bool onlyOneMimePart); virtual ~MimeMessagePart(); QString text() const Q_DECL_OVERRIDE; QString plaintextContent() const Q_DECL_OVERRIDE; QString htmlContent() const Q_DECL_OVERRIDE; private: KMime::Content *mNode; bool mOnlyOneMimePart; friend class AlternativeMessagePart; }; class MIMETREEPARSER_EXPORT MessagePartList : public MessagePart { Q_OBJECT public: typedef QSharedPointer Ptr; MessagePartList(MimeTreeParser::ObjectTreeParser *otp); virtual ~MessagePartList(); QString text() const Q_DECL_OVERRIDE; QString plaintextContent() const Q_DECL_OVERRIDE; QString htmlContent() const Q_DECL_OVERRIDE; private: }; enum IconType { NoIcon = 0, IconExternal, IconInline }; class MIMETREEPARSER_EXPORT TextMessagePart : public MessagePartList { Q_OBJECT public: typedef QSharedPointer Ptr; TextMessagePart(MimeTreeParser::ObjectTreeParser *otp, KMime::Content *node, bool drawFrame, bool showLink, bool decryptMessage, IconType asIcon); virtual ~TextMessagePart(); KMMsgSignatureState signatureState() const; KMMsgEncryptionState encryptionState() const; bool decryptMessage() const; bool isHidden() const Q_DECL_OVERRIDE; private: void parseContent(); KMime::Content *mNode; KMMsgSignatureState mSignatureState; KMMsgEncryptionState mEncryptionState; bool mDrawFrame; bool mShowLink; bool mDecryptMessage; bool mIsHidden; IconType mAsIcon; friend class DefaultRendererPrivate; }; class MIMETREEPARSER_EXPORT HtmlMessagePart : public MessagePart { Q_OBJECT public: typedef QSharedPointer Ptr; HtmlMessagePart(MimeTreeParser::ObjectTreeParser *otp, KMime::Content *node, MimeTreeParser::Interface::ObjectTreeSource *source); virtual ~HtmlMessagePart(); QString text() const Q_DECL_OVERRIDE; void fix() const Q_DECL_OVERRIDE; bool isHtml() const Q_DECL_OVERRIDE; private: KMime::Content *mNode; Interface::ObjectTreeSource *mSource; QString mBodyHTML; QByteArray mCharset; friend class DefaultRendererPrivate; }; class MIMETREEPARSER_EXPORT AlternativeMessagePart : public MessagePart { Q_OBJECT public: typedef QSharedPointer Ptr; AlternativeMessagePart(MimeTreeParser::ObjectTreeParser *otp, KMime::Content *textNode, KMime::Content *htmlNode); virtual ~AlternativeMessagePart(); QString text() const Q_DECL_OVERRIDE; void setViewHtml(bool html); bool viewHtml() const; bool isHtml() const Q_DECL_OVERRIDE; QString plaintextContent() const Q_DECL_OVERRIDE; QString htmlContent() const Q_DECL_OVERRIDE; void fix() const Q_DECL_OVERRIDE; void copyContentFrom() const Q_DECL_OVERRIDE; private: KMime::Content *mTextNode; KMime::Content *mHTMLNode; MimeMessagePart::Ptr mTextPart; MimeMessagePart::Ptr mHTMLPart; bool mViewHtml; friend class DefaultRendererPrivate; }; class MIMETREEPARSER_EXPORT CertMessagePart : public MessagePart { Q_OBJECT public: typedef QSharedPointer Ptr; CertMessagePart(MimeTreeParser::ObjectTreeParser *otp, KMime::Content *node, const Kleo::CryptoBackend::Protocol *cryptoProto, bool autoImport); virtual ~CertMessagePart(); QString text() const Q_DECL_OVERRIDE; private: KMime::Content *mNode; bool mAutoImport; GpgME::ImportResult mImportResult; const Kleo::CryptoBackend::Protocol *mCryptoProto; friend class DefaultRendererPrivate; }; class MIMETREEPARSER_EXPORT EncapsulatedRfc822MessagePart : public MessagePart { Q_OBJECT public: typedef QSharedPointer Ptr; EncapsulatedRfc822MessagePart(MimeTreeParser::ObjectTreeParser *otp, KMime::Content *node, const KMime::Message::Ptr &message); virtual ~EncapsulatedRfc822MessagePart(); QString text() const Q_DECL_OVERRIDE; void copyContentFrom() const Q_DECL_OVERRIDE; void fix() const Q_DECL_OVERRIDE; private: const KMime::Message::Ptr mMessage; KMime::Content *mNode; friend class DefaultRendererPrivate; }; class MIMETREEPARSER_EXPORT CryptoMessagePart : public MessagePart { Q_OBJECT Q_PROPERTY(bool decryptMessage READ decryptMessage WRITE setDecryptMessage) Q_PROPERTY(bool isEncrypted READ isEncrypted) Q_PROPERTY(bool isSigned READ isSigned) Q_PROPERTY(bool passphraseError READ passphraseError) public: typedef QSharedPointer Ptr; CryptoMessagePart(ObjectTreeParser *otp, const QString &text, const Kleo::CryptoBackend::Protocol *cryptoProto, const QString &fromAddress, KMime::Content *node); virtual ~CryptoMessagePart(); void setDecryptMessage(bool decrypt); bool decryptMessage() const; void setIsEncrypted(bool encrypted); bool isEncrypted() const; void setIsSigned(bool isSigned); bool isSigned() const; bool passphraseError() const; void startDecryption(const QByteArray &text, const QTextCodec *aCodec); void startDecryption(KMime::Content *data = 0); void startVerification(const QByteArray &text, const QTextCodec *aCodec); void startVerificationDetached(const QByteArray &text, KMime::Content *textNode, const QByteArray &signature); QByteArray mDecryptedData; std::vector mSignatures; QString plaintextContent() const Q_DECL_OVERRIDE; QString htmlContent() const Q_DECL_OVERRIDE; private: /** Handles the dectyptioon of a given content * returns true if the decryption was successfull * if used in async mode, check if mMetaData.inProgress is true, it inicates a running decryption process. */ bool okDecryptMIME(KMime::Content &data); /** Handles the verification of data * If signature is empty it is handled as inline signature otherwise as detached signature mode. * Returns true if the verfication was successfull and the block is signed. * If used in async mode, check if mMetaData.inProgress is true, it inicates a running verification process. */ bool okVerify(const QByteArray &data, const QByteArray &signature); void sigStatusToMetaData(); protected: bool mPassphraseError; bool mNoSecKey; const Kleo::CryptoBackend::Protocol *mCryptoProto; QString mFromAddress; KMime::Content *mNode; bool mDecryptMessage; QByteArray mVerifiedText; std::vector mDecryptRecipients; friend class DefaultRendererPrivate; }; } #endif //__MIMETREEPARSER_MESSAGEPART_H__ diff --git a/mimetreeparser/src/viewer/objecttreeparser.cpp b/mimetreeparser/src/viewer/objecttreeparser.cpp index d7bcdebc..0af374c7 100644 --- a/mimetreeparser/src/viewer/objecttreeparser.cpp +++ b/mimetreeparser/src/viewer/objecttreeparser.cpp @@ -1,538 +1,532 @@ /* objecttreeparser.cpp This file is part of KMail, the KDE mail client. Copyright (c) 2003 Marc Mutz Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net Copyright (c) 2009 Andras Mantia Copyright (c) 2015 Sandro Knauß KMail is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation. KMail 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ // MessageViewer includes #include "objecttreeparser.h" #include "attachmentstrategy.h" #include "bodypartformatterbasefactory.h" -#include "csshelperbase.h" #include "nodehelper.h" #include "messagepart.h" #include "partnodebodypart.h" #include "mimetreeparser_debug.h" #include "interfaces/bodypartformatter.h" #include "interfaces/htmlwriter.h" #include "interfaces/messagepartrenderer.h" #include "utils/util.h" #include #include // KDE includes #include // Qt includes #include #include #include using namespace MimeTreeParser; ObjectTreeParser::ObjectTreeParser(const ObjectTreeParser *topLevelParser, bool showOnlyOneMimePart, const AttachmentStrategy *strategy) : mSource(topLevelParser->mSource), mNodeHelper(topLevelParser->mNodeHelper), mHtmlWriter(topLevelParser->mHtmlWriter), mTopLevelContent(topLevelParser->mTopLevelContent), mShowOnlyOneMimePart(showOnlyOneMimePart), mHasPendingAsyncJobs(false), mAllowAsync(topLevelParser->mAllowAsync), mAttachmentStrategy(strategy), mPrinting(false) { init(); } ObjectTreeParser::ObjectTreeParser(Interface::ObjectTreeSource *source, MimeTreeParser::NodeHelper *nodeHelper, bool showOnlyOneMimePart, const AttachmentStrategy *strategy) : mSource(source), mNodeHelper(nodeHelper), mHtmlWriter(Q_NULLPTR), mTopLevelContent(0), mShowOnlyOneMimePart(showOnlyOneMimePart), mHasPendingAsyncJobs(false), mAllowAsync(false), mAttachmentStrategy(strategy), mPrinting(false) { init(); } void ObjectTreeParser::init() { assert(mSource); if (!attachmentStrategy()) { mAttachmentStrategy = mSource->attachmentStrategy(); } if (!mNodeHelper) { mNodeHelper = new NodeHelper(); mDeleteNodeHelper = true; } else { mDeleteNodeHelper = false; } } ObjectTreeParser::ObjectTreeParser(const ObjectTreeParser &other) : mSource(other.mSource), mNodeHelper(other.nodeHelper()), //TODO(Andras) hm, review what happens if mDeleteNodeHelper was true in the source mHtmlWriter(other.mHtmlWriter), mTopLevelContent(other.mTopLevelContent), mShowOnlyOneMimePart(other.showOnlyOneMimePart()), mHasPendingAsyncJobs(other.hasPendingAsyncJobs()), mAllowAsync(other.allowAsync()), mAttachmentStrategy(other.attachmentStrategy()), mDeleteNodeHelper(false), // TODO see above mPrinting(other.printing()) { } ObjectTreeParser::~ObjectTreeParser() { if (mDeleteNodeHelper) { delete mNodeHelper; mNodeHelper = Q_NULLPTR; } } void ObjectTreeParser::setAllowAsync(bool allow) { assert(!mHasPendingAsyncJobs); mAllowAsync = allow; } bool ObjectTreeParser::allowAsync() const { return mAllowAsync; } bool ObjectTreeParser::hasPendingAsyncJobs() const { return mHasPendingAsyncJobs; } QString ObjectTreeParser::plainTextContent() const { return mPlainTextContent; } QString ObjectTreeParser::htmlContent() const { return mHtmlContent; } void ObjectTreeParser::copyContentFrom(const ObjectTreeParser *other) { mPlainTextContent += other->plainTextContent(); mHtmlContent += other->htmlContent(); if (!other->plainTextContentCharset().isEmpty()) { mPlainTextContentCharset = other->plainTextContentCharset(); } if (!other->htmlContentCharset().isEmpty()) { mHtmlContentCharset = other->htmlContentCharset(); } } //----------------------------------------------------------------------------- void ObjectTreeParser::parseObjectTree(KMime::Content *node) { mTopLevelContent = node; mParsedPart = MessagePart::Ptr(new MessagePartList(this)); parseObjectTreeInternal(node); if (mParsedPart) { mParsedPart->fix(); mParsedPart->copyContentFrom(); if (htmlWriter()) { const auto renderer = mSource->messagePartTheme(mParsedPart); if (renderer) { mHtmlWriter->queue(renderer->html()); } } } } MessagePartPtr ObjectTreeParser::parsedPart() const { return mParsedPart; } void ObjectTreeParser::setPrinting(bool printing) { mPrinting = printing; } bool ObjectTreeParser::printing() const { return mPrinting; } bool ObjectTreeParser::processType(KMime::Content *node, ProcessResult &processResult, const QByteArray &mediaType, const QByteArray &subType, Interface::MessagePartPtr &mpRet) { bool bRendered = false; const auto sub = mSource->bodyPartFormatterFactory()->subtypeRegistry(mediaType.constData()); auto range = sub.equal_range(subType.constData()); for (auto it = range.first; it != range.second; ++it) { const auto formatter = (*it).second; if (!formatter) { continue; } PartNodeBodyPart part(this, &processResult, mTopLevelContent, node, mNodeHelper, codecFor(node)); // Set the default display strategy for this body part relying on the // identity of Interface::BodyPart::Display and AttachmentStrategy::Display part.setDefaultDisplay((Interface::BodyPart::Display) attachmentStrategy()->defaultDisplay(node)); mNodeHelper->setNodeDisplayedEmbedded(node, true); const Interface::MessagePart::Ptr result = formatter->process(part); if (!result) { continue; } if (const auto mp = result.dynamicCast()) { mp->setAttachmentFlag(node); mpRet = result; bRendered = true; break; } else if (dynamic_cast(result.data())) { QObject *asyncResultObserver = allowAsync() ? mSource->sourceObject() : Q_NULLPTR; const auto r = formatter->format(&part, htmlWriter(), asyncResultObserver); if (r == Interface::BodyPartFormatter::AsIcon) { processResult.setNeverDisplayInline(true); formatter->adaptProcessResult(processResult); mNodeHelper->setNodeDisplayedEmbedded(node, false); const Interface::MessagePart::Ptr mp = defaultHandling(node, processResult); if (mp) { if (auto _mp = mp.dynamicCast()) { _mp->setAttachmentFlag(node); } mpRet = mp; } bRendered = true; break; } continue; } else { continue; } } return bRendered; } MessagePart::Ptr ObjectTreeParser::parseObjectTreeInternal(KMime::Content *node) { if (!node) { return MessagePart::Ptr(); } // reset pending async jobs state (we'll rediscover pending jobs as we go) mHasPendingAsyncJobs = false; // reset "processed" flags for... if (showOnlyOneMimePart()) { // ... this node and all descendants mNodeHelper->setNodeUnprocessed(node, false); if (!node->contents().isEmpty()) { mNodeHelper->setNodeUnprocessed(node, true); } } else if (!node->parent()) { // ...this node and all it's siblings and descendants mNodeHelper->setNodeUnprocessed(node, true); } const bool isRoot = node->isTopLevel(); mParsedPart = MessagePart::Ptr(new MessagePartList(this)); mParsedPart->setIsRoot(isRoot); KMime::Content *parent = node->parent(); auto contents = parent ? parent->contents() : KMime::Content::List(); if (contents.isEmpty()) { contents.append(node); } int i = contents.indexOf(const_cast(node)); for (; i < contents.size(); ++i) { node = contents.at(i); if (mNodeHelper->nodeProcessed(node)) { continue; } ProcessResult processResult(mNodeHelper); 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(); } Interface::MessagePartPtr mp; if (processType(node, processResult, mediaType, subType, mp)) { if (mp) { mParsedPart->appendSubPart(mp); } } else if (processType(node, processResult, mediaType, "*", mp)) { if (mp) { mParsedPart->appendSubPart(mp); } } else { qCWarning(MIMETREEPARSER_LOG) << "THIS SHOULD NO LONGER HAPPEN:" << mediaType << '/' << subType; const auto mp = defaultHandling(node, processResult); if (mp) { if (auto _mp = mp.dynamicCast()) { _mp->setAttachmentFlag(node); } mParsedPart->appendSubPart(mp); } } mNodeHelper->setNodeProcessed(node, false); // adjust signed/encrypted flags if inline PGP was found processResult.adjustCryptoStatesOfNode(node); if (showOnlyOneMimePart()) { break; } } return mParsedPart; } Interface::MessagePart::Ptr ObjectTreeParser::defaultHandling(KMime::Content *node, ProcessResult &result) { // ### (mmutz) default handling should go into the respective // ### bodypartformatters. if (!htmlWriter()) { qCWarning(MIMETREEPARSER_LOG) << "no htmlWriter()"; return MessagePart::Ptr(); } // always show images in multipart/related when showing in html, not with an additional icon if (result.isImage() && node->parent() && node->parent()->contentType()->subType() == "related" && mSource->htmlMail() && !showOnlyOneMimePart()) { QString fileName = mNodeHelper->writeNodeToTempFile(node); QString href = QUrl::fromLocalFile(fileName).url(); QByteArray cid = node->contentID()->identifier(); htmlWriter()->embedPart(cid, href); nodeHelper()->setNodeDisplayedEmbedded(node, true); mNodeHelper->setNodeDisplayedHidden(node, true); const auto mp = TextMessagePart::Ptr(new TextMessagePart(this, node, false, true, mSource->decryptMessage(), MimeTreeParser::IconInline)); return mp; } Interface::MessagePart::Ptr mp; ProcessResult processResult(mNodeHelper); if (node->contentType()->mimeType() == QByteArray("application/octet-stream") && (node->contentType()->name().endsWith(QLatin1String("p7m")) || node->contentType()->name().endsWith(QLatin1String("p7s")) || node->contentType()->name().endsWith(QLatin1String("p7c")) ) && processType(node, processResult, "application", "pkcs7-mime", mp)) { return mp; } const AttachmentStrategy *const as = attachmentStrategy(); if (as && as->defaultDisplay(node) == AttachmentStrategy::None && !showOnlyOneMimePart() && node->parent() /* message is not an attachment */) { mNodeHelper->setNodeDisplayedHidden(node, true); const auto mp = TextMessagePart::Ptr(new TextMessagePart(this, node, false, true, mSource->decryptMessage(), MimeTreeParser::IconInline)); return mp; } bool asIcon = true; if (!result.neverDisplayInline()) { if (as) { asIcon = as->defaultDisplay(node) == AttachmentStrategy::AsIcon; } } // Show it inline if showOnlyOneMimePart(), which means the user clicked the image // in the message structure viewer manually, and therefore wants to see the full image if (result.isImage() && showOnlyOneMimePart() && !result.neverDisplayInline()) { asIcon = false; } // neither image nor text -> show as icon if (!result.isImage() && !node->contentType()->isText()) { asIcon = true; } /*FIXME(Andras) port it // if the image is not complete do not try to show it inline if ( result.isImage() && !node->msgPart().isComplete() ) asIcon = true; */ if (asIcon) { bool hidePart = (as && as->defaultDisplay(node) == AttachmentStrategy::None) || showOnlyOneMimePart(); mNodeHelper->setNodeDisplayedHidden(node, hidePart); return TextMessagePart::Ptr(new TextMessagePart(this, node, false, true, mSource->decryptMessage(), MimeTreeParser::IconExternal)); } else if (result.isImage()) { // Embed the image mNodeHelper->setNodeDisplayedEmbedded(node, true); return TextMessagePart::Ptr(new TextMessagePart(this, node, false, true, mSource->decryptMessage(), MimeTreeParser::IconInline)); } else { mNodeHelper->setNodeDisplayedEmbedded(node, true); const auto mp = TextMessagePart::Ptr(new TextMessagePart(this, node, false, true, mSource->decryptMessage(), MimeTreeParser::NoIcon)); result.setInlineSignatureState(mp->signatureState()); result.setInlineEncryptionState(mp->encryptionState()); return mp; } return MessagePart::Ptr(); } KMMsgSignatureState ProcessResult::inlineSignatureState() const { return mInlineSignatureState; } void ProcessResult::setInlineSignatureState(KMMsgSignatureState state) { mInlineSignatureState = state; } KMMsgEncryptionState ProcessResult::inlineEncryptionState() const { return mInlineEncryptionState; } void ProcessResult::setInlineEncryptionState(KMMsgEncryptionState state) { mInlineEncryptionState = state; } bool ProcessResult::neverDisplayInline() const { return mNeverDisplayInline; } void ProcessResult::setNeverDisplayInline(bool display) { mNeverDisplayInline = display; } bool ProcessResult::isImage() const { return mIsImage; } void ProcessResult::setIsImage(bool image) { mIsImage = image; } void ProcessResult::adjustCryptoStatesOfNode(const KMime::Content *node) const { if ((inlineSignatureState() != KMMsgNotSigned) || (inlineEncryptionState() != KMMsgNotEncrypted)) { mNodeHelper->setSignatureState(node, inlineSignatureState()); mNodeHelper->setEncryptionState(node, inlineEncryptionState()); } } void ObjectTreeParser::extractNodeInfos(KMime::Content *curNode, bool isFirstTextPart) { if (isFirstTextPart) { mPlainTextContent += curNode->decodedText(); mPlainTextContentCharset += NodeHelper::charset(curNode); } } void ObjectTreeParser::setPlainTextContent(QString plainTextContent) { mPlainTextContent = plainTextContent; } const QTextCodec *ObjectTreeParser::codecFor(KMime::Content *node) const { assert(node); if (mSource->overrideCodec()) { return mSource->overrideCodec(); } return mNodeHelper->codec(node); } QByteArray ObjectTreeParser::plainTextContentCharset() const { return mPlainTextContentCharset; } QByteArray ObjectTreeParser::htmlContentCharset() const { return mHtmlContentCharset; } bool ObjectTreeParser::showOnlyOneMimePart() const { return mShowOnlyOneMimePart; } void ObjectTreeParser::setShowOnlyOneMimePart(bool show) { mShowOnlyOneMimePart = show; } const AttachmentStrategy *ObjectTreeParser::attachmentStrategy() const { return mAttachmentStrategy; } HtmlWriter *ObjectTreeParser::htmlWriter() const { if (mHtmlWriter) { return mHtmlWriter; } return mSource->htmlWriter(); } -CSSHelperBase *ObjectTreeParser::cssHelper() const -{ - return mSource->cssHelper(); -} - MimeTreeParser::NodeHelper *ObjectTreeParser::nodeHelper() const { return mNodeHelper; } diff --git a/mimetreeparser/src/viewer/objecttreeparser.h b/mimetreeparser/src/viewer/objecttreeparser.h index d5cd85da..54f4ae4a 100644 --- a/mimetreeparser/src/viewer/objecttreeparser.h +++ b/mimetreeparser/src/viewer/objecttreeparser.h @@ -1,421 +1,418 @@ /* objecttreeparser.h This file is part of KMail, the KDE mail client. Copyright (c) 2003 Marc Mutz Copyright (C) 2002-2003, 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net Copyright (c) 2009 Andras Mantia KMail is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation. KMail 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __MIMETREEPARSER_OBJECTTREEPARSER_H__ #define __MIMETREEPARSER_OBJECTTREEPARSER_H__ #include "mimetreeparser_export.h" #include "mimetreeparser/nodehelper.h" #include "mimetreeparser/objecttreesource.h" #include #include class QString; namespace KMime { class Content; } namespace GpgME { class Error; class ImportResult; } namespace MimeTreeParser { namespace Interface { class MessagePart; typedef QSharedPointer MessagePartPtr; } class PartMetaData; class ViewerPrivate; class HtmlWriter; -class CSSHelperBase; class AttachmentStrategy; class NodeHelper; class MessagePart; class MimeMessagePart; typedef QSharedPointer MessagePartPtr; typedef QSharedPointer MimeMessagePartPtr; class MIMETREEPARSER_EXPORT ProcessResult { public: explicit ProcessResult(NodeHelper *nodeHelper, KMMsgSignatureState inlineSignatureState = KMMsgNotSigned, KMMsgEncryptionState inlineEncryptionState = KMMsgNotEncrypted, bool neverDisplayInline = false, bool isImage = false) : mInlineSignatureState(inlineSignatureState), mInlineEncryptionState(inlineEncryptionState), mNeverDisplayInline(neverDisplayInline), mIsImage(isImage), mNodeHelper(nodeHelper) {} KMMsgSignatureState inlineSignatureState() const; void setInlineSignatureState(KMMsgSignatureState state); KMMsgEncryptionState inlineEncryptionState() const; void setInlineEncryptionState(KMMsgEncryptionState state); bool neverDisplayInline() const; void setNeverDisplayInline(bool display); bool isImage() const; void setIsImage(bool image); void adjustCryptoStatesOfNode(const KMime::Content *node) const; private: KMMsgSignatureState mInlineSignatureState; KMMsgEncryptionState mInlineEncryptionState; bool mNeverDisplayInline : 1; bool mIsImage : 1; NodeHelper *mNodeHelper; }; /** \brief Parses messages and generates HTML display code out of them \par Introduction First, have a look at the documentation in Mainpage.dox and at the documentation of ViewerPrivate to understand the broader picture. Just a note on the terminology: 'Node' refers to a MIME part here, which in KMime is a KMime::Content. \par Basics The ObjectTreeParser basically has two modes: Generating the HTML code for the Viewer, or only extracting the plainTextContent() for situations where only the message text is needed, for example when inline forwarding a message. The mode depends on the Interface::ObjectTreeSource passed to the constructor: If Interface::ObjectTreeSource::htmlWriter() is not 0, then the HTML code generation mode is used. Basically, all the ObjectTreeParser does is going through the tree of MIME parts and operating on those nodes. Operating here means creating the HTML code for the node or extracting the textual content from it. This process is started with parseObjectTree(), where we loop over the subnodes of the current root node. For each of those subnodes, we try to find a BodyPartFormatter that can handle the type of the node. This can either be an internal function, such as processMultiPartAlternativeSubtype() or processTextHtmlSubtype(), or it can be an external plugin. More on external plugins later. When no matching formatter is found, defaultHandling() is called for that node. \par Multipart Nodes Those nodes that are of type multipart have subnodes. If one of those children needs to be processed normally, the processMultipartXXX() functions call stdChildHandling() for the node that should be handled normally. stdChildHandling() creates its own ObjectTreeParser, which is a clone of the current ObjectTreeParser, and processes the node. stdChildHandling() is not called for all children of the multipart node, for example processMultiPartAlternativeSubtype() only calls it on one of the children, as the other one doesn't need to be displayed. Similary, processMultiPartSignedSubtype() doesn't call stdChildHandling() for the signature node, only for the signed node. \par Processed and Unprocessed Nodes When a BodyPartFormatter has finished processing a node, it is processed. Nodes are set to being not processed at the beginning of parseObjectTree(). The processed state of a node is saved in a list in NodeHelper, see NodeHelper::setNodeProcessed(), NodeHelper::nodeProcessed() and the other related helper functions. It is the responsibility of the BodyPartFormatter to correctly call setNodeProcessed() and the related functions. This is important so that processing the same node twice can be prevented. The check that prevents duplicate processing is in parseObjectTree(). An example where duplicate processing would happen if we didn't check for it is in stdChildHandling(), which is for example called from processMultiPartAlternativeSubtype(). Let's say the setting is to prefer HTML over plain text. In this case, processMultiPartAlternativeSubtype() would call stdChildHandling() on the HTML node, which would create a new ObjectTreeParser and call parseObjectTree() on it. parseObjectTree() processes the node and all its siblings, and one of the siblings is the plain text node, which shouldn't be processed! Therefore processMultiPartAlternativeSubtype() sets the plain text node as been processed already. \par Plain Text Output Various nodes have plain text that should be displayed. This plain text is usually processed though writeBodyString() first. That method checks if the provided text is an inline PGP text and decrypts it if necessary. It also pushes the text through quotedHTML(), which does a number of things like coloring quoted lines or detecting links and creating real link tags for them. \par Modifying the Message The ObjectTreeParser does not only parse its message, in some circumstances it also modifies it before displaying. This is for example the case when displaying a decrypted message: The original message only contains a binary blob of crypto data, and processMultiPartEncryptedSubtype() decrypts that blob. After decryption, the current node is replaced with the decrypted node, which happens in insertAndParseNewChildNode(). \par Crypto Operations For signature and decryption handling, there are functions which help with generating the HTML code for the signature header and footer. These are writeDeferredDecryptionBlock(), writeSigstatFooter() and writeSigstatHeader(). As the name writeDeferredDecryptionBlock() suggests, a setting can cause the message to not be decrypted unless the user clicks a link. Whether the message should be decrypted or not can be controlled by Interface::ObjectTreeSource::decryptMessage(). When the user clicks the decryption link, the URLHandler for 'kmail:' URLs sets that variable to true and triggers an update of the Viewer, which will cause parseObjectTree() to be called again. \par Async Crypto Operations The above case describes decryption the message in place. However, decryption and also verifying of the signature can take a long time, so synchronous decryption and verifing would cause the Viewer to block. Therefore it is possible to run these operations in async mode, see allowAsync(). In the first run of the async mode, all the ObjectTreeParser does is starting the decrypt or the verify job, and informing the user that the operation is in progress with writeDecryptionInProgressBlock() or with writeSigstatHeader(). Then, it creates and associates a BodyPartMemento with the current node, for example a VerifyDetachedBodyPartMemento. Each node can have multiple mementos associated with it, which are differeniated by name. NodeHelper::setBodyPartMemento() and NodeHelper::bodyPartMemento() provide means to store and retrieve these mementos. A memento is basically a thin wrapper around the crypto job, it stores the job pointer, the job input data and the job result. Mementos can be used for any async situation, not just for crypto jobs, but I'll describe crypto jobs here. So in the first run of decrypting or verifying a message, the BodyPartFormatter only starts the crypto job, creates the BodyPartMemento and writes the HTML code that tells the user that the operation is in progress. parseObjectTree() thus finishes without waiting for anything, and the message is displayed. At some point, the crypto jobs then finish, which will cause slotResult() of the BodyPartMemento to be called. slotResult() then saves the result to some member variable and calls BodyPartMemento::notify(), which in the end will trigger an update of the Viewer. That update will, in ViewerPrivate::parseMsg(), create a new ObjectTreeParser and call parseObjectTree() on it. This is where the second run begins. The functions that deal with decrypting of verifying, like processMultiPartSignedSubtype() or processMultiPartEncryptedSubtype() will look if they find a BodyPartMemento that is associated with the current node. Now it finds that memento, since it was created in the first run. It checks if the memento's job has finished, and if so, the result can be written out (either the decrypted data or the verified signature). When dealing with encrypted nodes, new nodes are created with the decrypted data. It is important to note that the original MIME tree is never modified, and remains the same as the original one. The method createAndParseTempNode is called with the newly decrypted data, and it generates a new temporary node to store the decrypted data. When these nodes are created, it is important to keep track of them as otherwise some mementos that are added to the newly created temporary nodes will be constantly regenerated. As the regeneration triggers a viewer update when complete, it results in an infinite refresh loop. The function NodeHelper::linkAsPermanentDecrypted will create a link between the newly created node and the original parent. Conversely, the function NodeHelper::attachExtraContent will create a link in the other direction, from the parent node to the newly created temporary node. When generating some mementos for nodes that may be temporary nodes (for example, contact photo mementos), the function NodeHelper::setBodyPartMementoForPermanentParent is used. This will save the given body part memento for the closest found permanent parent node, rather than the transient node itself. Then when checking for the existence of a certain memento in a node, NodeHelper::findPermanentParentBodyPartMemento will check to see if any parent of the given temporary node is a permanent (encrypted) node that has been used to generate the asked-for node. To conclude: For async operations, parseObjectTree() is called twice: The first call starts the crypto operation and creates the BodyPartMemento, the second calls sees that the BodyPartMemento is there and can use its result for writing out the HTML. \par PartMetaData and ProcessResult For crypto operations, the class PartMetaData is used a lot, mainly to pass around info about the crypto state of a node. A PartMetaData can also be associated with a node by using NodeHelper::setPartMetaData(). The only user of that however is MessageAnalyzer::processPart() of the Nepomuk E-Mail Feeder, which also uses the ObjectTreeParser to analyze the message. You'll notice that a ProcessResult is passed to each formatter. The formatter is supposed to modify the ProcessResult to tell the callers something about the state of the nodes that were processed. One example for its use is to tell the caller about the crypto state of the node. \par BodyPartFormatter Plugins As mentioned way earlier, BodyPartFormatter can either be plugins or be internal. bodypartformatter.cpp contains some trickery so that the processXXX() methods of the ObjectTreeParser are called from a BodyPartFormatter associated with them, see the CREATE_BODY_PART_FORMATTER macro. The BodyPartFormatter code is work in progress, it was supposed to be refactored, but that has not yet happened at the time of writing. Therefore the code can seem a bit chaotic. External plugins are loaded with loadPlugins() in bodypartformatterfactory.cpp. External plugins can only use the classes in the interfaces/ directory, they include BodyPart, BodyPartMemento, BodyPartFormatterPlugin, BodyPartFormatter, BodyPartURLHandler, HtmlWriter and URLHandler. Therefore external plugins have powerful capabilities, which are needed for example in the iCal formatter or in the vCard formatter. \par Special HTML tags As also mentioned in the documentation of ViewerPrivate, the ObjectTreeParser writes out special links that are only understood by the viewer, for example 'kmail:' URLs or 'attachment:' URLs. Also, some special HTML tags are created, which the Viewer later uses for post-processing. For example a div with the id 'attachmentInjectionPoint', or a div with the id 'attachmentDiv', which is used to mark an attachment in the body with a yellow border when the user clicks the attachment in the header. Finally, parseObjectTree() creates an anchor with the id 'att%1', which is used in the Viewer to scroll to the attachment. */ class MIMETREEPARSER_EXPORT ObjectTreeParser { /** * @internal * Copies the context of @p other, but not it's rawDecryptedBody, plainTextContent or htmlContent. */ ObjectTreeParser(const ObjectTreeParser &other); public: explicit ObjectTreeParser(Interface::ObjectTreeSource *source, NodeHelper *nodeHelper = 0, bool showOneMimePart = false, const AttachmentStrategy *attachmentStrategy = Q_NULLPTR); explicit ObjectTreeParser(const ObjectTreeParser *topLevelParser, bool showOneMimePart = false, const AttachmentStrategy *attachmentStrategy = Q_NULLPTR); virtual ~ObjectTreeParser(); void setAllowAsync(bool allow); bool allowAsync() const; bool hasPendingAsyncJobs() const; /** * The text of the message, ie. what would appear in the * composer's text editor if this was edited or replied to. * This is usually the content of the first text/plain MIME part. */ QString plainTextContent() const; /** * Similar to plainTextContent(), but returns the HTML source of the first text/html MIME part. * * Not to be consfused with the HTML code that the message viewer widget displays, that HTML * is written out by htmlWriter() and a totally different pair of shoes. */ QString htmlContent() const; /** * The original charset of MIME part the plain text was extracted from. * * If there were more than one text/plain MIME parts in the mail, the this is the charset * of the last MIME part processed. */ QByteArray plainTextContentCharset() const; QByteArray htmlContentCharset() const; bool showOnlyOneMimePart() const; void setShowOnlyOneMimePart(bool show); const AttachmentStrategy *attachmentStrategy() const; HtmlWriter *htmlWriter() const; - CSSHelperBase *cssHelper() const; - NodeHelper *nodeHelper() const; /** Parse beginning at a given node and recursively parsing the children of that node and it's next sibling. */ void parseObjectTree(KMime::Content *node); MessagePartPtr parsedPart() const; void setPrinting(bool printing); bool printing() const; private: void extractNodeInfos(KMime::Content *curNode, bool isFirstTextPart); void setPlainTextContent(QString plainTextContent); /** * Does the actual work for parseObjectTree. Unlike parseObjectTree(), this does not change the * top-level content. */ MessagePartPtr parseObjectTreeInternal(KMime::Content *node); bool processType(KMime::Content *node, MimeTreeParser::ProcessResult &processResult, const QByteArray &mediaType, const QByteArray &subType, Interface::MessagePartPtr &mpRet); Interface::MessagePartPtr defaultHandling(KMime::Content *node, ProcessResult &result); private: /** ctor helper */ void init(); const QTextCodec *codecFor(KMime::Content *node) const; void copyContentFrom(const ObjectTreeParser *other); private: Interface::ObjectTreeSource *mSource; NodeHelper *mNodeHelper; HtmlWriter *mHtmlWriter; QByteArray mPlainTextContentCharset; QByteArray mHtmlContentCharset; QString mPlainTextContent; QString mHtmlContent; KMime::Content *mTopLevelContent; MessagePartPtr mParsedPart; /// Show only one mime part means that the user has selected some node in the message structure /// viewer that is not the root, which means the user wants to only see the selected node and its /// children. If that is the case, this variable is set to true. /// The code needs to behave differently if this is set. For example, it should not process the /// siblings. Also, consider inline images: Normally, those nodes are completely hidden, as the /// HTML node embedds them. However, when showing only the node of the image, one has to show them, /// as their is no HTML node in which they are displayed. There are many more cases where this /// variable needs to be obeyed. /// This variable is set to false again when processing the children in stdChildHandling(), as /// the children can be completely displayed again. bool mShowOnlyOneMimePart; bool mHasPendingAsyncJobs; bool mAllowAsync; const AttachmentStrategy *mAttachmentStrategy; // DataUrl Icons cache QString mCollapseIcon; QString mExpandIcon; bool mDeleteNodeHelper; bool mPrinting; friend class PartNodeBodyPart; friend class MessagePart; friend class CryptoMessagePart; friend class EncapsulatedRfc822MessagePart; friend class TextMessagePart; friend class HtmlMessagePart; friend class TextPlainBodyPartFormatter; friend class MultiPartSignedBodyPartFormatter; friend class ApplicationPkcs7MimeBodyPartFormatter; }; } #endif // __MIMETREEPARSER_OBJECTTREEPARSER_H__