summaryrefslogtreecommitdiffstats
path: root/framework/src
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2017-05-23 19:13:13 +0200
committerChristian Mollekopf <chrigi_1@fastmail.fm>2017-05-23 19:13:13 +0200
commitb968ea8ed364238c57c3e74cf2c122cb897cfbea (patch)
tree7a2dca2199906413a2d0b7d075ded0e4d5ffb69f /framework/src
parentc1ca732bafc60f5c140ef5516e32bd46503bf68c (diff)
downloadkube-b968ea8ed364238c57c3e74cf2c122cb897cfbea.tar.gz
kube-b968ea8ed364238c57c3e74cf2c122cb897cfbea.zip
Builds but doesn't link, no formatters yet
Diffstat (limited to 'framework/src')
-rw-r--r--framework/src/CMakeLists.txt5
-rw-r--r--framework/src/domain/mailtemplates.cpp2
-rw-r--r--framework/src/domain/mimetreeparser/CMakeLists.txt8
-rw-r--r--framework/src/domain/mimetreeparser/interface.cpp6
-rw-r--r--framework/src/domain/mimetreeparser/objecttreesource.cpp8
-rw-r--r--framework/src/domain/mimetreeparser/objecttreesource.h2
-rw-r--r--framework/src/domain/mimetreeparser/otp/CMakeLists.txt180
-rw-r--r--framework/src/domain/mimetreeparser/otp/attachmentstrategy.cpp343
-rw-r--r--framework/src/domain/mimetreeparser/otp/attachmentstrategy.h86
-rw-r--r--framework/src/domain/mimetreeparser/otp/attachmenttemporaryfilesdirs.cpp108
-rw-r--r--framework/src/domain/mimetreeparser/otp/attachmenttemporaryfilesdirs.h57
-rw-r--r--framework/src/domain/mimetreeparser/otp/bodypart.cpp41
-rw-r--r--framework/src/domain/mimetreeparser/otp/bodypart.h209
-rw-r--r--framework/src/domain/mimetreeparser/otp/bodypartformatter.cpp147
-rw-r--r--framework/src/domain/mimetreeparser/otp/bodypartformatter.h149
-rw-r--r--framework/src/domain/mimetreeparser/otp/bodypartformatterbasefactory.cpp208
-rw-r--r--framework/src/domain/mimetreeparser/otp/bodypartformatterbasefactory.h85
-rw-r--r--framework/src/domain/mimetreeparser/otp/bodypartformatterbasefactory_p.h57
-rw-r--r--framework/src/domain/mimetreeparser/otp/cryptobodypartmemento.cpp56
-rw-r--r--framework/src/domain/mimetreeparser/otp/cryptobodypartmemento.h75
-rw-r--r--framework/src/domain/mimetreeparser/otp/cryptohelper.cpp150
-rw-r--r--framework/src/domain/mimetreeparser/otp/cryptohelper.h62
-rw-r--r--framework/src/domain/mimetreeparser/otp/decryptverifybodypartmemento.cpp86
-rw-r--r--framework/src/domain/mimetreeparser/otp/decryptverifybodypartmemento.h81
-rw-r--r--framework/src/domain/mimetreeparser/otp/enums.h54
-rw-r--r--framework/src/domain/mimetreeparser/otp/filehtmlwriter.cpp119
-rw-r--r--framework/src/domain/mimetreeparser/otp/filehtmlwriter.h70
-rw-r--r--framework/src/domain/mimetreeparser/otp/htmlwriter.cpp40
-rw-r--r--framework/src/domain/mimetreeparser/otp/htmlwriter.h125
-rw-r--r--framework/src/domain/mimetreeparser/otp/messagepart.cpp1352
-rw-r--r--framework/src/domain/mimetreeparser/otp/messagepart.h422
-rw-r--r--framework/src/domain/mimetreeparser/otp/messagepartrenderer.cpp23
-rw-r--r--framework/src/domain/mimetreeparser/otp/messagepartrenderer.h43
-rw-r--r--framework/src/domain/mimetreeparser/otp/mimetreeparser_debug.cpp3
-rw-r--r--framework/src/domain/mimetreeparser/otp/mimetreeparser_debug.h4
-rw-r--r--framework/src/domain/mimetreeparser/otp/nodehelper.cpp1069
-rw-r--r--framework/src/domain/mimetreeparser/otp/nodehelper.h290
-rw-r--r--framework/src/domain/mimetreeparser/otp/objecttreeparser.cpp495
-rw-r--r--framework/src/domain/mimetreeparser/otp/objecttreeparser.h406
-rw-r--r--framework/src/domain/mimetreeparser/otp/objecttreesource.cpp28
-rw-r--r--framework/src/domain/mimetreeparser/otp/objecttreesource.h109
-rw-r--r--framework/src/domain/mimetreeparser/otp/partmetadata.h67
-rw-r--r--framework/src/domain/mimetreeparser/otp/partnodebodypart.cpp125
-rw-r--r--framework/src/domain/mimetreeparser/otp/partnodebodypart.h108
-rw-r--r--framework/src/domain/mimetreeparser/otp/qgpgmejobexecutor.cpp158
-rw-r--r--framework/src/domain/mimetreeparser/otp/qgpgmejobexecutor.h86
-rw-r--r--framework/src/domain/mimetreeparser/otp/queuehtmlwriter.cpp136
-rw-r--r--framework/src/domain/mimetreeparser/otp/queuehtmlwriter.h75
-rw-r--r--framework/src/domain/mimetreeparser/otp/util.cpp136
-rw-r--r--framework/src/domain/mimetreeparser/otp/util.h67
-rw-r--r--framework/src/domain/mimetreeparser/otp/utils.cpp70
-rw-r--r--framework/src/domain/mimetreeparser/otp/utils.h42
-rw-r--r--framework/src/domain/mimetreeparser/otp/verifydetachedbodypartmemento.cpp177
-rw-r--r--framework/src/domain/mimetreeparser/otp/verifydetachedbodypartmemento.h87
-rw-r--r--framework/src/domain/mimetreeparser/otp/verifyopaquebodypartmemento.cpp179
-rw-r--r--framework/src/domain/mimetreeparser/otp/verifyopaquebodypartmemento.h93
-rw-r--r--framework/src/domain/mimetreeparser/stringhtmlwriter.h2
-rw-r--r--framework/src/domain/mimetreeparser/tests/CMakeLists.txt18
-rw-r--r--framework/src/domain/objecttreesource.cpp8
-rw-r--r--framework/src/domain/objecttreesource.h2
-rw-r--r--framework/src/domain/stringhtmlwriter.h2
61 files changed, 8470 insertions, 31 deletions
diff --git a/framework/src/CMakeLists.txt b/framework/src/CMakeLists.txt
index 54dcd4dc..37cb9640 100644
--- a/framework/src/CMakeLists.txt
+++ b/framework/src/CMakeLists.txt
@@ -1,6 +1,5 @@
1 1
2find_package(Qt5 COMPONENTS REQUIRED Core Qml) 2find_package(Qt5 COMPONENTS REQUIRED Core Qml)
3find_package(KF5MimeTreeParser "5.1.46" CONFIG REQUIRED)
4find_package(KF5Mime "4.87.0" CONFIG REQUIRED) 3find_package(KF5Mime "4.87.0" CONFIG REQUIRED)
5find_package(Sink CONFIG REQUIRED) 4find_package(Sink CONFIG REQUIRED)
6find_package(KAsync CONFIG REQUIRED) 5find_package(KAsync CONFIG REQUIRED)
@@ -10,7 +9,7 @@ find_package(KF5Package CONFIG REQUIRED)
10 9
11add_definitions("-Wall -std=c++0x -g") 10add_definitions("-Wall -std=c++0x -g")
12 11
13include_directories(.) 12include_directories(. domain/mimetreeparser)
14 13
15set(SRCS 14set(SRCS
16 frameworkplugin.cpp 15 frameworkplugin.cpp
@@ -45,7 +44,7 @@ set(SRCS
45 44
46add_library(frameworkplugin SHARED ${SRCS}) 45add_library(frameworkplugin SHARED ${SRCS})
47qt5_use_modules(frameworkplugin Core Quick Qml WebEngineWidgets Test) 46qt5_use_modules(frameworkplugin Core Quick Qml WebEngineWidgets Test)
48target_link_libraries(frameworkplugin sink mimetreeparser KF5::MimeTreeParser KF5::Codecs KF5::Package KAsync) 47target_link_libraries(frameworkplugin sink mimetreeparser KF5::Codecs KF5::Package KAsync)
49install(TARGETS frameworkplugin DESTINATION ${FRAMEWORK_INSTALL_DIR}) 48install(TARGETS frameworkplugin DESTINATION ${FRAMEWORK_INSTALL_DIR})
50 49
51add_subdirectory(domain/mimetreeparser) 50add_subdirectory(domain/mimetreeparser)
diff --git a/framework/src/domain/mailtemplates.cpp b/framework/src/domain/mailtemplates.cpp
index 43e169de..254dbba3 100644
--- a/framework/src/domain/mailtemplates.cpp
+++ b/framework/src/domain/mailtemplates.cpp
@@ -37,7 +37,7 @@
37#include "stringhtmlwriter.h" 37#include "stringhtmlwriter.h"
38#include "objecttreesource.h" 38#include "objecttreesource.h"
39 39
40#include <MimeTreeParser/ObjectTreeParser> 40#include <otp/objecttreeparser.h>
41 41
42namespace KMime { 42namespace KMime {
43 namespace Types { 43 namespace Types {
diff --git a/framework/src/domain/mimetreeparser/CMakeLists.txt b/framework/src/domain/mimetreeparser/CMakeLists.txt
index 64da2656..517fb7e5 100644
--- a/framework/src/domain/mimetreeparser/CMakeLists.txt
+++ b/framework/src/domain/mimetreeparser/CMakeLists.txt
@@ -1,3 +1,5 @@
1include_directories(.)
2
1set(mimetreeparser_SRCS 3set(mimetreeparser_SRCS
2 interface.cpp 4 interface.cpp
3 objecttreesource.cpp 5 objecttreesource.cpp
@@ -7,9 +9,9 @@ set(mimetreeparser_SRCS
7add_library(mimetreeparser SHARED ${mimetreeparser_SRCS}) 9add_library(mimetreeparser SHARED ${mimetreeparser_SRCS})
8 10
9qt5_use_modules(mimetreeparser Core Gui) 11qt5_use_modules(mimetreeparser Core Gui)
10target_link_libraries(mimetreeparser KF5::Mime KF5::MimeTreeParser) 12target_link_libraries(mimetreeparser KF5::Mime kube_otp)
11 13
12install(TARGETS mimetreeparser 14install(TARGETS mimetreeparser DESTINATION ${LIB_INSTALL_DIR})
13 DESTINATION ${LIB_INSTALL_DIR})
14 15
15add_subdirectory(tests) 16add_subdirectory(tests)
17add_subdirectory(otp)
diff --git a/framework/src/domain/mimetreeparser/interface.cpp b/framework/src/domain/mimetreeparser/interface.cpp
index 663a2013..b8556336 100644
--- a/framework/src/domain/mimetreeparser/interface.cpp
+++ b/framework/src/domain/mimetreeparser/interface.cpp
@@ -29,9 +29,9 @@
29#include <gpgme++/keylistresult.h> 29#include <gpgme++/keylistresult.h>
30 30
31#include <KMime/Content> 31#include <KMime/Content>
32#include <MimeTreeParser/ObjectTreeParser> 32#include <otp/objecttreeparser.h>
33#include <MimeTreeParser/MessagePart> 33#include <otp/messagepart.h>
34#include <MimeTreeParser/NodeHelper> 34#include <otp/nodehelper.h>
35 35
36#include <QMimeDatabase> 36#include <QMimeDatabase>
37#include <QMimeType> 37#include <QMimeType>
diff --git a/framework/src/domain/mimetreeparser/objecttreesource.cpp b/framework/src/domain/mimetreeparser/objecttreesource.cpp
index 567f3516..186fdf80 100644
--- a/framework/src/domain/mimetreeparser/objecttreesource.cpp
+++ b/framework/src/domain/mimetreeparser/objecttreesource.cpp
@@ -19,10 +19,10 @@
19 19
20#include "objecttreesource.h" 20#include "objecttreesource.h"
21 21
22#include <MimeTreeParser/AttachmentStrategy> 22#include <otp/attachmentstrategy.h>
23#include <MimeTreeParser/BodyPartFormatterBaseFactory> 23#include <otp/bodypartformatterbasefactory.h>
24#include <MimeTreeParser/MessagePart> 24#include <otp/messagepart.h>
25#include <MimeTreeParser/MessagePartRenderer> 25#include <otp/messagepartrenderer.h>
26 26
27class ObjectSourcePrivate 27class ObjectSourcePrivate
28{ 28{
diff --git a/framework/src/domain/mimetreeparser/objecttreesource.h b/framework/src/domain/mimetreeparser/objecttreesource.h
index 93812dc3..2167e06f 100644
--- a/framework/src/domain/mimetreeparser/objecttreesource.h
+++ b/framework/src/domain/mimetreeparser/objecttreesource.h
@@ -20,7 +20,7 @@
20#ifndef MAILVIEWER_OBJECTTREEEMPTYSOURCE_H 20#ifndef MAILVIEWER_OBJECTTREEEMPTYSOURCE_H
21#define MAILVIEWER_OBJECTTREEEMPTYSOURCE_H 21#define MAILVIEWER_OBJECTTREEEMPTYSOURCE_H
22 22
23#include <MimeTreeParser/ObjectTreeSource> 23#include <otp/objecttreesource.h>
24 24
25class QString; 25class QString;
26 26
diff --git a/framework/src/domain/mimetreeparser/otp/CMakeLists.txt b/framework/src/domain/mimetreeparser/otp/CMakeLists.txt
new file mode 100644
index 00000000..fcbe574f
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/CMakeLists.txt
@@ -0,0 +1,180 @@
1add_definitions( -DQT_NO_CAST_FROM_ASCII )
2add_definitions( -DQT_NO_CAST_TO_ASCII )
3add_definitions("-fvisibility=default")
4
5find_package(Qt5 COMPONENTS REQUIRED Core Gui)
6find_package(KF5Mime "4.87.0" CONFIG REQUIRED)
7find_package(QGpgme CONFIG REQUIRED)
8find_package(KF5Codecs CONFIG REQUIRED)
9find_package(KF5Package CONFIG REQUIRED)
10find_package(KF5I18n CONFIG REQUIRED)
11
12#add_definitions(-DTRANSLATION_DOMAIN=\"libmimetreeparser\")
13
14# target_include_directories does not handle empty include paths
15include_directories(${GPGME_INCLUDES})
16
17set(libmimetreeparser_main_SRCS
18 objecttreeparser.cpp
19 #bodyformatter/applicationpgpencrypted.cpp
20 #bodyformatter/applicationpkcs7mime.cpp
21 #bodyformatter/mailman.cpp
22 #bodyformatter/multipartalternative.cpp
23 #bodyformatter/multipartencrypted.cpp
24 #bodyformatter/multipartmixed.cpp
25 #bodyformatter/multipartsigned.cpp
26 #bodyformatter/textplain.cpp
27 #bodyformatter/texthtml.cpp
28 #bodyformatter/utils.cpp
29
30 #Interfaces
31 bodypartformatter.cpp
32 objecttreesource.cpp
33 bodypart.cpp
34 htmlwriter.cpp
35 messagepartrenderer.cpp
36
37 #bodypartformatter.cpp
38 bodypartformatterbasefactory.cpp
39 cryptohelper.cpp
40 nodehelper.cpp
41 messagepart.cpp
42 utils.cpp
43 partnodebodypart.cpp
44 #Mementos
45 cryptobodypartmemento.cpp
46 decryptverifybodypartmemento.cpp
47 verifydetachedbodypartmemento.cpp
48 verifyopaquebodypartmemento.cpp
49 #Stuff
50 mimetreeparser_debug.cpp
51 qgpgmejobexecutor.cpp
52 util.cpp
53 attachmentstrategy.cpp
54 #HTML Writer
55 queuehtmlwriter.cpp
56 # htmlwriter/filehtmlwriter.cpp
57 attachmenttemporaryfilesdirs.cpp
58 )
59
60#ecm_generate_headers(MimeTreeParser_Camelcaseviewer_HEADERS
61# HEADER_NAMES
62# AttachmentStrategy
63# BodyPartFormatterBaseFactory
64# Enums
65# MessagePart
66# NodeHelper
67# ObjectTreeParser
68# PartMetaData
69# PartNodeBodyPart
70# REQUIRED_HEADERS MimeTreeParser_viewer_HEADERS
71# PREFIX MimeTreeParser
72# RELATIVE viewer
73# )
74#
75#ecm_generate_headers(MimeTreeParser_Camelcaseutils_HEADERS
76# HEADER_NAMES
77# Util
78# REQUIRED_HEADERS MimeTreeParser_utils_HEADERS
79# PREFIX MimeTreeParser
80# RELATIVE utils
81# )
82#
83#ecm_generate_headers(MimeTreeParser_Camelcaseinterfaces_HEADERS
84# HEADER_NAMES
85# BodyPartFormatter
86# BodyPart
87# HtmlWriter
88# MessagePartRenderer
89# ObjectTreeSource
90# REQUIRED_HEADERS MimeTreeParser_interfaces_HEADERS
91# PREFIX MimeTreeParser
92# RELATIVE interfaces
93# )
94#
95#ecm_generate_headers(MimeTreeParser_Camelcasehtmlwriter_HEADERS
96# HEADER_NAMES
97# FileHtmlWriter
98# QueueHtmlWriter
99# REQUIRED_HEADERS MimeTreeParser_htmlwriter_HEADERS
100# PREFIX MimeTreeParser
101# RELATIVE htmlwriter
102# )
103#
104#ecm_generate_headers(MimeTreeParser_Camelcasetemporaryfile_HEADERS
105# HEADER_NAMES
106# AttachmentTemporaryFilesDirs
107# REQUIRED_HEADERS MimeTreeParser_temporaryfile_HEADERS
108# PREFIX MimeTreeParser
109# RELATIVE temporaryfile
110# )
111
112#install(FILES
113# ${MimeTreeParser_Camelcasehtmlwriter_HEADERS}
114# ${MimeTreeParser_Camelcaseutils_HEADERS}
115# ${MimeTreeParser_Camelcaseinterfaces_HEADERS}
116# ${MimeTreeParser_Camelcaseviewer_HEADERS}
117# ${MimeTreeParser_Camelcasetemporaryfile_HEADERS}
118# DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/MimeTreeParser
119# COMPONENT Devel
120# )
121#
122#install(FILES
123# ${MimeTreeParser_htmlwriter_HEADERS}
124# ${MimeTreeParser_utils_HEADERS}
125# ${MimeTreeParser_interfaces_HEADERS}
126# ${MimeTreeParser_viewer_HEADERS}
127# ${MimeTreeParser_temporaryfile_HEADERS}
128# ${CMAKE_CURRENT_BINARY_DIR}/mimetreeparser_export.h
129# ${CMAKE_CURRENT_BINARY_DIR}/mimetreeparser_debug.h
130#
131# DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/mimetreeparser
132# COMPONENT Devel
133# )
134#
135#ecm_generate_pri_file(BASE_NAME MimeTreeParser
136# LIB_NAME KF5MimeTreeParser
137# FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/MimeTreeParser
138# )
139#
140#install(FILES
141# ${PRI_FILENAME}
142# DESTINATION ${ECM_MKSPECS_INSTALL_DIR}
143# )
144
145set(libmimetreeparser_SRCS
146 ${libmimetreeparser_main_SRCS}
147 )
148
149#ecm_qt_declare_logging_category(libmimetreeparser_SRCS HEADER mimetreeparser_debug.h IDENTIFIER MIMETREEPARSER_LOG CATEGORY_NAME org.kde.pim.mimetreeparser)
150
151add_library(kube_otp ${libmimetreeparser_SRCS})
152
153#generate_export_header(KF5MimeTreeParser BASE_NAME mimetreeparser)
154
155#set(mimetreeparser_LINK_LIBRARIES
156# )
157
158target_link_libraries(kube_otp
159 PRIVATE
160 QGpgme
161 KF5::Codecs
162 KF5::I18n
163 KF5::Mime
164 Qt5::Gui
165 )
166install(TARGETS kube_otp DESTINATION ${LIB_INSTALL_DIR})
167
168#install(TARGETS
169# KF5MimeTreeParser
170# EXPORT KF5MimeTreeParserTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS} ${LIBRARY_NAMELINK}
171# )
172#
173#set_target_properties(KF5MimeTreeParser PROPERTIES
174# VERSION ${MIMETREEPARSER_VERSION_STRING}
175# SOVERSION ${MIMETREEPARSER_SOVERSION}
176# EXPORT_NAME MimeTreeParser
177# )
178#
179#target_include_directories(KF5MimeTreeParser INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR_KF5}/MimeTreeParser/;${KDE_INSTALL_INCLUDEDIR_KF5}/mimetreeparser>")
180#
diff --git a/framework/src/domain/mimetreeparser/otp/attachmentstrategy.cpp b/framework/src/domain/mimetreeparser/otp/attachmentstrategy.cpp
new file mode 100644
index 00000000..5ea21133
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/attachmentstrategy.cpp
@@ -0,0 +1,343 @@
1/* -*- c++ -*-
2 attachmentstrategy.cpp
3
4 This file is part of KMail, the KDE mail client.
5 Copyright (c) 2003 Marc Mutz <mutz@kde.org>
6 Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
7 Copyright (c) 2009 Andras Mantia <andras@kdab.net>
8
9 KMail is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License, version 2, as
11 published by the Free Software Foundation.
12
13 KMail is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
22 In addition, as a special exception, the copyright holders give
23 permission to link the code of this program with any edition of
24 the Qt library by Trolltech AS, Norway (or with modified versions
25 of Qt that use the same license as Qt), and distribute linked
26 combinations including the two. You must obey the GNU General
27 Public License in all respects for all of the code used other than
28 Qt. If you modify this file, you may extend this exception to
29 your version of the file, but you are not obligated to do so. If
30 you do not wish to do so, delete this exception statement from
31 your version.
32*/
33
34#include "attachmentstrategy.h"
35
36#include "nodehelper.h"
37#include "util.h"
38
39#include <KMime/Content>
40
41#include <QIcon>
42
43#include "mimetreeparser_debug.h"
44
45using namespace MimeTreeParser;
46
47static AttachmentStrategy::Display smartDisplay(KMime::Content *node)
48{
49 const auto cd = node->contentDisposition(false);
50
51 if (cd && cd->disposition() == KMime::Headers::CDinline)
52 // explict "inline" disposition:
53 {
54 return AttachmentStrategy::Inline;
55 }
56 if (cd && cd->disposition() == KMime::Headers::CDattachment)
57 // explicit "attachment" disposition:
58 {
59 return AttachmentStrategy::AsIcon;
60 }
61
62 const auto ct = node->contentType(false);
63 if (ct && ct->isText() && ct->name().trimmed().isEmpty() &&
64 (!cd || cd->filename().trimmed().isEmpty()))
65 // text/* w/o filename parameter:
66 {
67 return AttachmentStrategy::Inline;
68 }
69 return AttachmentStrategy::AsIcon;
70}
71
72//
73// IconicAttachmentStrategy:
74// show everything but the first text/plain body as icons
75//
76
77class IconicAttachmentStrategy : public AttachmentStrategy
78{
79 friend class AttachmentStrategy;
80protected:
81 IconicAttachmentStrategy() : AttachmentStrategy() {}
82 virtual ~IconicAttachmentStrategy() {}
83
84public:
85 const char *name() const Q_DECL_OVERRIDE
86 {
87 return "iconic";
88 }
89
90 bool inlineNestedMessages() const Q_DECL_OVERRIDE
91 {
92 return false;
93 }
94 Display defaultDisplay(KMime::Content *node) const Q_DECL_OVERRIDE
95 {
96 if (node->contentType()->isText() &&
97 node->contentDisposition()->filename().trimmed().isEmpty() &&
98 node->contentType()->name().trimmed().isEmpty())
99 // text/* w/o filename parameter:
100 {
101 return Inline;
102 }
103 return AsIcon;
104 }
105};
106
107//
108// SmartAttachmentStrategy:
109// in addition to Iconic, show all body parts
110// with content-disposition == "inline" and
111// all text parts without a filename or name parameter inline
112//
113
114class SmartAttachmentStrategy : public AttachmentStrategy
115{
116 friend class AttachmentStrategy;
117protected:
118 SmartAttachmentStrategy() : AttachmentStrategy() {}
119 virtual ~SmartAttachmentStrategy() {}
120
121public:
122 const char *name() const Q_DECL_OVERRIDE
123 {
124 return "smart";
125 }
126
127 bool inlineNestedMessages() const Q_DECL_OVERRIDE
128 {
129 return true;
130 }
131 Display defaultDisplay(KMime::Content *node) const Q_DECL_OVERRIDE
132 {
133 return smartDisplay(node);
134 }
135};
136
137//
138// InlinedAttachmentStrategy:
139// show everything possible inline
140//
141
142class InlinedAttachmentStrategy : public AttachmentStrategy
143{
144 friend class AttachmentStrategy;
145protected:
146 InlinedAttachmentStrategy() : AttachmentStrategy() {}
147 virtual ~InlinedAttachmentStrategy() {}
148
149public:
150 const char *name() const Q_DECL_OVERRIDE
151 {
152 return "inlined";
153 }
154
155 bool inlineNestedMessages() const Q_DECL_OVERRIDE
156 {
157 return true;
158 }
159 Display defaultDisplay(KMime::Content *) const Q_DECL_OVERRIDE
160 {
161 return Inline;
162 }
163};
164
165//
166// HiddenAttachmentStrategy
167// show nothing except the first text/plain body part _at all_
168//
169
170class HiddenAttachmentStrategy : public AttachmentStrategy
171{
172 friend class AttachmentStrategy;
173protected:
174 HiddenAttachmentStrategy() : AttachmentStrategy() {}
175 virtual ~HiddenAttachmentStrategy() {}
176
177public:
178 const char *name() const Q_DECL_OVERRIDE
179 {
180 return "hidden";
181 }
182
183 bool inlineNestedMessages() const Q_DECL_OVERRIDE
184 {
185 return false;
186 }
187 Display defaultDisplay(KMime::Content *node) const Q_DECL_OVERRIDE
188 {
189 if (node->contentType()->isText() &&
190 node->contentDisposition()->filename().trimmed().isEmpty() &&
191 node->contentType()->name().trimmed().isEmpty())
192 // text/* w/o filename parameter:
193 {
194 return Inline;
195 }
196 if (!node->parent()) {
197 return Inline;
198 }
199
200 if (node->parent() && node->parent()->contentType()->isMultipart() &&
201 node->parent()->contentType()->subType() == "related") {
202 return Inline;
203 }
204
205 return None;
206 }
207};
208
209class HeaderOnlyAttachmentStrategy : public AttachmentStrategy
210{
211 friend class AttachmentStrategy;
212protected:
213 HeaderOnlyAttachmentStrategy() : AttachmentStrategy() {}
214 virtual ~HeaderOnlyAttachmentStrategy() {}
215
216public:
217 const char *name() const Q_DECL_OVERRIDE
218 {
219 return "headerOnly";
220 }
221
222 bool inlineNestedMessages() const Q_DECL_OVERRIDE
223 {
224 return true;
225 }
226
227 Display defaultDisplay(KMime::Content *node) const Q_DECL_OVERRIDE
228 {
229 if (NodeHelper::isInEncapsulatedMessage(node)) {
230 return smartDisplay(node);
231 }
232
233 if (!Util::labelForContent(node).isEmpty() && QIcon::hasThemeIcon(Util::iconNameForContent(node)) && ! Util::isTypeBlacklisted(node)) {
234 return None;
235 }
236 return smartDisplay(node);
237 }
238
239 bool requiresAttachmentListInHeader() const Q_DECL_OVERRIDE
240 {
241 return true;
242 }
243};
244
245//
246// AttachmentStrategy abstract base:
247//
248
249AttachmentStrategy::AttachmentStrategy()
250{
251
252}
253
254AttachmentStrategy::~AttachmentStrategy()
255{
256
257}
258
259const AttachmentStrategy *AttachmentStrategy::create(Type type)
260{
261 switch (type) {
262 case Iconic: return iconic();
263 case Smart: return smart();
264 case Inlined: return inlined();
265 case Hidden: return hidden();
266 case HeaderOnly: return headerOnly();
267 }
268 qCCritical(MIMETREEPARSER_LOG) << "Unknown attachment startegy ( type =="
269 << (int)type << ") requested!";
270 return nullptr; // make compiler happy
271}
272
273const AttachmentStrategy *AttachmentStrategy::create(const QString &type)
274{
275 const QString lowerType = type.toLower();
276 if (lowerType == QLatin1String("iconic")) {
277 return iconic();
278 }
279 //if ( lowerType == "smart" ) return smart(); // not needed, see below
280 if (lowerType == QLatin1String("inlined")) {
281 return inlined();
282 }
283 if (lowerType == QLatin1String("hidden")) {
284 return hidden();
285 }
286 if (lowerType == QLatin1String("headeronly")) {
287 return headerOnly();
288 }
289 // don't kFatal here, b/c the strings are user-provided
290 // (KConfig), so fail gracefully to the default:
291 return smart();
292}
293
294static const AttachmentStrategy *iconicStrategy = nullptr;
295static const AttachmentStrategy *smartStrategy = nullptr;
296static const AttachmentStrategy *inlinedStrategy = nullptr;
297static const AttachmentStrategy *hiddenStrategy = nullptr;
298static const AttachmentStrategy *headerOnlyStrategy = nullptr;
299
300const AttachmentStrategy *AttachmentStrategy::iconic()
301{
302 if (!iconicStrategy) {
303 iconicStrategy = new IconicAttachmentStrategy();
304 }
305 return iconicStrategy;
306}
307
308const AttachmentStrategy *AttachmentStrategy::smart()
309{
310 if (!smartStrategy) {
311 smartStrategy = new SmartAttachmentStrategy();
312 }
313 return smartStrategy;
314}
315
316const AttachmentStrategy *AttachmentStrategy::inlined()
317{
318 if (!inlinedStrategy) {
319 inlinedStrategy = new InlinedAttachmentStrategy();
320 }
321 return inlinedStrategy;
322}
323
324const AttachmentStrategy *AttachmentStrategy::hidden()
325{
326 if (!hiddenStrategy) {
327 hiddenStrategy = new HiddenAttachmentStrategy();
328 }
329 return hiddenStrategy;
330}
331
332const AttachmentStrategy *AttachmentStrategy::headerOnly()
333{
334 if (!headerOnlyStrategy) {
335 headerOnlyStrategy = new HeaderOnlyAttachmentStrategy();
336 }
337 return headerOnlyStrategy;
338}
339
340bool AttachmentStrategy::requiresAttachmentListInHeader() const
341{
342 return false;
343}
diff --git a/framework/src/domain/mimetreeparser/otp/attachmentstrategy.h b/framework/src/domain/mimetreeparser/otp/attachmentstrategy.h
new file mode 100644
index 00000000..a0b5dc81
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/attachmentstrategy.h
@@ -0,0 +1,86 @@
1/* -*- c++ -*-
2 attachmentstrategy.h
3
4 This file is part of KMail, the KDE mail client.
5 Copyright (c) 2003 Marc Mutz <mutz@kde.org>
6 Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
7 Copyright (c) 2009 Andras Mantia <andras@kdab.net>
8
9 KMail is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License, version 2, as
11 published by the Free Software Foundation.
12
13 KMail is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
22 In addition, as a special exception, the copyright holders give
23 permission to link the code of this program with any edition of
24 the Qt library by Trolltech AS, Norway (or with modified versions
25 of Qt that use the same license as Qt), and distribute linked
26 combinations including the two. You must obey the GNU General
27 Public License in all respects for all of the code used other than
28 Qt. If you modify this file, you may extend this exception to
29 your version of the file, but you are not obligated to do so. If
30 you do not wish to do so, delete this exception statement from
31 your version.
32*/
33
34#ifndef __MIMETREEPARSER_ATTACHMENTSTRATEGY_H__
35#define __MIMETREEPARSER_ATTACHMENTSTRATEGY_H__
36
37class QString;
38namespace KMime
39{
40class Content;
41}
42
43namespace MimeTreeParser
44{
45
46class AttachmentStrategy
47{
48protected:
49 AttachmentStrategy();
50 virtual ~AttachmentStrategy();
51
52public:
53 //
54 // Factory methods:
55 //
56 enum Type { Iconic, Smart, Inlined, Hidden, HeaderOnly };
57
58 static const AttachmentStrategy *create(Type type);
59 static const AttachmentStrategy *create(const QString &type);
60
61 static const AttachmentStrategy *iconic();
62 static const AttachmentStrategy *smart();
63 static const AttachmentStrategy *inlined();
64 static const AttachmentStrategy *hidden();
65 static const AttachmentStrategy *headerOnly();
66
67 //
68 // Navigation methods:
69 //
70
71 virtual const char *name() const = 0;
72
73 //
74 // Bahavioural:
75 //
76
77 enum Display { None, AsIcon, Inline };
78
79 virtual bool inlineNestedMessages() const = 0;
80 virtual Display defaultDisplay(KMime::Content *node) const = 0;
81 virtual bool requiresAttachmentListInHeader() const;
82};
83
84}
85
86#endif // __MIMETREEPARSER_ATTACHMENTSTRATEGY_H__
diff --git a/framework/src/domain/mimetreeparser/otp/attachmenttemporaryfilesdirs.cpp b/framework/src/domain/mimetreeparser/otp/attachmenttemporaryfilesdirs.cpp
new file mode 100644
index 00000000..364bc422
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/attachmenttemporaryfilesdirs.cpp
@@ -0,0 +1,108 @@
1/*
2 Copyright (c) 2013-2017 Montel Laurent <montel@kde.org>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18
19*/
20
21#include "attachmenttemporaryfilesdirs.h"
22
23#include <QDir>
24#include <QFile>
25#include <QTimer>
26
27using namespace MimeTreeParser;
28
29class MimeTreeParser::AttachmentTemporaryFilesDirsPrivate
30{
31public:
32 AttachmentTemporaryFilesDirsPrivate()
33 : mDelayRemoveAll(10000)
34 {
35
36 }
37 QStringList mTempFiles;
38 QStringList mTempDirs;
39 int mDelayRemoveAll;
40};
41
42AttachmentTemporaryFilesDirs::AttachmentTemporaryFilesDirs(QObject *parent)
43 : QObject(parent),
44 d(new AttachmentTemporaryFilesDirsPrivate)
45{
46
47}
48
49AttachmentTemporaryFilesDirs::~AttachmentTemporaryFilesDirs()
50{
51 delete d;
52}
53
54void AttachmentTemporaryFilesDirs::setDelayRemoveAllInMs(int ms)
55{
56 d->mDelayRemoveAll = (ms < 0) ? 0 : ms;
57}
58
59void AttachmentTemporaryFilesDirs::removeTempFiles()
60{
61 QTimer::singleShot(d->mDelayRemoveAll, this, &AttachmentTemporaryFilesDirs::slotRemoveTempFiles);
62}
63
64void AttachmentTemporaryFilesDirs::forceCleanTempFiles()
65{
66 QStringList::ConstIterator end = d->mTempFiles.constEnd();
67 for (QStringList::ConstIterator it = d->mTempFiles.constBegin(); it != end; ++it) {
68 QFile::remove(*it);
69 }
70 d->mTempFiles.clear();
71 end = d->mTempDirs.constEnd();
72 for (QStringList::ConstIterator it = d->mTempDirs.constBegin(); it != end; ++it) {
73 QDir(*it).rmdir(*it);
74 }
75 d->mTempDirs.clear();
76}
77
78void AttachmentTemporaryFilesDirs::slotRemoveTempFiles()
79{
80 forceCleanTempFiles();
81 //Delete it after cleaning
82 deleteLater();
83}
84
85void AttachmentTemporaryFilesDirs::addTempFile(const QString &file)
86{
87 if (!d->mTempFiles.contains(file)) {
88 d->mTempFiles.append(file);
89 }
90}
91
92void AttachmentTemporaryFilesDirs::addTempDir(const QString &dir)
93{
94 if (!d->mTempDirs.contains(dir)) {
95 d->mTempDirs.append(dir);
96 }
97}
98
99QStringList AttachmentTemporaryFilesDirs::temporaryFiles() const
100{
101 return d->mTempFiles;
102}
103
104QStringList AttachmentTemporaryFilesDirs::temporaryDirs() const
105{
106 return d->mTempDirs;
107}
108
diff --git a/framework/src/domain/mimetreeparser/otp/attachmenttemporaryfilesdirs.h b/framework/src/domain/mimetreeparser/otp/attachmenttemporaryfilesdirs.h
new file mode 100644
index 00000000..bf65fcdb
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/attachmenttemporaryfilesdirs.h
@@ -0,0 +1,57 @@
1/*
2 Copyright (c) 2013-2016 Montel Laurent <montel@kde.org>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18
19*/
20
21#ifndef ATTACHMENTTEMPORARYFILESDIRS_H
22#define ATTACHMENTTEMPORARYFILESDIRS_H
23
24#include <QObject>
25#include <QStringList>
26
27namespace MimeTreeParser
28{
29class AttachmentTemporaryFilesDirsPrivate;
30
31class AttachmentTemporaryFilesDirs : public QObject
32{
33 Q_OBJECT
34public:
35 explicit AttachmentTemporaryFilesDirs(QObject *parent = nullptr);
36 ~AttachmentTemporaryFilesDirs();
37
38 void addTempFile(const QString &file);
39 void addTempDir(const QString &dir);
40 QStringList temporaryFiles() const;
41 void removeTempFiles();
42 void forceCleanTempFiles();
43
44 QStringList temporaryDirs() const;
45
46 void setDelayRemoveAllInMs(int ms);
47
48private Q_SLOTS:
49 void slotRemoveTempFiles();
50
51private:
52 AttachmentTemporaryFilesDirsPrivate *const d;
53};
54
55}
56
57#endif // ATTACHMENTTEMPORARYFILESDIRS_H
diff --git a/framework/src/domain/mimetreeparser/otp/bodypart.cpp b/framework/src/domain/mimetreeparser/otp/bodypart.cpp
new file mode 100644
index 00000000..62e92d0c
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/bodypart.cpp
@@ -0,0 +1,41 @@
1/*
2 This file is part of KMail's plugin interface.
3 Copyright (c) 2004 Marc Mutz <mutz@kde.org>,
4 Ingo Kloecker <kloecker@kde.org>
5
6 KMail is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 KMail is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
20 In addition, as a special exception, the copyright holders give
21 permission to link the code of this program with any edition of
22 the Qt library by Trolltech AS, Norway (or with modified versions
23 of Qt that use the same license as Qt), and distribute linked
24 combinations including the two. You must obey the GNU General
25 Public License in all respects for all of the code used other than
26 Qt. If you modify this file, you may extend this exception to
27 your version of the file, but you are not obligated to do so. If
28 you do not wish to do so, delete this exception statement from
29 your version.
30*/
31
32#include "bodypart.h"
33
34MimeTreeParser::Interface::BodyPartMemento::~BodyPartMemento()
35{
36}
37
38MimeTreeParser::Interface::BodyPart::~BodyPart()
39{
40}
41
diff --git a/framework/src/domain/mimetreeparser/otp/bodypart.h b/framework/src/domain/mimetreeparser/otp/bodypart.h
new file mode 100644
index 00000000..f50c0360
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/bodypart.h
@@ -0,0 +1,209 @@
1/* -*- mode: C++; c-file-style: "gnu" -*-
2 bodypart.h
3
4 This file is part of KMail's plugin interface.
5 Copyright (c) 2004 Marc Mutz <mutz@kde.org>,
6 Ingo Kloecker <kloecker@kde.org>
7
8 KMail is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 KMail is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
22 In addition, as a special exception, the copyright holders give
23 permission to link the code of this program with any edition of
24 the Qt library by Trolltech AS, Norway (or with modified versions
25 of Qt that use the same license as Qt), and distribute linked
26 combinations including the two. You must obey the GNU General
27 Public License in all respects for all of the code used other than
28 Qt. If you modify this file, you may extend this exception to
29 your version of the file, but you are not obligated to do so. If
30 you do not wish to do so, delete this exception statement from
31 your version.
32*/
33
34#ifndef __MIMETREEPARSER_INTERFACES_BODYPART_H__
35#define __MIMETREEPARSER_INTERFACES_BODYPART_H__
36
37#include <QByteArray>
38#include <QString>
39
40namespace KMime
41{
42class Content;
43}
44
45namespace MimeTreeParser
46{
47class NodeHelper;
48class ObjectTreeParser;
49class ProcessResult;
50
51namespace Interface
52{
53
54class ObjectTreeSource;
55
56/*FIXME(Andras) review, port
57 class Observer;
58 class Observable;
59*/
60/**
61 @short interface of classes that implement status for BodyPartFormatters.
62*/
63class BodyPartMemento
64{
65public:
66 virtual ~BodyPartMemento();
67
68 virtual void detach() = 0;
69#if 0
70//FIXME(Andras) review, port
71 /** If your BodyPartMemento implementation also implements the
72 Observer interface, simply implement these as
73 <code>return this;</code>, else as <code>return
74 0;</code>. This is needed to avoid forcing a dependency of
75 plugins on internal KMail classes.
76 */
77 virtual Observer *asObserver() = 0;
78
79 /** If your BodyPartMemento implementation also implements the
80 Observable interface, simply implement these as
81 <code>return this;</code>, else as <code>return
82 0;</code>. This is needed to avoid forcing a dependency of
83 plugins on internal KMail classes.
84 */
85 virtual Observable *asObservable() = 0;
86#endif
87};
88
89/**
90 @short interface of message body parts.
91*/
92class BodyPart
93{
94public:
95 virtual ~BodyPart();
96
97 /**
98 @return a string respresentation of an URL that can be used
99 to invoke a BodyPartURLHandler for this body part.
100 */
101 virtual QString makeLink(const QString &path) const = 0;
102
103 /**
104 @return the decoded (CTE, canonicalisation, and charset
105 encoding undone) text contained in the body part, or
106 QString(), it the body part is not of type "text".
107 */
108 virtual QString asText() const = 0;
109
110 /**
111 @return the decoded (CTE undone) content of the body part, or
112 a null array if this body part instance is of type text.
113 */
114 virtual QByteArray asBinary() const = 0;
115
116 /**
117 @return the value of the content-type header field parameter
118 with name \a parameter, or QString(), if that that
119 parameter is not present in the body's content-type header
120 field. RFC 2231 encoding is removed first.
121
122 Note that this method will suppress queries to certain
123 standard parameters (most notably "charset") to keep plugins
124 decent.
125
126 Note2 that this method preserves the case of the parameter
127 value returned. So, if the parameter you want to use defines
128 the value to be case-insensitive (such as the smime-type
129 parameter), you need to make sure you do the casemap yourself
130 before comparing to a reference value.
131 */
132 virtual QString contentTypeParameter(const char *parameter) const = 0;
133
134 /**
135 @return the content of the content-description header field,
136 or QString() if that header is not present in this body
137 part. RFC 2047 encoding is decoded first.
138 */
139 virtual QString contentDescription() const = 0;
140
141 //virtual int contentDisposition() const = 0;
142 /**
143 @return the value of the content-disposition header field
144 parameter with name \a parameter, or QString() if that
145 parameter is not present in the body's content-disposition
146 header field. RFC 2231 encoding is removed first.
147
148 The notes made for contentTypeParameter() above apply here as
149 well.
150 */
151 virtual QString contentDispositionParameter(const char *parameter) const = 0;
152
153 /**
154 @return whether this part already has it's complete body
155 fetched e.g. from an IMAP server.
156 */
157 virtual bool hasCompleteBody() const = 0;
158
159 /**
160 @return the BodyPartMemento set for this part, or null, if
161 none is set.
162 */
163 virtual BodyPartMemento *memento() const = 0;
164
165 /**
166 @return register an implementation of the BodyPartMemento
167 interface as a status object with this part.
168 */
169 virtual void setBodyPartMemento(BodyPartMemento *) = 0;
170
171 enum Display { None, AsIcon, Inline };
172 /**
173 @return whether this body part should be displayed iconic or inline
174 */
175 virtual Display defaultDisplay() const = 0;
176
177 /** Returns the KMime::Content node represented here. Makes most of the above obsolete
178 and probably should be used in the interfaces in the first place.
179 */
180 virtual KMime::Content *content() const = 0;
181
182 /**
183 * Returns the top-level content.
184 * Note that this is _not_ necessarily the same as content()->topLevel(), for example the later
185 * will not work for "extra nodes", i.e. nodes in encrypted parts of the mail.
186 * topLevelContent() will return the correct result in this case. Also note that
187 * topLevelContent()
188 */
189 virtual KMime::Content *topLevelContent() const = 0;
190
191 /**
192 * Ok, this is ugly, exposing the node helper here, but there is too much useful stuff in there
193 * for real-world plugins. Still, there should be a nicer way for this.
194 */
195 virtual MimeTreeParser::NodeHelper *nodeHelper() const = 0;
196
197 /**
198 * For making it easier to refactor, add objectTreeParser
199 */
200 virtual MimeTreeParser::ObjectTreeParser *objectTreeParser() const = 0;
201 virtual MimeTreeParser::Interface::ObjectTreeSource *source() const = 0;
202 virtual MimeTreeParser::ProcessResult *processResult() const = 0;
203};
204
205} // namespace Interface
206
207}
208
209#endif // __MIMETREEPARSER_INTERFACES_BODYPART_H__
diff --git a/framework/src/domain/mimetreeparser/otp/bodypartformatter.cpp b/framework/src/domain/mimetreeparser/otp/bodypartformatter.cpp
new file mode 100644
index 00000000..63d7e92c
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/bodypartformatter.cpp
@@ -0,0 +1,147 @@
1/* -*- mode: C++; c-file-style: "gnu" -*-
2 bodypartformatter.cpp
3
4 This file is part of KMail's plugin interface.
5 Copyright (c) 2016 Sandro Knauß <sknauss@kde.org>
6
7 KMail is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 KMail is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
21 In addition, as a special exception, the copyright holders give
22 permission to link the code of this program with any edition of
23 the Qt library by Trolltech AS, Norway (or with modified versions
24 of Qt that use the same license as Qt), and distribute linked
25 combinations including the two. You must obey the GNU General
26 Public License in all respects for all of the code used other than
27 Qt. If you modify this file, you may extend this exception to
28 your version of the file, but you are not obligated to do so. If
29 you do not wish to do so, delete this exception statement from
30 your version.
31*/
32
33#include "bodypartformatter.h"
34
35#include "bodypart.h"
36#include "queuehtmlwriter.h"
37#include "objecttreeparser.h"
38
39using namespace MimeTreeParser::Interface;
40
41namespace MimeTreeParser
42{
43namespace Interface
44{
45
46class MessagePartPrivate
47{
48public:
49 MessagePartPrivate(const BodyPart *part)
50 : mHtmlWriter(nullptr)
51 , mPart(part)
52 , mParentPart(nullptr)
53 , mCreatedWriter(false)
54 {
55 }
56
57 ~MessagePartPrivate()
58 {
59 if (mCreatedWriter) {
60 delete mHtmlWriter;
61 }
62 }
63
64 MimeTreeParser::HtmlWriter *htmlWriter()
65 {
66 if (!mHtmlWriter && mPart) {
67 mHtmlWriter = mPart->objectTreeParser()->htmlWriter();
68 }
69 return mHtmlWriter;
70 }
71
72 MimeTreeParser::HtmlWriter *mHtmlWriter;
73 const BodyPart *mPart;
74 MessagePart *mParentPart;
75 bool mCreatedWriter;
76
77};
78}
79}
80
81MessagePart::MessagePart()
82 : QObject()
83 , d(new MessagePartPrivate(nullptr))
84{
85}
86
87MessagePart::MessagePart(const BodyPart &part)
88 : QObject()
89 , d(new MessagePartPrivate(&part))
90{
91}
92
93MessagePart::~MessagePart()
94{
95 delete d;
96}
97
98void MessagePart::html(bool decorate)
99{
100 Q_UNUSED(decorate);
101 static_cast<QueueHtmlWriter *>(d->mHtmlWriter)->replay();
102}
103
104QString MessagePart::text() const
105{
106 return QString();
107}
108
109MessagePart *MessagePart::parentPart() const
110{
111 return d->mParentPart;
112}
113
114void MessagePart::setParentPart(MessagePart *parentPart)
115{
116 d->mParentPart = parentPart;
117}
118
119QString MessagePart::htmlContent() const
120{
121 return text();
122}
123
124QString MessagePart::plaintextContent() const
125{
126 return text();
127}
128
129MimeTreeParser::HtmlWriter *MessagePart::htmlWriter() const
130{
131 return d->htmlWriter();
132}
133
134void MessagePart::setHtmlWriter(MimeTreeParser::HtmlWriter *htmlWriter) const
135{
136 if (d->mHtmlWriter) {
137 d->mHtmlWriter = htmlWriter;
138 }
139}
140
141MessagePart::Ptr BodyPartFormatter::process(BodyPart &part) const
142{
143 auto mp = MessagePart::Ptr(new MessagePart(part));
144 mp->setHtmlWriter(new QueueHtmlWriter(mp->htmlWriter()));
145 mp->d->mCreatedWriter = true;
146 return mp;
147}
diff --git a/framework/src/domain/mimetreeparser/otp/bodypartformatter.h b/framework/src/domain/mimetreeparser/otp/bodypartformatter.h
new file mode 100644
index 00000000..682f9391
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/bodypartformatter.h
@@ -0,0 +1,149 @@
1/* -*- mode: C++; c-file-style: "gnu" -*-
2 bodypartformatter.h
3
4 This file is part of KMail's plugin interface.
5 Copyright (c) 2004 Marc Mutz <mutz@kde.org>,
6 Ingo Kloecker <kloecker@kde.org>
7
8 KMail is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 KMail is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
22 In addition, as a special exception, the copyright holders give
23 permission to link the code of this program with any edition of
24 the Qt library by Trolltech AS, Norway (or with modified versions
25 of Qt that use the same license as Qt), and distribute linked
26 combinations including the two. You must obey the GNU General
27 Public License in all respects for all of the code used other than
28 Qt. If you modify this file, you may extend this exception to
29 your version of the file, but you are not obligated to do so. If
30 you do not wish to do so, delete this exception statement from
31 your version.
32*/
33
34#ifndef __MIMETREEPARSER_INTERFACE_BODYPARTFORMATTER_H__
35#define __MIMETREEPARSER_INTERFACE_BODYPARTFORMATTER_H__
36
37#include <QObject>
38#include <QSharedPointer>
39
40#include "mimetreeparser/objecttreeparser.h"
41
42namespace MimeTreeParser
43{
44class HtmlWriter;
45
46namespace Interface
47{
48
49class BodyPartURLHandler;
50class BodyPart;
51class MessagePartPrivate;
52
53class MessagePart : public QObject
54{
55 Q_OBJECT
56 Q_PROPERTY(QString plaintextContent READ plaintextContent)
57 Q_PROPERTY(QString htmlContent READ htmlContent)
58public:
59 typedef QSharedPointer<MessagePart> Ptr;
60 explicit MessagePart();
61 explicit MessagePart(const BodyPart &part);
62 virtual ~MessagePart();
63
64 virtual void html(bool decorate);
65 virtual QString text() const;
66
67 void setParentPart(MessagePart *parentPart);
68 MessagePart *parentPart() const;
69
70 virtual QString plaintextContent() const;
71 virtual QString htmlContent() const;
72
73 virtual MimeTreeParser::HtmlWriter *htmlWriter() const;
74 virtual void setHtmlWriter(MimeTreeParser::HtmlWriter *htmlWriter) const;
75private:
76 MessagePartPrivate *d;
77
78 friend class BodyPartFormatter;
79};
80
81class BodyPartFormatter
82{
83public:
84 virtual ~BodyPartFormatter() {}
85
86 /**
87 @li Ok returned when format() generated some HTML
88 @li NeedContent returned when format() needs the body of the part
89 @li AsIcon returned when the part should be shown iconified
90 @li Failed returned when formatting failed. Currently equivalent to Ok
91 */
92 enum Result { Ok, NeedContent, AsIcon, Failed };
93
94 /**
95 Format body part \a part by generating some HTML and writing
96 that to \a writer.
97
98 @return the result code (see above)
99 */
100 virtual Result format(BodyPart *part, MimeTreeParser::HtmlWriter *writer) const = 0;
101
102 /**
103 Variant of format that allows implementors to hook notifications up to
104 a listener interested in the result, for async operations.
105
106 @return the result code (see above)
107 */
108 virtual Result format(BodyPart *part, MimeTreeParser::HtmlWriter *writer, QObject *asyncResultObserver) const
109 {
110 Q_UNUSED(asyncResultObserver);
111 return format(part, writer);
112 }
113
114 virtual void adaptProcessResult(ProcessResult &result) const
115 {
116 Q_UNUSED(result);
117 }
118 virtual MessagePart::Ptr process(BodyPart &part) const;
119};
120
121/**
122 @short interface for BodyPartFormatter plugins
123
124 The interface is queried by for types, subtypes, and the
125 corresponding bodypart formatter, and the result inserted into
126 the bodypart formatter factory.
127
128 Subtype alone or both type and subtype may be "*", which is
129 taken as a wildcard, so that e.g. type=text subtype=* matches
130 any text subtype, but with lesser specificity than a concrete
131 mimetype such as text/plain. type=* is only allowed when
132 subtype=*, too.
133*/
134class BodyPartFormatterPlugin
135{
136public:
137 virtual ~BodyPartFormatterPlugin() {}
138
139 virtual const BodyPartFormatter *bodyPartFormatter(int idx) const = 0;
140 virtual const char *type(int idx) const = 0;
141 virtual const char *subtype(int idx) const = 0;
142
143 virtual const BodyPartURLHandler *urlHandler(int idx) const = 0;
144};
145
146} // namespace Interface
147
148}
149#endif // __MIMETREEPARSER_INTERFACE_BODYPARTFORMATTER_H__
diff --git a/framework/src/domain/mimetreeparser/otp/bodypartformatterbasefactory.cpp b/framework/src/domain/mimetreeparser/otp/bodypartformatterbasefactory.cpp
new file mode 100644
index 00000000..a44576b8
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/bodypartformatterbasefactory.cpp
@@ -0,0 +1,208 @@
1/*
2 bodypartformatterfactory.cpp
3
4 This file is part of KMail, the KDE mail client.
5 Copyright (c) 2004 Marc Mutz <mutz@kde.org>,
6 Ingo Kloecker <kloecker@kde.org>
7
8 KMail is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 KMail is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
22 In addition, as a special exception, the copyright holders give
23 permission to link the code of this program with any edition of
24 the Qt library by Trolltech AS, Norway (or with modified versions
25 of Qt that use the same license as Qt), and distribute linked
26 combinations including the two. You must obey the GNU General
27 Public License in all respects for all of the code used other than
28 Qt. If you modify this file, you may extend this exception to
29 your version of the file, but you are not obligated to do so. If
30 you do not wish to do so, delete this exception statement from
31 your version.
32*/
33
34#include "bodypartformatterbasefactory.h"
35#include "bodypartformatterbasefactory_p.h"
36#include "mimetreeparser_debug.h"
37
38// Qt
39
40#include <assert.h>
41
42using namespace MimeTreeParser;
43
44BodyPartFormatterBaseFactoryPrivate::BodyPartFormatterBaseFactoryPrivate(BodyPartFormatterBaseFactory *factory)
45 : q(factory)
46 , all(nullptr)
47{
48}
49
50BodyPartFormatterBaseFactoryPrivate::~BodyPartFormatterBaseFactoryPrivate()
51{
52 if (all) {
53 delete all;
54 all = nullptr;
55 }
56}
57
58void BodyPartFormatterBaseFactoryPrivate::setup()
59{
60 if (!all) {
61 all = new TypeRegistry();
62 messageviewer_create_builtin_bodypart_formatters();
63 q->loadPlugins();
64 }
65}
66
67void BodyPartFormatterBaseFactoryPrivate::insert(const char *type, const char *subtype, const Interface::BodyPartFormatter *formatter)
68{
69 if (!type || !*type || !subtype || !*subtype || !formatter || !all) {
70 return;
71 }
72
73 TypeRegistry::iterator type_it = all->find(type);
74 if (type_it == all->end()) {
75 qCDebug(MIMETREEPARSER_LOG) << "BodyPartFormatterBaseFactory: instantiating new Subtype Registry for \""
76 << type << "\"";
77 type_it = all->insert(std::make_pair(type, SubtypeRegistry())).first;
78 assert(type_it != all->end());
79 }
80
81 SubtypeRegistry &subtype_reg = type_it->second;
82
83 subtype_reg.insert(std::make_pair(subtype, formatter));
84}
85
86void BodyPartFormatterBaseFactoryPrivate::messageviewer_create_builtin_bodypart_formatters()
87{
88 //FIXME defined in bodypartformatter.cpp
89 // insert("application", "octet-stream", AnyTypeBodyPartFormatter::create());
90 // insert("application", "pgp", ApplicationPgpBodyPartFormatter::create());
91 // insert("application", "pkcs7-mime", ApplicationPkcs7MimeBodyPartFormatter::create());
92 // insert("application", "x-pkcs7-mime", ApplicationPkcs7MimeBodyPartFormatter::create());
93 // insert("application", "pgp-encrypted", ApplicationPGPEncryptedBodyPartFormatter::create());
94 // insert("application", "*", AnyTypeBodyPartFormatter::create());
95
96 // insert("text", "html", TextHtmlBodyPartFormatter::create());
97 // insert("text", "rtf", AnyTypeBodyPartFormatter::create());
98 // insert("text", "plain", MailmanBodyPartFormatter::create());
99 // insert("text", "plain", TextPlainBodyPartFormatter::create());
100 // insert("text", "*", MailmanBodyPartFormatter::create());
101 // insert("text", "*", TextPlainBodyPartFormatter::create());
102
103 // insert("image", "*", ImageTypeBodyPartFormatter::create());
104
105 // insert("message", "rfc822", MessageRfc822BodyPartFormatter::create());
106 // insert("message", "*", AnyTypeBodyPartFormatter::create());
107
108 // insert("multipart", "alternative", MultiPartAlternativeBodyPartFormatter::create());
109 // insert("multipart", "encrypted", MultiPartEncryptedBodyPartFormatter::create());
110 // insert("multipart", "signed", MultiPartSignedBodyPartFormatter::create());
111 // insert("multipart", "*", MultiPartMixedBodyPartFormatter::create());
112 // insert("*", "*", AnyTypeBodyPartFormatter::create());
113}
114
115BodyPartFormatterBaseFactory::BodyPartFormatterBaseFactory()
116 : d(new BodyPartFormatterBaseFactoryPrivate(this))
117{
118}
119
120BodyPartFormatterBaseFactory::~BodyPartFormatterBaseFactory()
121{
122 delete d;
123}
124
125void BodyPartFormatterBaseFactory::insert(const char *type, const char *subtype, const Interface::BodyPartFormatter *formatter)
126{
127 d->insert(type, subtype, formatter);
128}
129
130const SubtypeRegistry &BodyPartFormatterBaseFactory::subtypeRegistry(const char *type) const
131{
132 if (!type || !*type) {
133 type = "*"; //krazy:exclude=doublequote_chars
134 }
135
136 d->setup();
137 assert(d->all);
138
139 static SubtypeRegistry emptyRegistry;
140 if (d->all->empty()) {
141 return emptyRegistry;
142 }
143
144 TypeRegistry::const_iterator type_it = d->all->find(type);
145 if (type_it == d->all->end()) {
146 type_it = d->all->find("*");
147 }
148 if (type_it == d->all->end()) {
149 return emptyRegistry;
150 }
151
152 const SubtypeRegistry &subtype_reg = type_it->second;
153 if (subtype_reg.empty()) {
154 return emptyRegistry;
155 }
156 return subtype_reg;
157}
158
159SubtypeRegistry::const_iterator BodyPartFormatterBaseFactory::createForIterator(const char *type, const char *subtype) const
160{
161 if (!type || !*type) {
162 type = "*"; //krazy:exclude=doublequote_chars
163 }
164 if (!subtype || !*subtype) {
165 subtype = "*"; //krazy:exclude=doublequote_chars
166 }
167
168 d->setup();
169 assert(d->all);
170
171 if (d->all->empty()) {
172 return SubtypeRegistry::const_iterator();
173 }
174
175 TypeRegistry::const_iterator type_it = d->all->find(type);
176 if (type_it == d->all->end()) {
177 type_it = d->all->find("*");
178 }
179 if (type_it == d->all->end()) {
180 return SubtypeRegistry::const_iterator();
181 }
182
183 const SubtypeRegistry &subtype_reg = type_it->second;
184 if (subtype_reg.empty()) {
185 return SubtypeRegistry::const_iterator();
186 }
187
188 SubtypeRegistry::const_iterator subtype_it = subtype_reg.find(subtype);
189 qCWarning(MIMETREEPARSER_LOG) << type << subtype << subtype_reg.size();
190 if (subtype_it == subtype_reg.end()) {
191 subtype_it = subtype_reg.find("*");
192 }
193 if (subtype_it == subtype_reg.end()) {
194 return SubtypeRegistry::const_iterator();
195 }
196
197 if (!(*subtype_it).second) {
198 qCWarning(MIMETREEPARSER_LOG) << "BodyPartFormatterBaseFactory: a null bodypart formatter sneaked in for \""
199 << type << "/" << subtype << "\"!";
200 }
201
202 return subtype_it;
203}
204
205void BodyPartFormatterBaseFactory::loadPlugins()
206{
207 qCDebug(MIMETREEPARSER_LOG) << "plugin loading is not enabled in libmimetreeparser";
208}
diff --git a/framework/src/domain/mimetreeparser/otp/bodypartformatterbasefactory.h b/framework/src/domain/mimetreeparser/otp/bodypartformatterbasefactory.h
new file mode 100644
index 00000000..2bba551d
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/bodypartformatterbasefactory.h
@@ -0,0 +1,85 @@
1/*
2 bodypartformatterfactory.h
3
4 This file is part of KMail, the KDE mail client.
5 Copyright (c) 2004 Marc Mutz <mutz@kde.org>,
6 Ingo Kloecker <kloecker@kde.org>
7
8 KMail is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 KMail is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
22 In addition, as a special exception, the copyright holders give
23 permission to link the code of this program with any edition of
24 the Qt library by Trolltech AS, Norway (or with modified versions
25 of Qt that use the same license as Qt), and distribute linked
26 combinations including the two. You must obey the GNU General
27 Public License in all respects for all of the code used other than
28 Qt. If you modify this file, you may extend this exception to
29 your version of the file, but you are not obligated to do so. If
30 you do not wish to do so, delete this exception statement from
31 your version.
32*/
33
34#ifndef __MIMETREEPARSER_BODYPARTFORMATTERBASEFACTORY_H__
35#define __MIMETREEPARSER_BODYPARTFORMATTERBASEFACTORY_H__
36
37#include <map>
38#include <QByteArray>
39
40namespace MimeTreeParser
41{
42
43namespace Interface
44{
45class BodyPartFormatter;
46}
47
48struct ltstr {
49 bool operator()(const char *s1, const char *s2) const
50 {
51 return qstricmp(s1, s2) < 0;
52 }
53};
54
55typedef std::multimap<const char *, const Interface::BodyPartFormatter *, ltstr> SubtypeRegistry;
56typedef std::map<const char *, MimeTreeParser::SubtypeRegistry, MimeTreeParser::ltstr> TypeRegistry;
57
58class BodyPartFormatterBaseFactoryPrivate;
59
60class BodyPartFormatterBaseFactory
61{
62public:
63 BodyPartFormatterBaseFactory();
64 virtual ~BodyPartFormatterBaseFactory();
65
66 SubtypeRegistry::const_iterator createForIterator(const char *type, const char *subtype) const;
67 const SubtypeRegistry &subtypeRegistry(const char *type) const;
68
69protected:
70 void insert(const char *type, const char *subtype, const Interface::BodyPartFormatter *formatter);
71 virtual void loadPlugins();
72private:
73 static BodyPartFormatterBaseFactory *mSelf;
74
75 BodyPartFormatterBaseFactoryPrivate *d;
76 friend class BodyPartFormatterBaseFactoryPrivate;
77private:
78 // disabled
79 const BodyPartFormatterBaseFactory &operator=(const BodyPartFormatterBaseFactory &);
80 BodyPartFormatterBaseFactory(const BodyPartFormatterBaseFactory &);
81};
82
83}
84
85#endif // __MIMETREEPARSER_BODYPARTFORMATTERFACTORY_H__
diff --git a/framework/src/domain/mimetreeparser/otp/bodypartformatterbasefactory_p.h b/framework/src/domain/mimetreeparser/otp/bodypartformatterbasefactory_p.h
new file mode 100644
index 00000000..1f71f183
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/bodypartformatterbasefactory_p.h
@@ -0,0 +1,57 @@
1/* -*- mode: C++; c-file-style: "gnu" -*-
2 bodypartformatterfactory.h
3
4 This file is part of KMail, the KDE mail client.
5 Copyright (c) 2004 Marc Mutz <mutz@kde.org>,
6 Ingo Kloecker <kloecker@kde.org>
7
8 KMail is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 KMail is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
22 In addition, as a special exception, the copyright holders give
23 permission to link the code of this program with any edition of
24 the Qt library by Trolltech AS, Norway (or with modified versions
25 of Qt that use the same license as Qt), and distribute linked
26 combinations including the two. You must obey the GNU General
27 Public License in all respects for all of the code used other than
28 Qt. If you modify this file, you may extend this exception to
29 your version of the file, but you are not obligated to do so. If
30 you do not wish to do so, delete this exception statement from
31 your version.
32*/
33
34#ifndef __MIMETREEPARSER_BODYPARTFORMATTERBASEFACTORY_P_H__
35#define __MIMETREEPARSER_BODYPARTFORMATTERBASEFACTORY_P_H__
36
37namespace MimeTreeParser
38{
39class BodyPartFormatterBaseFactory;
40
41class BodyPartFormatterBaseFactoryPrivate
42{
43public:
44 BodyPartFormatterBaseFactoryPrivate(BodyPartFormatterBaseFactory *factory);
45 ~BodyPartFormatterBaseFactoryPrivate();
46
47 void setup();
48 void messageviewer_create_builtin_bodypart_formatters(); //defined in bodypartformatter.cpp
49 void insert(const char *type, const char *subtype, const Interface::BodyPartFormatter *formatter);
50
51 BodyPartFormatterBaseFactory *q;
52 TypeRegistry *all;
53};
54
55}
56
57#endif // __MIMETREEPARSER_BODYPARTFORMATTERFACTORY_P_H__
diff --git a/framework/src/domain/mimetreeparser/otp/cryptobodypartmemento.cpp b/framework/src/domain/mimetreeparser/otp/cryptobodypartmemento.cpp
new file mode 100644
index 00000000..a884ec36
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/cryptobodypartmemento.cpp
@@ -0,0 +1,56 @@
1/*
2 Copyright (c) 2014-2017 Montel Laurent <montel@kde.org>
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License, version 2, as
6 published by the Free Software Foundation.
7
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16*/
17
18#include "cryptobodypartmemento.h"
19
20using namespace GpgME;
21using namespace MimeTreeParser;
22
23CryptoBodyPartMemento::CryptoBodyPartMemento()
24 : QObject(nullptr),
25 Interface::BodyPartMemento(),
26 m_running(false)
27{
28
29}
30
31CryptoBodyPartMemento::~CryptoBodyPartMemento()
32{
33
34}
35
36bool CryptoBodyPartMemento::isRunning() const
37{
38 return m_running;
39}
40
41void CryptoBodyPartMemento::setAuditLog(const Error &err, const QString &log)
42{
43 m_auditLogError = err;
44 m_auditLog = log;
45}
46
47void CryptoBodyPartMemento::setRunning(bool running)
48{
49 m_running = running;
50}
51
52void CryptoBodyPartMemento::detach()
53{
54 disconnect(this, SIGNAL(update(MimeTreeParser::UpdateMode)), nullptr, nullptr);
55}
56
diff --git a/framework/src/domain/mimetreeparser/otp/cryptobodypartmemento.h b/framework/src/domain/mimetreeparser/otp/cryptobodypartmemento.h
new file mode 100644
index 00000000..076ed890
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/cryptobodypartmemento.h
@@ -0,0 +1,75 @@
1/*
2 Copyright (c) 2014-2016 Montel Laurent <montel@kde.org>
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License, version 2, as
6 published by the Free Software Foundation.
7
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16*/
17
18#ifndef __MIMETREEPARSER_CRYPTOBODYPARTMEMENTO_H__
19#define __MIMETREEPARSER_CRYPTOBODYPARTMEMENTO_H__
20
21#include <gpgme++/error.h>
22
23#include <QObject>
24#include <QString>
25
26#include "bodypart.h"
27#include "enums.h"
28
29namespace MimeTreeParser
30{
31
32class CryptoBodyPartMemento
33 : public QObject,
34 public Interface::BodyPartMemento
35{
36 Q_OBJECT
37public:
38 CryptoBodyPartMemento();
39 ~CryptoBodyPartMemento();
40
41 virtual bool start() = 0;
42 virtual void exec() = 0;
43 bool isRunning() const;
44
45 const QString &auditLogAsHtml() const
46 {
47 return m_auditLog;
48 }
49 GpgME::Error auditLogError() const
50 {
51 return m_auditLogError;
52 }
53
54 void detach() Q_DECL_OVERRIDE;
55
56Q_SIGNALS:
57 void update(MimeTreeParser::UpdateMode);
58
59protected Q_SLOTS:
60 void notify()
61 {
62 Q_EMIT update(MimeTreeParser::Force);
63 }
64
65protected:
66 void setAuditLog(const GpgME::Error &err, const QString &log);
67 void setRunning(bool running);
68
69private:
70 bool m_running;
71 QString m_auditLog;
72 GpgME::Error m_auditLogError;
73};
74}
75#endif // __MIMETREEPARSER_CRYPTOBODYPARTMEMENTO_H__
diff --git a/framework/src/domain/mimetreeparser/otp/cryptohelper.cpp b/framework/src/domain/mimetreeparser/otp/cryptohelper.cpp
new file mode 100644
index 00000000..8e5df576
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/cryptohelper.cpp
@@ -0,0 +1,150 @@
1/*
2 Copyright (C) 2015 Sandro Knauß <knauss@kolabsys.com>
3 Copyright (C) 2001,2002 the KPGP authors
4 See file AUTHORS.kpgp for details
5
6 Kmail is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 You should have received a copy of the GNU General Public License
12 along with this program; if not, write to the Free Software Foundation,
13 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
14 */
15
16#include "cryptohelper.h"
17
18using namespace MimeTreeParser;
19
20PGPBlockType Block::determineType() const
21{
22 const QByteArray data = text();
23 if (data.startsWith("-----BEGIN PGP SIGNED")) {
24 return ClearsignedBlock;
25 } else if (data.startsWith("-----BEGIN PGP SIGNATURE")) {
26 return SignatureBlock;
27 } else if (data.startsWith("-----BEGIN PGP PUBLIC")) {
28 return PublicKeyBlock;
29 } else if (data.startsWith("-----BEGIN PGP PRIVATE")
30 || data.startsWith("-----BEGIN PGP SECRET")) {
31 return PrivateKeyBlock;
32 } else if (data.startsWith("-----BEGIN PGP MESSAGE")) {
33 if (data.startsWith("-----BEGIN PGP MESSAGE PART")) {
34 return MultiPgpMessageBlock;
35 } else {
36 return PgpMessageBlock;
37 }
38 } else if (data.startsWith("-----BEGIN PGP ARMORED FILE")) {
39 return PgpMessageBlock;
40 } else if (data.startsWith("-----BEGIN PGP ")) {
41 return UnknownBlock;
42 } else {
43 return NoPgpBlock;
44 }
45}
46
47QList<Block> MimeTreeParser::prepareMessageForDecryption(const QByteArray &msg)
48{
49 PGPBlockType pgpBlock = NoPgpBlock;
50 QList<Block> blocks;
51 int start = -1; // start of the current PGP block
52 int lastEnd = -1; // end of the last PGP block
53 const int length = msg.length();
54
55 if (msg.isEmpty()) {
56 return blocks;
57 }
58
59 if (msg.startsWith("-----BEGIN PGP ")) {
60 start = 0;
61 } else {
62 start = msg.indexOf("\n-----BEGIN PGP ") + 1;
63 if (start == 0) {
64 blocks.append(Block(msg, NoPgpBlock));
65 return blocks;
66 }
67 }
68
69 while (start != -1) {
70 int nextEnd, nextStart;
71
72 // is the PGP block a clearsigned block?
73 if (!strncmp(msg.constData() + start + 15, "SIGNED", 6)) {
74 pgpBlock = ClearsignedBlock;
75 } else {
76 pgpBlock = UnknownBlock;
77 }
78
79 nextEnd = msg.indexOf("\n-----END PGP ", start + 15);
80 nextStart = msg.indexOf("\n-----BEGIN PGP ", start + 15);
81
82 if (nextEnd == -1) { // Missing END PGP line
83 if (lastEnd != -1) {
84 blocks.append(Block(msg.mid(lastEnd + 1), UnknownBlock));
85 } else {
86 blocks.append(Block(msg.mid(start), UnknownBlock));
87 }
88 break;
89 }
90
91 if ((nextStart == -1) || (nextEnd < nextStart) || (pgpBlock == ClearsignedBlock)) {
92 // most likely we found a PGP block (but we don't check if it's valid)
93
94 // store the preceding non-PGP block
95 if (start - lastEnd - 1 > 0) {
96 blocks.append(Block(msg.mid(lastEnd + 1, start - lastEnd - 1), NoPgpBlock));
97 }
98
99 lastEnd = msg.indexOf("\n", nextEnd + 14);
100 if (lastEnd == -1) {
101 if (start < length) {
102 blocks.append(Block(msg.mid(start)));
103 }
104 break;
105 } else {
106 blocks.append(Block(msg.mid(start, lastEnd + 1 - start)));
107 if ((nextStart != -1) && (nextEnd > nextStart)) {
108 nextStart = msg.indexOf("\n-----BEGIN PGP ", lastEnd + 1);
109 }
110 }
111 }
112
113 start = nextStart;
114
115 if (start == -1) {
116 if (lastEnd + 1 < length) {
117 //rest of mail is no PGP Block
118 blocks.append(Block(msg.mid(lastEnd + 1), NoPgpBlock));
119 }
120 break;
121 } else {
122 start++; // move start behind the '\n'
123 }
124 }
125
126 return blocks;
127}
128
129Block::Block(const QByteArray &m)
130 : msg(m)
131{
132 mType = determineType();
133}
134
135Block::Block(const QByteArray &m, PGPBlockType t)
136 : msg(m)
137 , mType(t)
138{
139
140}
141
142QByteArray MimeTreeParser::Block::text() const
143{
144 return msg;
145}
146
147PGPBlockType Block::type() const
148{
149 return mType;
150}
diff --git a/framework/src/domain/mimetreeparser/otp/cryptohelper.h b/framework/src/domain/mimetreeparser/otp/cryptohelper.h
new file mode 100644
index 00000000..f09771c3
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/cryptohelper.h
@@ -0,0 +1,62 @@
1/*
2 cryptohelper.h
3
4 Copyright (C) 2015 Sandro Knauß <knauss@kolabsys.com>
5 Copyright (C) 2001,2002 the KPGP authors
6 See file AUTHORS.kpgp for details
7
8 KMail is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software Foundation,
15 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
16 */
17
18#ifndef __MIMETREEPARSER_CRYPTOHELPER_H__
19#define __MIMETREEPARSER_CRYPTOHELPER_H__
20
21#include <QByteArray>
22#include <QList>
23
24namespace MimeTreeParser
25{
26
27enum PGPBlockType {
28 UnknownBlock = -1, // BEGIN PGP ???
29 NoPgpBlock = 0,
30 PgpMessageBlock = 1, // BEGIN PGP MESSAGE
31 MultiPgpMessageBlock = 2, // BEGIN PGP MESSAGE, PART X[/Y]
32 SignatureBlock = 3, // BEGIN PGP SIGNATURE
33 ClearsignedBlock = 4, // BEGIN PGP SIGNED MESSAGE
34 PublicKeyBlock = 5, // BEGIN PGP PUBLIC KEY BLOCK
35 PrivateKeyBlock = 6 // BEGIN PGP PRIVATE KEY BLOCK (PGP 2.x: ...SECRET...)
36};
37
38class Block
39{
40public:
41 Block(const QByteArray &m);
42
43 Block(const QByteArray &m, PGPBlockType t);
44
45 QByteArray text() const;
46 PGPBlockType type() const;
47 PGPBlockType determineType() const;
48
49 QByteArray msg;
50 PGPBlockType mType;
51};
52
53/** Parses the given message and splits it into OpenPGP blocks and
54 Non-OpenPGP blocks.
55*/
56QList<Block> prepareMessageForDecryption(const QByteArray &msg);
57
58} // namespace MimeTreeParser
59
60Q_DECLARE_TYPEINFO(MimeTreeParser::Block, Q_MOVABLE_TYPE);
61
62#endif
diff --git a/framework/src/domain/mimetreeparser/otp/decryptverifybodypartmemento.cpp b/framework/src/domain/mimetreeparser/otp/decryptverifybodypartmemento.cpp
new file mode 100644
index 00000000..9810797a
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/decryptverifybodypartmemento.cpp
@@ -0,0 +1,86 @@
1/*
2 Copyright (c) 2014-2017 Montel Laurent <montel@kde.org>
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License, version 2, as
6 published by the Free Software Foundation.
7
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16*/
17
18#include "decryptverifybodypartmemento.h"
19
20#include <QGpgME/DecryptVerifyJob>
21
22#include <qstringlist.h>
23
24using namespace QGpgME;
25using namespace GpgME;
26using namespace MimeTreeParser;
27
28DecryptVerifyBodyPartMemento::DecryptVerifyBodyPartMemento(DecryptVerifyJob *job, const QByteArray &cipherText)
29 : CryptoBodyPartMemento(),
30 m_cipherText(cipherText),
31 m_job(job)
32{
33 Q_ASSERT(m_job);
34}
35
36DecryptVerifyBodyPartMemento::~DecryptVerifyBodyPartMemento()
37{
38 if (m_job) {
39 m_job->slotCancel();
40 }
41}
42
43bool DecryptVerifyBodyPartMemento::start()
44{
45 Q_ASSERT(m_job);
46 if (const Error err = m_job->start(m_cipherText)) {
47 m_dr = DecryptionResult(err);
48 return false;
49 }
50 connect(m_job.data(), &DecryptVerifyJob::result,
51 this, &DecryptVerifyBodyPartMemento::slotResult);
52 setRunning(true);
53 return true;
54}
55
56void DecryptVerifyBodyPartMemento::exec()
57{
58 Q_ASSERT(m_job);
59 QByteArray plainText;
60 setRunning(true);
61 const std::pair<DecryptionResult, VerificationResult> p = m_job->exec(m_cipherText, plainText);
62 saveResult(p.first, p.second, plainText);
63 m_job->deleteLater(); // exec'ed jobs don't delete themselves
64 m_job = nullptr;
65}
66
67void DecryptVerifyBodyPartMemento::saveResult(const DecryptionResult &dr,
68 const VerificationResult &vr,
69 const QByteArray &plainText)
70{
71 Q_ASSERT(m_job);
72 setRunning(false);
73 m_dr = dr;
74 m_vr = vr;
75 m_plainText = plainText;
76 setAuditLog(m_job->auditLogError(), m_job->auditLogAsHtml());
77}
78
79void DecryptVerifyBodyPartMemento::slotResult(const DecryptionResult &dr,
80 const VerificationResult &vr,
81 const QByteArray &plainText)
82{
83 saveResult(dr, vr, plainText);
84 m_job = nullptr;
85 notify();
86}
diff --git a/framework/src/domain/mimetreeparser/otp/decryptverifybodypartmemento.h b/framework/src/domain/mimetreeparser/otp/decryptverifybodypartmemento.h
new file mode 100644
index 00000000..4781abe2
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/decryptverifybodypartmemento.h
@@ -0,0 +1,81 @@
1/*
2 Copyright (c) 2014-2016 Montel Laurent <montel@kde.org>
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License, version 2, as
6 published by the Free Software Foundation.
7
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16*/
17
18#ifndef __MIMETREEPARSER_DECRYPTVERIFYBODYPARTMEMENTO_H__
19#define __MIMETREEPARSER_DECRYPTVERIFYBODYPARTMEMENTO_H__
20
21#include "cryptobodypartmemento.h"
22
23#include <gpgme++/verificationresult.h>
24#include <gpgme++/decryptionresult.h>
25
26#include <QPointer>
27
28#include "bodypart.h"
29
30namespace QGpgME
31{
32class DecryptVerifyJob;
33}
34
35namespace MimeTreeParser
36{
37
38class DecryptVerifyBodyPartMemento
39 : public CryptoBodyPartMemento
40{
41 Q_OBJECT
42public:
43 DecryptVerifyBodyPartMemento(QGpgME::DecryptVerifyJob *job, const QByteArray &cipherText);
44 ~DecryptVerifyBodyPartMemento();
45
46 bool start() Q_DECL_OVERRIDE;
47 void exec() Q_DECL_OVERRIDE;
48
49 const QByteArray &plainText() const
50 {
51 return m_plainText;
52 }
53 const GpgME::DecryptionResult &decryptResult() const
54 {
55 return m_dr;
56 }
57 const GpgME::VerificationResult &verifyResult() const
58 {
59 return m_vr;
60 }
61
62private Q_SLOTS:
63 void slotResult(const GpgME::DecryptionResult &dr,
64 const GpgME::VerificationResult &vr,
65 const QByteArray &plainText);
66
67private:
68 void saveResult(const GpgME::DecryptionResult &,
69 const GpgME::VerificationResult &,
70 const QByteArray &);
71private:
72 // input:
73 const QByteArray m_cipherText;
74 QPointer<QGpgME::DecryptVerifyJob> m_job;
75 // output:
76 GpgME::DecryptionResult m_dr;
77 GpgME::VerificationResult m_vr;
78 QByteArray m_plainText;
79};
80}
81#endif // __MIMETREEPARSER_DECRYPTVERIFYBODYPARTMEMENTO_H__
diff --git a/framework/src/domain/mimetreeparser/otp/enums.h b/framework/src/domain/mimetreeparser/otp/enums.h
new file mode 100644
index 00000000..bec5a028
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/enums.h
@@ -0,0 +1,54 @@
1/*
2 Copyright (c) 2016 Sandro Knauß <sknauss@kde.org>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17*/
18
19#ifndef __MIMETREEPARSER_ENUMS_H__
20#define __MIMETREEPARSER_ENUMS_H__
21
22namespace MimeTreeParser
23{
24
25/**
26 * The display update mode: Force updates the display immediately, Delayed updates
27 * after some time (150ms by default)
28 */
29enum UpdateMode {
30 Force = 0,
31 Delayed
32};
33
34/** Flags for the encryption state. */
35typedef enum {
36 KMMsgEncryptionStateUnknown = ' ',
37 KMMsgNotEncrypted = 'N',
38 KMMsgPartiallyEncrypted = 'P',
39 KMMsgFullyEncrypted = 'F',
40 KMMsgEncryptionProblematic = 'X'
41} KMMsgEncryptionState;
42
43/** Flags for the signature state. */
44typedef enum {
45 KMMsgSignatureStateUnknown = ' ',
46 KMMsgNotSigned = 'N',
47 KMMsgPartiallySigned = 'P',
48 KMMsgFullySigned = 'F',
49 KMMsgSignatureProblematic = 'X'
50} KMMsgSignatureState;
51
52}
53
54#endif
diff --git a/framework/src/domain/mimetreeparser/otp/filehtmlwriter.cpp b/framework/src/domain/mimetreeparser/otp/filehtmlwriter.cpp
new file mode 100644
index 00000000..a143f944
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/filehtmlwriter.cpp
@@ -0,0 +1,119 @@
1/* -*- c++ -*-
2 filehtmlwriter.cpp
3
4 This file is part of KMail, the KDE mail client.
5 Copyright (c) 2003 Marc Mutz <mutz@kde.org>
6
7 KMail is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License, version 2, as
9 published by the Free Software Foundation.
10
11 KMail is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
20 In addition, as a special exception, the copyright holders give
21 permission to link the code of this program with any edition of
22 the Qt library by Trolltech AS, Norway (or with modified versions
23 of Qt that use the same license as Qt), and distribute linked
24 combinations including the two. You must obey the GNU General
25 Public License in all respects for all of the code used other than
26 Qt. If you modify this file, you may extend this exception to
27 your version of the file, but you are not obligated to do so. If
28 you do not wish to do so, delete this exception statement from
29 your version.
30*/
31
32#include "filehtmlwriter.h"
33
34#include "mimetreeparser_debug.h"
35
36namespace MimeTreeParser
37{
38
39FileHtmlWriter::FileHtmlWriter(const QString &filename)
40 : HtmlWriter(),
41 mFile(filename.isEmpty() ? QStringLiteral("filehtmlwriter.out") : filename)
42{
43}
44
45FileHtmlWriter::~FileHtmlWriter()
46{
47 if (mFile.isOpen()) {
48 qCWarning(MIMETREEPARSER_LOG) << "FileHtmlWriter: file still open!";
49 mStream.setDevice(nullptr);
50 mFile.close();
51 }
52}
53
54void FileHtmlWriter::begin(const QString &css)
55{
56 openOrWarn();
57 if (!css.isEmpty()) {
58 write(QLatin1String("<!-- CSS Definitions \n") + css + QLatin1String("-->\n"));
59 }
60}
61
62void FileHtmlWriter::end()
63{
64 flush();
65 mStream.setDevice(nullptr);
66 mFile.close();
67}
68
69void FileHtmlWriter::reset()
70{
71 if (mFile.isOpen()) {
72 mStream.setDevice(nullptr);
73 mFile.close();
74 }
75}
76
77void FileHtmlWriter::write(const QString &str)
78{
79 mStream << str;
80 flush();
81}
82
83void FileHtmlWriter::queue(const QString &str)
84{
85 write(str);
86}
87
88void FileHtmlWriter::flush()
89{
90 mStream.flush();
91 mFile.flush();
92}
93
94void FileHtmlWriter::openOrWarn()
95{
96 if (mFile.isOpen()) {
97 qCWarning(MIMETREEPARSER_LOG) << "FileHtmlWriter: file still open!";
98 mStream.setDevice(nullptr);
99 mFile.close();
100 }
101 if (!mFile.open(QIODevice::WriteOnly)) {
102 qCWarning(MIMETREEPARSER_LOG) << "FileHtmlWriter: Cannot open file" << mFile.fileName();
103 } else {
104 mStream.setDevice(&mFile);
105 mStream.setCodec("UTF-8");
106 }
107}
108
109void FileHtmlWriter::embedPart(const QByteArray &contentId, const QString &url)
110{
111 mStream << "<!-- embedPart(contentID=" << contentId << ", url=" << url << ") -->" << endl;
112 flush();
113}
114void FileHtmlWriter::extraHead(const QString &)
115{
116
117}
118
119} //
diff --git a/framework/src/domain/mimetreeparser/otp/filehtmlwriter.h b/framework/src/domain/mimetreeparser/otp/filehtmlwriter.h
new file mode 100644
index 00000000..5dafb593
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/filehtmlwriter.h
@@ -0,0 +1,70 @@
1/* -*- c++ -*-
2 filehtmlwriter.h
3
4 This file is part of KMail, the KDE mail client.
5 Copyright (c) 2003 Marc Mutz <mutz@kde.org>
6
7 KMail is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License, version 2, as
9 published by the Free Software Foundation.
10
11 KMail is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
20 In addition, as a special exception, the copyright holders give
21 permission to link the code of this program with any edition of
22 the Qt library by Trolltech AS, Norway (or with modified versions
23 of Qt that use the same license as Qt), and distribute linked
24 combinations including the two. You must obey the GNU General
25 Public License in all respects for all of the code used other than
26 Qt. If you modify this file, you may extend this exception to
27 your version of the file, but you are not obligated to do so. If
28 you do not wish to do so, delete this exception statement from
29 your version.
30*/
31
32#ifndef __MIMETREEPARSER_FILEHTMLWRITER_H__
33#define __MIMETREEPARSER_FILEHTMLWRITER_H__
34
35#include "mimetreeparser_export.h"
36#include "mimetreeparser/htmlwriter.h"
37
38#include <QFile>
39#include <QTextStream>
40
41class QString;
42
43namespace MimeTreeParser
44{
45
46class MIMETREEPARSER_EXPORT FileHtmlWriter : public HtmlWriter
47{
48public:
49 explicit FileHtmlWriter(const QString &filename);
50 virtual ~FileHtmlWriter();
51
52 void begin(const QString &cssDefs) Q_DECL_OVERRIDE;
53 void end() Q_DECL_OVERRIDE;
54 void reset() Q_DECL_OVERRIDE;
55 void write(const QString &str) Q_DECL_OVERRIDE;
56 void queue(const QString &str) Q_DECL_OVERRIDE;
57 void flush() Q_DECL_OVERRIDE;
58 void embedPart(const QByteArray &contentId, const QString &url) Q_DECL_OVERRIDE;
59 void extraHead(const QString &str) Q_DECL_OVERRIDE;
60private:
61 void openOrWarn();
62
63private:
64 QFile mFile;
65 QTextStream mStream;
66};
67
68} // namespace MimeTreeParser
69
70#endif // __MIMETREEPARSER_FILEHTMLWRITER_H__
diff --git a/framework/src/domain/mimetreeparser/otp/htmlwriter.cpp b/framework/src/domain/mimetreeparser/otp/htmlwriter.cpp
new file mode 100644
index 00000000..3c98d997
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/htmlwriter.cpp
@@ -0,0 +1,40 @@
1/*
2 This file is part of KMail's plugin interface.
3 Copyright (c) 2003 Marc Mutz <mutz@kde.org>
4
5 KMail is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 KMail is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19 In addition, as a special exception, the copyright holders give
20 permission to link the code of this program with any edition of
21 the Qt library by Trolltech AS, Norway (or with modified versions
22 of Qt that use the same license as Qt), and distribute linked
23 combinations including the two. You must obey the GNU General
24 Public License in all respects for all of the code used other than
25 Qt. If you modify this file, you may extend this exception to
26 your version of the file, but you are not obligated to do so. If
27 you do not wish to do so, delete this exception statement from
28 your version.
29*/
30
31#include "htmlwriter.h"
32
33MimeTreeParser::Interface::HtmlWriter::~HtmlWriter()
34{
35}
36
37MimeTreeParser::HtmlWriter::~HtmlWriter()
38{
39}
40
diff --git a/framework/src/domain/mimetreeparser/otp/htmlwriter.h b/framework/src/domain/mimetreeparser/otp/htmlwriter.h
new file mode 100644
index 00000000..382c80fb
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/htmlwriter.h
@@ -0,0 +1,125 @@
1/* -*- c++ -*-
2 interfaces/htmlwriter.h
3
4 This file is part of KMail's plugin interface.
5 Copyright (c) 2003 Marc Mutz <mutz@kde.org>
6
7 KMail is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 KMail is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
21 In addition, as a special exception, the copyright holders give
22 permission to link the code of this program with any edition of
23 the Qt library by Trolltech AS, Norway (or with modified versions
24 of Qt that use the same license as Qt), and distribute linked
25 combinations including the two. You must obey the GNU General
26 Public License in all respects for all of the code used other than
27 Qt. If you modify this file, you may extend this exception to
28 your version of the file, but you are not obligated to do so. If
29 you do not wish to do so, delete this exception statement from
30 your version.
31*/
32
33#ifndef __MIMETREEPARSER_INTERFACES_HTMLWRITER_H__
34#define __MIMETREEPARSER_INTERFACES_HTMLWRITER_H__
35
36class QByteArray;
37class QString;
38
39namespace MimeTreeParser
40{
41/**
42 * @short An interface for HTML sinks.
43 * @author Marc Mutz <mutz@kde.org>
44 *
45 */
46namespace Interface
47{
48class HtmlWriter
49{
50public:
51 virtual ~HtmlWriter();
52
53 /** Signal the begin of stuff to write, and give the CSS definitions */
54 virtual void begin(const QString &cssDefinitions) = 0;
55 /** Write out a chunk of text. No HTML escaping is performed. */
56 virtual void write(const QString &html) = 0;
57 /** Signal the end of stuff to write. */
58 virtual void end() = 0;
59};
60}
61
62/**
63 * @short An interface to HTML sinks
64 * @author Marc Mutz <mutz@kde.org>
65 *
66 * @deprecated KMail should be ported to Interface::HtmlWriter. This
67 * interface exposes internal working models. The queuing
68 * vs. writing() issues exposed here should be hidden by using two
69 * different implementations of KHTMLPartHtmlWriter: one for
70 * queuing, and one for writing. This should be fixed before the
71 * release, so we an keep the plugin interface stable.
72 *
73 * Operate this interface in one and only one of the following two
74 * modes:
75 *
76 * @section Sync Mode
77 *
78 * In sync mode, use #begin() to initiate a session, then
79 * #write() some chunks of HTML code and finally #end() the session.
80 *
81 * @section Async Mode
82 *
83 * In async mode, use #begin() to initialize a session, then
84 * #queue() some chunks of HTML code and finally end the
85 * session by calling #flush().
86 *
87 * Queued HTML code is fed to the html sink using a timer. For this
88 * to work, control must return to the event loop so timer events
89 * are delivered.
90 *
91 * @section Combined mode
92 *
93 * You may combine the two modes in the following way only. Any
94 * number of #write() calls can precede #queue() calls,
95 * but once a chunk has been queued, you @em must @em not
96 * #write() more data, only #queue() it.
97 *
98 * Naturally, whenever you queued data in a given session, that
99 * session must be ended by calling #flush(), not #end().
100 */
101class HtmlWriter : public Interface::HtmlWriter
102{
103public:
104 virtual ~HtmlWriter();
105
106 /** Stop all possibly pending processing in order to be able to
107 * call #begin() again. */
108 virtual void reset() = 0;
109
110 virtual void queue(const QString &str) = 0;
111 /** (Start) flushing internal buffers, if any. */
112 virtual void flush() = 0;
113
114 /**
115 * Embed a part with Content-ID @p contentId, using url @p url.
116 */
117 virtual void embedPart(const QByteArray &contentId, const QString &url) = 0;
118
119 virtual void extraHead(const QString &str) = 0;
120};
121
122}
123
124#endif // __MIMETREEPARSER_INTERFACES_HTMLWRITER_H__
125
diff --git a/framework/src/domain/mimetreeparser/otp/messagepart.cpp b/framework/src/domain/mimetreeparser/otp/messagepart.cpp
new file mode 100644
index 00000000..3228a387
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/messagepart.cpp
@@ -0,0 +1,1352 @@
1/*
2 Copyright (c) 2015 Sandro Knauß <sknauss@kde.org>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20#include "messagepart.h"
21#include "mimetreeparser_debug.h"
22#include "attachmentstrategy.h"
23#include "cryptohelper.h"
24#include "objecttreeparser.h"
25#include "htmlwriter.h"
26#include "qgpgmejobexecutor.h"
27
28#include "cryptobodypartmemento.h"
29#include "decryptverifybodypartmemento.h"
30#include "verifydetachedbodypartmemento.h"
31#include "verifyopaquebodypartmemento.h"
32
33#include "utils.h"
34
35#include <KMime/Content>
36
37#include <QGpgME/DN>
38#include <QGpgME/Protocol>
39#include <QGpgME/ImportJob>
40#include <QGpgME/KeyListJob>
41#include <QGpgME/VerifyDetachedJob>
42#include <QGpgME/VerifyOpaqueJob>
43
44#include <gpgme++/key.h>
45#include <gpgme++/keylistresult.h>
46#include <gpgme.h>
47
48#include <KLocalizedString>
49
50#include <QTextCodec>
51
52using namespace MimeTreeParser;
53
54//------MessagePart-----------------------
55MessagePart::MessagePart(ObjectTreeParser *otp,
56 const QString &text)
57 : mText(text)
58 , mOtp(otp)
59 , mAttachmentNode(nullptr)
60 , mRoot(false)
61{
62}
63
64MessagePart::~MessagePart()
65{
66}
67
68PartMetaData *MessagePart::partMetaData()
69{
70 return &mMetaData;
71}
72
73void MessagePart::setAttachmentFlag(KMime::Content *node)
74{
75 mAttachmentNode = node;
76}
77
78bool MessagePart::isAttachment() const
79{
80 return mAttachmentNode;
81}
82
83KMime::Content *MessagePart::attachmentNode() const
84{
85 return mAttachmentNode;
86}
87
88void MessagePart::setIsRoot(bool root)
89{
90 mRoot = root;
91}
92
93bool MessagePart::isRoot() const
94{
95 return mRoot;
96}
97
98QString MessagePart::text() const
99{
100 return mText;
101}
102
103void MessagePart::setText(const QString &text)
104{
105 mText = text;
106}
107
108bool MessagePart::isHtml() const
109{
110 return false;
111}
112
113bool MessagePart::isHidden() const
114{
115 return false;
116}
117
118Interface::ObjectTreeSource *MessagePart::source() const
119{
120 Q_ASSERT(mOtp);
121 return mOtp->mSource;
122}
123
124HtmlWriter *MessagePart::htmlWriter() const
125{
126 Q_ASSERT(mOtp);
127 return mOtp->htmlWriter();
128}
129
130void MessagePart::setHtmlWriter(HtmlWriter *htmlWriter) const
131{
132 mOtp->mHtmlWriter = htmlWriter;
133}
134
135void MessagePart::parseInternal(KMime::Content *node, bool onlyOneMimePart)
136{
137 auto subMessagePart = mOtp->parseObjectTreeInternal(node, onlyOneMimePart);
138 mRoot = subMessagePart->isRoot();
139 foreach (const auto &part, subMessagePart->subParts()) {
140 appendSubPart(part);
141 }
142}
143
144QString MessagePart::renderInternalText() const
145{
146 QString text;
147 foreach (const auto &mp, subParts()) {
148 text += mp->text();
149 }
150 return text;
151}
152
153void MessagePart::copyContentFrom() const
154{
155 foreach (const auto &mp, subParts()) {
156 const auto m = mp.dynamicCast<MessagePart>();
157 if (m) {
158 m->copyContentFrom();
159 }
160 }
161}
162
163void MessagePart::fix() const
164{
165 foreach (const auto &mp, subParts()) {
166 const auto m = mp.dynamicCast<MessagePart>();
167 if (m) {
168 m->fix();
169 }
170 }
171}
172
173void MessagePart::appendSubPart(const Interface::MessagePart::Ptr &messagePart)
174{
175 messagePart->setParentPart(this);
176 mBlocks.append(messagePart);
177}
178
179const QVector<Interface::MessagePart::Ptr> &MessagePart::subParts() const
180{
181 return mBlocks;
182}
183
184bool MessagePart::hasSubParts() const
185{
186 return !mBlocks.isEmpty();
187}
188
189//-----MessagePartList----------------------
190MessagePartList::MessagePartList(ObjectTreeParser *otp)
191 : MessagePart(otp, QString())
192{
193}
194
195MessagePartList::~MessagePartList()
196{
197
198}
199
200QString MessagePartList::text() const
201{
202 return renderInternalText();
203}
204
205QString MessagePartList::plaintextContent() const
206{
207 return QString();
208}
209
210QString MessagePartList::htmlContent() const
211{
212 return QString();
213}
214
215//-----TextMessageBlock----------------------
216
217TextMessagePart::TextMessagePart(ObjectTreeParser *otp, KMime::Content *node, bool drawFrame, bool showLink, bool decryptMessage)
218 : MessagePartList(otp)
219 , mNode(node)
220 , mDrawFrame(drawFrame)
221 , mShowLink(showLink)
222 , mDecryptMessage(decryptMessage)
223 , mIsHidden(false)
224{
225 if (!mNode) {
226 qCWarning(MIMETREEPARSER_LOG) << "not a valid node";
227 return;
228 }
229
230 mIsHidden = mOtp->nodeHelper()->isNodeDisplayedHidden(mNode);
231
232 parseContent();
233}
234
235TextMessagePart::~TextMessagePart()
236{
237
238}
239
240bool TextMessagePart::decryptMessage() const
241{
242 return mDecryptMessage;
243}
244
245void TextMessagePart::parseContent()
246{
247 const auto aCodec = mOtp->codecFor(mNode);
248 const QString &fromAddress = mOtp->nodeHelper()->fromAsString(mNode);
249 mSignatureState = KMMsgNotSigned;
250 mEncryptionState = KMMsgNotEncrypted;
251 const auto blocks = prepareMessageForDecryption(mNode->decodedContent());
252
253 const auto cryptProto = QGpgME::openpgp();
254
255 if (!blocks.isEmpty()) {
256
257 /* The (overall) signature/encrypted status is broken
258 * if one unencrypted part is at the beginning or in the middle
259 * because mailmain adds an unencrypted part at the end this should not break the overall status
260 *
261 * That's why we first set the tmp status and if one crypted/signed block comes afterwards, than
262 * the status is set to unencryped
263 */
264 bool fullySignedOrEncrypted = true;
265 bool fullySignedOrEncryptedTmp = true;
266
267 for (const auto &block : blocks) {
268
269 if (!fullySignedOrEncryptedTmp) {
270 fullySignedOrEncrypted = false;
271 }
272
273 if (block.type() == NoPgpBlock && !block.text().trimmed().isEmpty()) {
274 fullySignedOrEncryptedTmp = false;
275 appendSubPart(MessagePart::Ptr(new MessagePart(mOtp, aCodec->toUnicode(block.text()))));
276 } else if (block.type() == PgpMessageBlock) {
277 EncryptedMessagePart::Ptr mp(new EncryptedMessagePart(mOtp, QString(), cryptProto, fromAddress, nullptr));
278 mp->setDecryptMessage(decryptMessage());
279 mp->setIsEncrypted(true);
280 appendSubPart(mp);
281 if (!decryptMessage()) {
282 continue;
283 }
284 mp->startDecryption(block.text(), aCodec);
285 if (mp->partMetaData()->inProgress) {
286 continue;
287 }
288 } else if (block.type() == ClearsignedBlock) {
289 SignedMessagePart::Ptr mp(new SignedMessagePart(mOtp, QString(), cryptProto, fromAddress, nullptr));
290 appendSubPart(mp);
291 mp->startVerification(block.text(), aCodec);
292 } else {
293 continue;
294 }
295
296 const auto mp = subParts().last().staticCast<MessagePart>();
297 const PartMetaData *messagePart(mp->partMetaData());
298
299 if (!messagePart->isEncrypted && !messagePart->isSigned && !block.text().trimmed().isEmpty()) {
300 mp->setText(aCodec->toUnicode(block.text()));
301 }
302
303 if (messagePart->isEncrypted) {
304 mEncryptionState = KMMsgPartiallyEncrypted;
305 }
306
307 if (messagePart->isSigned) {
308 mSignatureState = KMMsgPartiallySigned;
309 }
310 }
311
312 //Do we have an fully Signed/Encrypted Message?
313 if (fullySignedOrEncrypted) {
314 if (mSignatureState == KMMsgPartiallySigned) {
315 mSignatureState = KMMsgFullySigned;
316 }
317 if (mEncryptionState == KMMsgPartiallyEncrypted) {
318 mEncryptionState = KMMsgFullyEncrypted;
319 }
320 }
321 }
322}
323
324KMMsgEncryptionState TextMessagePart::encryptionState() const
325{
326 return mEncryptionState;
327}
328
329KMMsgSignatureState TextMessagePart::signatureState() const
330{
331 return mSignatureState;
332}
333
334bool TextMessagePart::isHidden() const
335{
336 return mIsHidden;
337}
338
339bool TextMessagePart::showLink() const
340{
341 return mShowLink;
342}
343
344bool TextMessagePart::showTextFrame() const
345{
346 return mDrawFrame;
347}
348
349//-----AttachmentMessageBlock----------------------
350
351AttachmentMessagePart::AttachmentMessagePart(ObjectTreeParser *otp, KMime::Content *node, bool drawFrame, bool showLink, bool decryptMessage)
352 : TextMessagePart(otp, node, drawFrame, showLink, decryptMessage)
353 , mIsImage(false)
354 , mNeverDisplayInline(false)
355{
356
357}
358
359AttachmentMessagePart::~AttachmentMessagePart()
360{
361
362}
363
364bool AttachmentMessagePart::neverDisplayInline() const
365{
366 return mNeverDisplayInline;
367}
368
369void AttachmentMessagePart::setNeverDisplayInline(bool displayInline)
370{
371 mNeverDisplayInline = displayInline;
372}
373
374bool AttachmentMessagePart::isImage() const
375{
376 return mIsImage;
377}
378
379void AttachmentMessagePart::setIsImage(bool image)
380{
381 mIsImage = image;
382}
383
384IconType AttachmentMessagePart::asIcon() const
385{
386 const AttachmentStrategy *const as = mOtp->attachmentStrategy();
387 const bool defaultHidden(as && as->defaultDisplay(mNode) == AttachmentStrategy::None);
388 const bool showOnlyOneMimePart(mOtp->showOnlyOneMimePart());
389 auto preferredMode = source()->preferredMode();
390 bool isHtmlPreferred = (preferredMode == Util::Html) || (preferredMode == Util::MultipartHtml);
391
392 QByteArray mediaType("text");
393 QByteArray subType("plain");
394 if (mNode->contentType(false) && !mNode->contentType()->mediaType().isEmpty() &&
395 !mNode->contentType()->subType().isEmpty()) {
396 mediaType = mNode->contentType()->mediaType();
397 subType = mNode->contentType()->subType();
398 }
399 const bool isTextPart = (mediaType == QByteArrayLiteral("text"));
400
401 bool defaultAsIcon = true;
402 if (!neverDisplayInline()) {
403 if (as) {
404 defaultAsIcon = as->defaultDisplay(mNode) == AttachmentStrategy::AsIcon;
405 }
406 }
407 if (isImage() && showOnlyOneMimePart && !neverDisplayInline()) {
408 defaultAsIcon = false;
409 }
410
411 // neither image nor text -> show as icon
412 if (!isImage() && !isTextPart) {
413 defaultAsIcon = true;
414 }
415
416 if (isTextPart) {
417 if (as && as->defaultDisplay(mNode) != AttachmentStrategy::Inline) {
418 return MimeTreeParser::IconExternal;
419 }
420 return MimeTreeParser::NoIcon;
421 } else {
422 if (isImage() && isHtmlPreferred &&
423 mNode->parent() && mNode->parent()->contentType()->subType() == "related") {
424 return MimeTreeParser::IconInline;
425 }
426
427 if (defaultHidden && !showOnlyOneMimePart && mNode->parent()) {
428 return MimeTreeParser::IconInline;
429 }
430
431 if (defaultAsIcon) {
432 return MimeTreeParser::IconExternal;
433 } else if (isImage()) {
434 return MimeTreeParser::IconInline;
435 } else {
436 return MimeTreeParser::NoIcon;
437 }
438 }
439}
440
441bool AttachmentMessagePart::isHidden() const
442{
443 const AttachmentStrategy *const as = mOtp->attachmentStrategy();
444 const bool defaultHidden(as && as->defaultDisplay(mNode) == AttachmentStrategy::None);
445 const bool showOnlyOneMimePart(mOtp->showOnlyOneMimePart());
446 auto preferredMode = source()->preferredMode();
447 bool isHtmlPreferred = (preferredMode == Util::Html) || (preferredMode == Util::MultipartHtml);
448
449 QByteArray mediaType("text");
450 QByteArray subType("plain");
451 if (mNode->contentType(false) && !mNode->contentType()->mediaType().isEmpty() &&
452 !mNode->contentType()->subType().isEmpty()) {
453 mediaType = mNode->contentType()->mediaType();
454 subType = mNode->contentType()->subType();
455 }
456 const bool isTextPart = (mediaType == QByteArrayLiteral("text"));
457
458 bool defaultAsIcon = true;
459 if (!neverDisplayInline()) {
460 if (as) {
461 defaultAsIcon = as->defaultDisplay(mNode) == AttachmentStrategy::AsIcon;
462 }
463 }
464 if (isImage() && showOnlyOneMimePart && !neverDisplayInline()) {
465 defaultAsIcon = false;
466 }
467
468 // neither image nor text -> show as icon
469 if (!isImage() && !isTextPart) {
470 defaultAsIcon = true;
471 }
472
473 bool hidden(false);
474 if (isTextPart) {
475 hidden = defaultHidden && !showOnlyOneMimePart;
476 } else {
477 if (isImage() && isHtmlPreferred &&
478 mNode->parent() && mNode->parent()->contentType()->subType() == "related") {
479 hidden = true;
480 } else {
481 hidden = defaultHidden && !showOnlyOneMimePart && mNode->parent();
482 hidden |= defaultAsIcon && (defaultHidden || showOnlyOneMimePart);
483 }
484 }
485 mOtp->nodeHelper()->setNodeDisplayedHidden(mNode, hidden);
486 return hidden;
487}
488
489//-----HtmlMessageBlock----------------------
490
491HtmlMessagePart::HtmlMessagePart(ObjectTreeParser *otp, KMime::Content *node, Interface::ObjectTreeSource *source)
492 : MessagePart(otp, QString())
493 , mNode(node)
494 , mSource(source)
495{
496 if (!mNode) {
497 qCWarning(MIMETREEPARSER_LOG) << "not a valid node";
498 return;
499 }
500
501 const QByteArray partBody(mNode->decodedContent());
502 mBodyHTML = mOtp->codecFor(mNode)->toUnicode(partBody);
503 mCharset = NodeHelper::charset(mNode);
504}
505
506HtmlMessagePart::~HtmlMessagePart()
507{
508}
509
510void HtmlMessagePart::fix() const
511{
512 mOtp->mHtmlContent += mBodyHTML;
513 mOtp->mHtmlContentCharset = mCharset;
514}
515
516QString HtmlMessagePart::text() const
517{
518 return mBodyHTML;
519}
520
521bool HtmlMessagePart::isHtml() const
522{
523 return true;
524}
525
526//-----MimeMessageBlock----------------------
527
528MimeMessagePart::MimeMessagePart(ObjectTreeParser *otp, KMime::Content *node, bool onlyOneMimePart)
529 : MessagePart(otp, QString())
530 , mNode(node)
531 , mOnlyOneMimePart(onlyOneMimePart)
532{
533 if (!mNode) {
534 qCWarning(MIMETREEPARSER_LOG) << "not a valid node";
535 return;
536 }
537
538 parseInternal(mNode, mOnlyOneMimePart);
539}
540
541MimeMessagePart::~MimeMessagePart()
542{
543
544}
545
546QString MimeMessagePart::text() const
547{
548 return renderInternalText();
549}
550
551QString MimeMessagePart::plaintextContent() const
552{
553 return QString();
554}
555
556QString MimeMessagePart::htmlContent() const
557{
558 return QString();
559}
560
561//-----AlternativeMessagePart----------------------
562
563AlternativeMessagePart::AlternativeMessagePart(ObjectTreeParser *otp, KMime::Content *node, Util::HtmlMode preferredMode)
564 : MessagePart(otp, QString())
565 , mNode(node)
566 , mPreferredMode(preferredMode)
567{
568 KMime::Content *dataIcal = findTypeInDirectChilds(mNode, "text/calendar");
569 KMime::Content *dataHtml = findTypeInDirectChilds(mNode, "text/html");
570 KMime::Content *dataText = findTypeInDirectChilds(mNode, "text/plain");
571
572 if (!dataHtml) {
573 // If we didn't find the HTML part as the first child of the multipart/alternative, it might
574 // be that this is a HTML message with images, and text/plain and multipart/related are the
575 // immediate children of this multipart/alternative node.
576 // In this case, the HTML node is a child of multipart/related.
577 dataHtml = findTypeInDirectChilds(mNode, "multipart/related");
578
579 // Still not found? Stupid apple mail actually puts the attachments inside of the
580 // multipart/alternative, which is wrong. Therefore we also have to look for multipart/mixed
581 // here.
582 // Do this only when prefering HTML mail, though, since otherwise the attachments are hidden
583 // when displaying plain text.
584 if (!dataHtml) {
585 dataHtml = findTypeInDirectChilds(mNode, "multipart/mixed");
586 }
587 }
588
589 if (dataIcal) {
590 mChildNodes[Util::MultipartIcal] = dataIcal;
591 }
592
593 if (dataText) {
594 mChildNodes[Util::MultipartPlain] = dataText;
595 }
596
597 if (dataHtml) {
598 mChildNodes[Util::MultipartHtml] = dataHtml;
599 }
600
601 if (mChildNodes.isEmpty()) {
602 qCWarning(MIMETREEPARSER_LOG) << "no valid nodes";
603 return;
604 }
605
606 QMapIterator<Util::HtmlMode, KMime::Content *> i(mChildNodes);
607 while (i.hasNext()) {
608 i.next();
609 mChildParts[i.key()] = MimeMessagePart::Ptr(new MimeMessagePart(mOtp, i.value(), true));
610 }
611}
612
613AlternativeMessagePart::~AlternativeMessagePart()
614{
615
616}
617
618Util::HtmlMode AlternativeMessagePart::preferredMode() const
619{
620 return mPreferredMode;
621}
622
623QList<Util::HtmlMode> AlternativeMessagePart::availableModes()
624{
625 return mChildParts.keys();
626}
627
628QString AlternativeMessagePart::text() const
629{
630 if (mChildParts.contains(Util::MultipartPlain)) {
631 return mChildParts[Util::MultipartPlain]->text();
632 }
633 return QString();
634}
635
636void AlternativeMessagePart::fix() const
637{
638 if (mChildParts.contains(Util::MultipartPlain)) {
639 mChildParts[Util::MultipartPlain]->fix();
640 }
641
642 const auto mode = preferredMode();
643 if (mode != Util::MultipartPlain && mChildParts.contains(mode)) {
644 mChildParts[mode]->fix();
645 }
646}
647
648void AlternativeMessagePart::copyContentFrom() const
649{
650 if (mChildParts.contains(Util::MultipartPlain)) {
651 mChildParts[Util::MultipartPlain]->copyContentFrom();
652 }
653
654 const auto mode = preferredMode();
655 if (mode != Util::MultipartPlain && mChildParts.contains(mode)) {
656 mChildParts[mode]->copyContentFrom();
657 }
658}
659
660bool AlternativeMessagePart::isHtml() const
661{
662 return mChildParts.contains(Util::MultipartHtml);
663}
664
665QString AlternativeMessagePart::plaintextContent() const
666{
667 return text();
668}
669
670QString AlternativeMessagePart::htmlContent() const
671{
672 if (mChildParts.contains(Util::MultipartHtml)) {
673 return mChildParts[Util::MultipartHtml]->text();
674 } else {
675 return plaintextContent();
676 }
677}
678
679//-----CertMessageBlock----------------------
680
681CertMessagePart::CertMessagePart(ObjectTreeParser *otp, KMime::Content *node, const QGpgME::Protocol *cryptoProto, bool autoImport)
682 : MessagePart(otp, QString())
683 , mNode(node)
684 , mAutoImport(autoImport)
685 , mCryptoProto(cryptoProto)
686{
687 if (!mNode) {
688 qCWarning(MIMETREEPARSER_LOG) << "not a valid node";
689 return;
690 }
691
692 if (!mAutoImport) {
693 return;
694 }
695
696 const QByteArray certData = node->decodedContent();
697
698 QGpgME::ImportJob *import = mCryptoProto->importJob();
699 QGpgMEJobExecutor executor;
700 mImportResult = executor.exec(import, certData);
701}
702
703CertMessagePart::~CertMessagePart()
704{
705
706}
707
708QString CertMessagePart::text() const
709{
710 return QString();
711}
712
713//-----SignedMessageBlock---------------------
714SignedMessagePart::SignedMessagePart(ObjectTreeParser *otp,
715 const QString &text,
716 const QGpgME::Protocol *cryptoProto,
717 const QString &fromAddress,
718 KMime::Content *node)
719 : MessagePart(otp, text)
720 , mCryptoProto(cryptoProto)
721 , mFromAddress(fromAddress)
722 , mNode(node)
723{
724 mMetaData.technicalProblem = (mCryptoProto == nullptr);
725 mMetaData.isSigned = true;
726 mMetaData.isGoodSignature = false;
727 mMetaData.keyTrust = GpgME::Signature::Unknown;
728 mMetaData.status = i18n("Wrong Crypto Plug-In.");
729 mMetaData.status_code = GPGME_SIG_STAT_NONE;
730}
731
732SignedMessagePart::~SignedMessagePart()
733{
734
735}
736
737void SignedMessagePart::setIsSigned(bool isSigned)
738{
739 mMetaData.isSigned = isSigned;
740}
741
742bool SignedMessagePart::isSigned() const
743{
744 return mMetaData.isSigned;
745}
746
747bool SignedMessagePart::okVerify(const QByteArray &data, const QByteArray &signature, KMime::Content *textNode)
748{
749 NodeHelper *nodeHelper = mOtp->nodeHelper();
750 Interface::ObjectTreeSource *_source = source();
751
752 mMetaData.isSigned = false;
753 mMetaData.technicalProblem = (mCryptoProto == nullptr);
754 mMetaData.keyTrust = GpgME::Signature::Unknown;
755 mMetaData.status = i18n("Wrong Crypto Plug-In.");
756 mMetaData.status_code = GPGME_SIG_STAT_NONE;
757
758 const QByteArray mementoName = "verification";
759
760 CryptoBodyPartMemento *m = dynamic_cast<CryptoBodyPartMemento *>(nodeHelper->bodyPartMemento(mNode, mementoName));
761 Q_ASSERT(!m || mCryptoProto); //No CryptoPlugin and having a bodyPartMemento -> there is something completely wrong
762
763 if (!m && mCryptoProto) {
764 if (!signature.isEmpty()) {
765 QGpgME::VerifyDetachedJob *job = mCryptoProto->verifyDetachedJob();
766 if (job) {
767 m = new VerifyDetachedBodyPartMemento(job, mCryptoProto->keyListJob(), signature, data);
768 }
769 } else {
770 QGpgME::VerifyOpaqueJob *job = mCryptoProto->verifyOpaqueJob();
771 if (job) {
772 m = new VerifyOpaqueBodyPartMemento(job, mCryptoProto->keyListJob(), data);
773 }
774 }
775 if (m) {
776 if (mOtp->allowAsync()) {
777 QObject::connect(m, &CryptoBodyPartMemento::update,
778 nodeHelper, &NodeHelper::update);
779 QObject::connect(m, SIGNAL(update(MimeTreeParser::UpdateMode)),
780 _source->sourceObject(), SLOT(update(MimeTreeParser::UpdateMode)));
781
782 if (m->start()) {
783 mMetaData.inProgress = true;
784 mOtp->mHasPendingAsyncJobs = true;
785 }
786 } else {
787 m->exec();
788 }
789 nodeHelper->setBodyPartMemento(mNode, mementoName, m);
790 }
791 } else if (m->isRunning()) {
792 mMetaData.inProgress = true;
793 mOtp->mHasPendingAsyncJobs = true;
794 } else {
795 mMetaData.inProgress = false;
796 mOtp->mHasPendingAsyncJobs = false;
797 }
798
799 if (m && !mMetaData.inProgress) {
800 if (!signature.isEmpty()) {
801 mVerifiedText = data;
802 }
803 setVerificationResult(m, textNode);
804 }
805
806 if (!m && !mMetaData.inProgress) {
807 QString errorMsg;
808 QString cryptPlugLibName;
809 QString cryptPlugDisplayName;
810 if (mCryptoProto) {
811 cryptPlugLibName = mCryptoProto->name();
812 cryptPlugDisplayName = mCryptoProto->displayName();
813 }
814
815 if (!mCryptoProto) {
816 if (cryptPlugDisplayName.isEmpty()) {
817 errorMsg = i18n("No appropriate crypto plug-in was found.");
818 } else {
819 errorMsg = i18nc("%1 is either 'OpenPGP' or 'S/MIME'",
820 "No %1 plug-in was found.",
821 cryptPlugDisplayName);
822 }
823 } else {
824 errorMsg = i18n("Crypto plug-in \"%1\" cannot verify signatures.",
825 cryptPlugLibName);
826 }
827 mMetaData.errorText = i18n("The message is signed, but the "
828 "validity of the signature cannot be "
829 "verified.<br />"
830 "Reason: %1",
831 errorMsg);
832 }
833
834 return mMetaData.isSigned;
835}
836
837static int signatureToStatus(const GpgME::Signature &sig)
838{
839 switch (sig.status().code()) {
840 case GPG_ERR_NO_ERROR:
841 return GPGME_SIG_STAT_GOOD;
842 case GPG_ERR_BAD_SIGNATURE:
843 return GPGME_SIG_STAT_BAD;
844 case GPG_ERR_NO_PUBKEY:
845 return GPGME_SIG_STAT_NOKEY;
846 case GPG_ERR_NO_DATA:
847 return GPGME_SIG_STAT_NOSIG;
848 case GPG_ERR_SIG_EXPIRED:
849 return GPGME_SIG_STAT_GOOD_EXP;
850 case GPG_ERR_KEY_EXPIRED:
851 return GPGME_SIG_STAT_GOOD_EXPKEY;
852 default:
853 return GPGME_SIG_STAT_ERROR;
854 }
855}
856
857QString prettifyDN(const char *uid)
858{
859 return QGpgME::DN(uid).prettyDN();
860}
861
862void SignedMessagePart::sigStatusToMetaData()
863{
864 GpgME::Key key;
865 if (mMetaData.isSigned) {
866 GpgME::Signature signature = mSignatures.front();
867 mMetaData.status_code = signatureToStatus(signature);
868 mMetaData.isGoodSignature = mMetaData.status_code & GPGME_SIG_STAT_GOOD;
869 // save extended signature status flags
870 mMetaData.sigSummary = signature.summary();
871
872 if (mMetaData.isGoodSignature && !key.keyID()) {
873 // Search for the key by its fingerprint so that we can check for
874 // trust etc.
875 QGpgME::KeyListJob *job = mCryptoProto->keyListJob(false); // local, no sigs
876 if (!job) {
877 qCDebug(MIMETREEPARSER_LOG) << "The Crypto backend does not support listing keys. ";
878 } else {
879 std::vector<GpgME::Key> found_keys;
880 // As we are local it is ok to make this synchronous
881 GpgME::KeyListResult res = job->exec(QStringList(QLatin1String(signature.fingerprint())), false, found_keys);
882 if (res.error()) {
883 qCDebug(MIMETREEPARSER_LOG) << "Error while searching key for Fingerprint: " << signature.fingerprint();
884 }
885 if (found_keys.size() > 1) {
886 // Should not Happen
887 qCDebug(MIMETREEPARSER_LOG) << "Oops: Found more then one Key for Fingerprint: " << signature.fingerprint();
888 }
889 if (found_keys.size() != 1) {
890 // Should not Happen at this point
891 qCDebug(MIMETREEPARSER_LOG) << "Oops: Found no Key for Fingerprint: " << signature.fingerprint();
892 } else {
893 key = found_keys[0];
894 }
895 delete job;
896 }
897 }
898
899 if (key.keyID()) {
900 mMetaData.keyId = key.keyID();
901 }
902 if (mMetaData.keyId.isEmpty()) {
903 mMetaData.keyId = signature.fingerprint();
904 }
905 mMetaData.keyTrust = signature.validity();
906 if (key.numUserIDs() > 0 && key.userID(0).id()) {
907 mMetaData.signer = prettifyDN(key.userID(0).id());
908 }
909 for (uint iMail = 0; iMail < key.numUserIDs(); ++iMail) {
910 // The following if /should/ always result in TRUE but we
911 // won't trust implicitely the plugin that gave us these data.
912 if (key.userID(iMail).email()) {
913 QString email = QString::fromUtf8(key.userID(iMail).email());
914 // ### work around gpgme 0.3.QString text() const Q_DECL_OVERRIDE;x / cryptplug bug where the
915 // ### email addresses are specified as angle-addr, not addr-spec:
916 if (email.startsWith(QLatin1Char('<')) && email.endsWith(QLatin1Char('>'))) {
917 email = email.mid(1, email.length() - 2);
918 }
919 if (!email.isEmpty()) {
920 mMetaData.signerMailAddresses.append(email);
921 }
922 }
923 }
924
925 if (signature.creationTime()) {
926 mMetaData.creationTime.setTime_t(signature.creationTime());
927 } else {
928 mMetaData.creationTime = QDateTime();
929 }
930 if (mMetaData.signer.isEmpty()) {
931 if (key.numUserIDs() > 0 && key.userID(0).name()) {
932 mMetaData.signer = prettifyDN(key.userID(0).name());
933 }
934 if (!mMetaData.signerMailAddresses.empty()) {
935 if (mMetaData.signer.isEmpty()) {
936 mMetaData.signer = mMetaData.signerMailAddresses.front();
937 } else {
938 mMetaData.signer += QLatin1String(" <") + mMetaData.signerMailAddresses.front() + QLatin1Char('>');
939 }
940 }
941 }
942 }
943}
944
945void SignedMessagePart::startVerification(const QByteArray &text, const QTextCodec *aCodec)
946{
947 startVerificationDetached(text, nullptr, QByteArray());
948
949 if (!mNode && mMetaData.isSigned) {
950 setText(aCodec->toUnicode(mVerifiedText));
951 }
952}
953
954void SignedMessagePart::startVerificationDetached(const QByteArray &text, KMime::Content *textNode, const QByteArray &signature)
955{
956 mMetaData.isEncrypted = false;
957 mMetaData.isDecryptable = false;
958
959 if (textNode) {
960 parseInternal(textNode, false);
961 }
962
963 okVerify(text, signature, textNode);
964
965 if (!mMetaData.isSigned) {
966 mMetaData.creationTime = QDateTime();
967 }
968}
969
970void SignedMessagePart::setVerificationResult(const CryptoBodyPartMemento *m, KMime::Content *textNode)
971{
972 {
973 const auto vm = dynamic_cast<const VerifyDetachedBodyPartMemento *>(m);
974 if (vm) {
975 mSignatures = vm->verifyResult().signatures();
976 }
977 }
978 {
979 const auto vm = dynamic_cast<const VerifyOpaqueBodyPartMemento *>(m);
980 if (vm) {
981 mVerifiedText = vm->plainText();
982 mSignatures = vm->verifyResult().signatures();
983 }
984 }
985 {
986 const auto vm = dynamic_cast<const DecryptVerifyBodyPartMemento *>(m);
987 if (vm) {
988 mVerifiedText = vm->plainText();
989 mSignatures = vm->verifyResult().signatures();
990 }
991 }
992 mMetaData.auditLogError = m->auditLogError();
993 mMetaData.auditLog = m->auditLogAsHtml();
994 mMetaData.isSigned = !mSignatures.empty();
995
996 if (mMetaData.isSigned) {
997 sigStatusToMetaData();
998 if (mNode) {
999 mOtp->nodeHelper()->setSignatureState(mNode, KMMsgFullySigned);
1000 if (!textNode) {
1001 mOtp->mNodeHelper->setPartMetaData(mNode, mMetaData);
1002
1003 if (!mVerifiedText.isEmpty()) {
1004 auto tempNode = new KMime::Content();
1005 tempNode->setContent(KMime::CRLFtoLF(mVerifiedText.constData()));
1006 tempNode->parse();
1007
1008 if (!tempNode->head().isEmpty()) {
1009 tempNode->contentDescription()->from7BitString("signed data");
1010 }
1011 mOtp->mNodeHelper->attachExtraContent(mNode, tempNode);
1012
1013 parseInternal(tempNode, false);
1014 }
1015 }
1016 }
1017 }
1018}
1019
1020QString SignedMessagePart::plaintextContent() const
1021{
1022 if (!mNode) {
1023 return MessagePart::text();
1024 } else {
1025 return QString();
1026 }
1027}
1028
1029QString SignedMessagePart::htmlContent() const
1030{
1031 if (!mNode) {
1032 return MessagePart::text();
1033 } else {
1034 return QString();
1035 }
1036}
1037
1038//-----CryptMessageBlock---------------------
1039EncryptedMessagePart::EncryptedMessagePart(ObjectTreeParser *otp,
1040 const QString &text,
1041 const QGpgME::Protocol *cryptoProto,
1042 const QString &fromAddress,
1043 KMime::Content *node)
1044 : MessagePart(otp, text)
1045 , mPassphraseError(false)
1046 , mNoSecKey(false)
1047 , mCryptoProto(cryptoProto)
1048 , mFromAddress(fromAddress)
1049 , mNode(node)
1050 , mDecryptMessage(false)
1051{
1052 mMetaData.technicalProblem = (mCryptoProto == nullptr);
1053 mMetaData.isSigned = false;
1054 mMetaData.isGoodSignature = false;
1055 mMetaData.isEncrypted = false;
1056 mMetaData.isDecryptable = false;
1057 mMetaData.keyTrust = GpgME::Signature::Unknown;
1058 mMetaData.status = i18n("Wrong Crypto Plug-In.");
1059 mMetaData.status_code = GPGME_SIG_STAT_NONE;
1060}
1061
1062EncryptedMessagePart::~EncryptedMessagePart()
1063{
1064
1065}
1066
1067void EncryptedMessagePart::setDecryptMessage(bool decrypt)
1068{
1069 mDecryptMessage = decrypt;
1070}
1071
1072bool EncryptedMessagePart::decryptMessage() const
1073{
1074 return mDecryptMessage;
1075}
1076
1077void EncryptedMessagePart::setIsEncrypted(bool encrypted)
1078{
1079 mMetaData.isEncrypted = encrypted;
1080}
1081
1082bool EncryptedMessagePart::isEncrypted() const
1083{
1084 return mMetaData.isEncrypted;
1085}
1086
1087bool EncryptedMessagePart::isDecryptable() const
1088{
1089 return mMetaData.isDecryptable;
1090}
1091
1092bool EncryptedMessagePart::passphraseError() const
1093{
1094 return mPassphraseError;
1095}
1096
1097void EncryptedMessagePart::startDecryption(const QByteArray &text, const QTextCodec *aCodec)
1098{
1099 KMime::Content *content = new KMime::Content;
1100 content->setBody(text);
1101 content->parse();
1102
1103 startDecryption(content);
1104
1105 if (!mMetaData.inProgress && mMetaData.isDecryptable) {
1106 if (hasSubParts()) {
1107 auto _mp = (subParts()[0]).dynamicCast<SignedMessagePart>();
1108 if (_mp) {
1109 _mp->setText(aCodec->toUnicode(mDecryptedData));
1110 } else {
1111 setText(aCodec->toUnicode(mDecryptedData));
1112 }
1113 } else {
1114 setText(aCodec->toUnicode(mDecryptedData));
1115 }
1116 }
1117}
1118
1119bool EncryptedMessagePart::okDecryptMIME(KMime::Content &data)
1120{
1121 mPassphraseError = false;
1122 mMetaData.inProgress = false;
1123 mMetaData.errorText.clear();
1124 mMetaData.auditLogError = GpgME::Error();
1125 mMetaData.auditLog.clear();
1126 bool bDecryptionOk = false;
1127 bool cannotDecrypt = false;
1128 Interface::ObjectTreeSource *_source = source();
1129 NodeHelper *nodeHelper = mOtp->nodeHelper();
1130
1131 Q_ASSERT(decryptMessage());
1132
1133 // Check whether the memento contains a result from last time:
1134 const DecryptVerifyBodyPartMemento *m
1135 = dynamic_cast<DecryptVerifyBodyPartMemento *>(nodeHelper->bodyPartMemento(&data, "decryptverify"));
1136
1137 Q_ASSERT(!m || mCryptoProto); //No CryptoPlugin and having a bodyPartMemento -> there is something completely wrong
1138
1139 if (!m && mCryptoProto) {
1140 QGpgME::DecryptVerifyJob *job = mCryptoProto->decryptVerifyJob();
1141 if (!job) {
1142 cannotDecrypt = true;
1143 } else {
1144 const QByteArray ciphertext = data.decodedContent();
1145 DecryptVerifyBodyPartMemento *newM
1146 = new DecryptVerifyBodyPartMemento(job, ciphertext);
1147 if (mOtp->allowAsync()) {
1148 QObject::connect(newM, &CryptoBodyPartMemento::update,
1149 nodeHelper, &NodeHelper::update);
1150 QObject::connect(newM, SIGNAL(update(MimeTreeParser::UpdateMode)), _source->sourceObject(),
1151 SLOT(update(MimeTreeParser::UpdateMode)));
1152 if (newM->start()) {
1153 mMetaData.inProgress = true;
1154 mOtp->mHasPendingAsyncJobs = true;
1155 } else {
1156 m = newM;
1157 }
1158 } else {
1159 newM->exec();
1160 m = newM;
1161 }
1162 nodeHelper->setBodyPartMemento(&data, "decryptverify", newM);
1163 }
1164 } else if (m->isRunning()) {
1165 mMetaData.inProgress = true;
1166 mOtp->mHasPendingAsyncJobs = true;
1167 m = nullptr;
1168 }
1169
1170 if (m) {
1171 const QByteArray &plainText = m->plainText();
1172 const GpgME::DecryptionResult &decryptResult = m->decryptResult();
1173 const GpgME::VerificationResult &verifyResult = m->verifyResult();
1174 mMetaData.isSigned = verifyResult.signatures().size() > 0;
1175
1176 if (verifyResult.signatures().size() > 0) {
1177 auto subPart = SignedMessagePart::Ptr(new SignedMessagePart(mOtp, MessagePart::text(), mCryptoProto, mFromAddress, mNode));
1178 subPart->setVerificationResult(m, nullptr);
1179 appendSubPart(subPart);
1180 }
1181
1182 mDecryptRecipients = decryptResult.recipients();
1183 bDecryptionOk = !decryptResult.error();
1184// std::stringstream ss;
1185// ss << decryptResult << '\n' << verifyResult;
1186// qCDebug(MIMETREEPARSER_LOG) << ss.str().c_str();
1187
1188 if (!bDecryptionOk && mMetaData.isSigned) {
1189 //Only a signed part
1190 mMetaData.isEncrypted = false;
1191 bDecryptionOk = true;
1192 mDecryptedData = plainText;
1193 } else {
1194 mPassphraseError = decryptResult.error().isCanceled() || decryptResult.error().code() == GPG_ERR_NO_SECKEY;
1195 mMetaData.isEncrypted = decryptResult.error().code() != GPG_ERR_NO_DATA;
1196 mMetaData.errorText = QString::fromLocal8Bit(decryptResult.error().asString());
1197 if (mMetaData.isEncrypted && decryptResult.numRecipients() > 0) {
1198 mMetaData.keyId = decryptResult.recipient(0).keyID();
1199 }
1200
1201 if (bDecryptionOk) {
1202 mDecryptedData = plainText;
1203 } else {
1204 mNoSecKey = true;
1205 foreach (const GpgME::DecryptionResult::Recipient &recipient, decryptResult.recipients()) {
1206 mNoSecKey &= (recipient.status().code() == GPG_ERR_NO_SECKEY);
1207 }
1208 if (!mPassphraseError && !mNoSecKey) { // GpgME do not detect passphrase error correctly
1209 mPassphraseError = true;
1210 }
1211 }
1212 }
1213 }
1214
1215 if (!bDecryptionOk) {
1216 QString cryptPlugLibName;
1217 if (mCryptoProto) {
1218 cryptPlugLibName = mCryptoProto->name();
1219 }
1220
1221 if (!mCryptoProto) {
1222 mMetaData.errorText = i18n("No appropriate crypto plug-in was found.");
1223 } else if (cannotDecrypt) {
1224 mMetaData.errorText = i18n("Crypto plug-in \"%1\" cannot decrypt messages.",
1225 cryptPlugLibName);
1226 } else if (!passphraseError()) {
1227 mMetaData.errorText = i18n("Crypto plug-in \"%1\" could not decrypt the data.", cryptPlugLibName)
1228 + QLatin1String("<br />")
1229 + i18n("Error: %1", mMetaData.errorText);
1230 }
1231 }
1232 return bDecryptionOk;
1233}
1234
1235void EncryptedMessagePart::startDecryption(KMime::Content *data)
1236{
1237 if (!mNode && !data) {
1238 return;
1239 }
1240
1241 if (!data) {
1242 data = mNode;
1243 }
1244
1245 mMetaData.isEncrypted = true;
1246
1247 bool bOkDecrypt = okDecryptMIME(*data);
1248
1249 if (mMetaData.inProgress) {
1250 return;
1251 }
1252 mMetaData.isDecryptable = bOkDecrypt;
1253
1254 if (!mMetaData.isDecryptable) {
1255 setText(QString::fromUtf8(mDecryptedData.constData()));
1256 }
1257
1258 if (mMetaData.isEncrypted && !decryptMessage()) {
1259 mMetaData.isDecryptable = true;
1260 }
1261
1262 if (mNode && !mMetaData.isSigned) {
1263 mOtp->mNodeHelper->setPartMetaData(mNode, mMetaData);
1264
1265 if (decryptMessage()) {
1266 auto tempNode = new KMime::Content();
1267 tempNode->setContent(KMime::CRLFtoLF(mDecryptedData.constData()));
1268 tempNode->parse();
1269
1270 if (!tempNode->head().isEmpty()) {
1271 tempNode->contentDescription()->from7BitString("encrypted data");
1272 }
1273 mOtp->mNodeHelper->attachExtraContent(mNode, tempNode);
1274
1275 parseInternal(tempNode, false);
1276 }
1277 }
1278}
1279
1280QString EncryptedMessagePart::plaintextContent() const
1281{
1282 if (!mNode) {
1283 return MessagePart::text();
1284 } else {
1285 return QString();
1286 }
1287}
1288
1289QString EncryptedMessagePart::htmlContent() const
1290{
1291 if (!mNode) {
1292 return MessagePart::text();
1293 } else {
1294 return QString();
1295 }
1296}
1297
1298QString EncryptedMessagePart::text() const
1299{
1300 if (hasSubParts()) {
1301 auto _mp = (subParts()[0]).dynamicCast<SignedMessagePart>();
1302 if (_mp) {
1303 return _mp->text();
1304 } else {
1305 return MessagePart::text();
1306 }
1307 } else {
1308 return MessagePart::text();
1309 }
1310}
1311
1312EncapsulatedRfc822MessagePart::EncapsulatedRfc822MessagePart(ObjectTreeParser *otp, KMime::Content *node, const KMime::Message::Ptr &message)
1313 : MessagePart(otp, QString())
1314 , mMessage(message)
1315 , mNode(node)
1316{
1317 mMetaData.isEncrypted = false;
1318 mMetaData.isSigned = false;
1319 mMetaData.isEncapsulatedRfc822Message = true;
1320
1321 mOtp->nodeHelper()->setNodeDisplayedEmbedded(mNode, true);
1322 mOtp->nodeHelper()->setPartMetaData(mNode, mMetaData);
1323
1324 if (!mMessage) {
1325 qCWarning(MIMETREEPARSER_LOG) << "Node is of type message/rfc822 but doesn't have a message!";
1326 return;
1327 }
1328
1329 // The link to "Encapsulated message" is clickable, therefore the temp file needs to exists,
1330 // since the user can click the link and expect to have normal attachment operations there.
1331 mOtp->nodeHelper()->writeNodeToTempFile(message.data());
1332
1333 parseInternal(message.data(), false);
1334}
1335
1336EncapsulatedRfc822MessagePart::~EncapsulatedRfc822MessagePart()
1337{
1338
1339}
1340
1341QString EncapsulatedRfc822MessagePart::text() const
1342{
1343 return renderInternalText();
1344}
1345
1346void EncapsulatedRfc822MessagePart::copyContentFrom() const
1347{
1348}
1349
1350void EncapsulatedRfc822MessagePart::fix() const
1351{
1352}
diff --git a/framework/src/domain/mimetreeparser/otp/messagepart.h b/framework/src/domain/mimetreeparser/otp/messagepart.h
new file mode 100644
index 00000000..433f3f6b
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/messagepart.h
@@ -0,0 +1,422 @@
1/*
2 Copyright (c) 2015 Sandro Knauß <sknauss@kde.org>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20#ifndef __MIMETREEPARSER_MESSAGEPART_H__
21#define __MIMETREEPARSER_MESSAGEPART_H__
22
23#include "bodypartformatter.h"
24#include "util.h"
25
26#include <KMime/Message>
27
28#include <gpgme++/verificationresult.h>
29#include <gpgme++/decryptionresult.h>
30#include <gpgme++/importresult.h>
31
32#include <QString>
33#include <QSharedPointer>
34
35class QTextCodec;
36class PartPrivate;
37
38namespace GpgME
39{
40class ImportResult;
41}
42
43namespace QGpgME
44{
45class Protocol;
46}
47
48namespace KMime
49{
50class Content;
51}
52
53namespace MimeTreeParser
54{
55class ObjectTreeParser;
56class HtmlWriter;
57class HTMLBlock;
58typedef QSharedPointer<HTMLBlock> HTMLBlockPtr;
59class CryptoBodyPartMemento;
60class MultiPartAlternativeBodyPartFormatter;
61namespace Interface
62{
63class ObjectTreeSource;
64}
65
66class MessagePart : public Interface::MessagePart
67{
68 Q_OBJECT
69 Q_PROPERTY(bool attachment READ isAttachment)
70 Q_PROPERTY(bool root READ isRoot)
71 Q_PROPERTY(bool isHtml READ isHtml)
72 Q_PROPERTY(bool isHidden READ isHidden)
73public:
74 typedef QSharedPointer<MessagePart> Ptr;
75 MessagePart(ObjectTreeParser *otp,
76 const QString &text);
77
78 virtual ~MessagePart();
79
80 virtual QString text() const Q_DECL_OVERRIDE;
81 void setText(const QString &text);
82 void setAttachmentFlag(KMime::Content *node);
83 bool isAttachment() const;
84
85 void setIsRoot(bool root);
86 bool isRoot() const;
87
88 virtual bool isHtml() const;
89 virtual bool isHidden() const;
90
91 PartMetaData *partMetaData();
92
93 /* only a function that should be removed if the refactoring is over */
94 virtual void fix() const;
95 virtual void copyContentFrom() const;
96
97 void appendSubPart(const Interface::MessagePart::Ptr &messagePart);
98 const QVector<Interface::MessagePart::Ptr> &subParts() const;
99 bool hasSubParts() const;
100
101 HtmlWriter *htmlWriter() const Q_DECL_OVERRIDE;
102 void setHtmlWriter(HtmlWriter *htmlWriter) const Q_DECL_OVERRIDE;
103
104 Interface::ObjectTreeSource *source() const;
105 KMime::Content *attachmentNode() const;
106
107protected:
108 void parseInternal(KMime::Content *node, bool onlyOneMimePart);
109 QString renderInternalText() const;
110
111 QString mText;
112 ObjectTreeParser *mOtp;
113 PartMetaData mMetaData;
114
115private:
116 QVector<Interface::MessagePart::Ptr> mBlocks;
117
118 KMime::Content *mAttachmentNode;
119 bool mRoot;
120};
121
122class MimeMessagePart : public MessagePart
123{
124 Q_OBJECT
125public:
126 typedef QSharedPointer<MimeMessagePart> Ptr;
127 MimeMessagePart(MimeTreeParser::ObjectTreeParser *otp, KMime::Content *node, bool onlyOneMimePart);
128 virtual ~MimeMessagePart();
129
130 QString text() const Q_DECL_OVERRIDE;
131
132 QString plaintextContent() const Q_DECL_OVERRIDE;
133 QString htmlContent() const Q_DECL_OVERRIDE;
134private:
135 KMime::Content *mNode;
136 bool mOnlyOneMimePart;
137
138 friend class AlternativeMessagePart;
139 friend class ::PartPrivate;
140};
141
142class MessagePartList : public MessagePart
143{
144 Q_OBJECT
145public:
146 typedef QSharedPointer<MessagePartList> Ptr;
147 MessagePartList(MimeTreeParser::ObjectTreeParser *otp);
148 virtual ~MessagePartList();
149
150 QString text() const Q_DECL_OVERRIDE;
151
152 QString plaintextContent() const Q_DECL_OVERRIDE;
153 QString htmlContent() const Q_DECL_OVERRIDE;
154private:
155};
156
157enum IconType {
158 NoIcon = 0,
159 IconExternal,
160 IconInline
161};
162
163class TextMessagePart : public MessagePartList
164{
165 Q_OBJECT
166public:
167 typedef QSharedPointer<TextMessagePart> Ptr;
168 TextMessagePart(MimeTreeParser::ObjectTreeParser *otp, KMime::Content *node, bool drawFrame, bool showLink, bool decryptMessage);
169 virtual ~TextMessagePart();
170
171 KMMsgSignatureState signatureState() const;
172 KMMsgEncryptionState encryptionState() const;
173
174 bool decryptMessage() const;
175
176 bool isHidden() const Q_DECL_OVERRIDE;
177
178 bool showLink() const;
179 bool showTextFrame() const;
180
181protected:
182 KMime::Content *mNode;
183
184private:
185 void parseContent();
186
187 KMMsgSignatureState mSignatureState;
188 KMMsgEncryptionState mEncryptionState;
189 bool mDrawFrame;
190 bool mShowLink;
191 bool mDecryptMessage;
192 bool mIsHidden;
193
194 friend class DefaultRendererPrivate;
195 friend class ObjectTreeParser;
196 friend class ::PartPrivate;
197};
198
199class AttachmentMessagePart : public TextMessagePart
200{
201 Q_OBJECT
202public:
203 typedef QSharedPointer<AttachmentMessagePart> Ptr;
204 AttachmentMessagePart(MimeTreeParser::ObjectTreeParser *otp, KMime::Content *node, bool drawFrame, bool showLink, bool decryptMessage);
205 virtual ~AttachmentMessagePart();
206
207 IconType asIcon() const;
208 bool neverDisplayInline() const;
209 void setNeverDisplayInline(bool displayInline);
210 bool isImage() const;
211 void setIsImage(bool image);
212
213 bool isHidden() const Q_DECL_OVERRIDE;
214
215private:
216 bool mIsImage;
217 bool mNeverDisplayInline;
218};
219
220class HtmlMessagePart : public MessagePart
221{
222 Q_OBJECT
223public:
224 typedef QSharedPointer<HtmlMessagePart> Ptr;
225 HtmlMessagePart(MimeTreeParser::ObjectTreeParser *otp, KMime::Content *node, MimeTreeParser::Interface::ObjectTreeSource *source);
226 virtual ~HtmlMessagePart();
227
228 QString text() const Q_DECL_OVERRIDE;
229
230 void fix() const Q_DECL_OVERRIDE;
231 bool isHtml() const Q_DECL_OVERRIDE;
232
233private:
234 KMime::Content *mNode;
235 Interface::ObjectTreeSource *mSource;
236 QString mBodyHTML;
237 QByteArray mCharset;
238
239 friend class DefaultRendererPrivate;
240 friend class ::PartPrivate;
241};
242
243class AlternativeMessagePart : public MessagePart
244{
245 Q_OBJECT
246public:
247 typedef QSharedPointer<AlternativeMessagePart> Ptr;
248 AlternativeMessagePart(MimeTreeParser::ObjectTreeParser *otp, KMime::Content *node, Util::HtmlMode preferredMode);
249 virtual ~AlternativeMessagePart();
250
251 QString text() const Q_DECL_OVERRIDE;
252
253 Util::HtmlMode preferredMode() const;
254
255 bool isHtml() const Q_DECL_OVERRIDE;
256
257 QString plaintextContent() const Q_DECL_OVERRIDE;
258 QString htmlContent() const Q_DECL_OVERRIDE;
259
260 QList<Util::HtmlMode> availableModes();
261
262 void fix() const Q_DECL_OVERRIDE;
263 void copyContentFrom() const Q_DECL_OVERRIDE;
264private:
265 KMime::Content *mNode;
266
267 Util::HtmlMode mPreferredMode;
268
269 QMap<Util::HtmlMode, KMime::Content *> mChildNodes;
270 QMap<Util::HtmlMode, MimeMessagePart::Ptr> mChildParts;
271
272 friend class DefaultRendererPrivate;
273 friend class ObjectTreeParser;
274 friend class MultiPartAlternativeBodyPartFormatter;
275 friend class ::PartPrivate;
276};
277
278class CertMessagePart : public MessagePart
279{
280 Q_OBJECT
281public:
282 typedef QSharedPointer<CertMessagePart> Ptr;
283 CertMessagePart(MimeTreeParser::ObjectTreeParser *otp, KMime::Content *node, const QGpgME::Protocol *cryptoProto, bool autoImport);
284 virtual ~CertMessagePart();
285
286 QString text() const Q_DECL_OVERRIDE;
287
288private:
289 KMime::Content *mNode;
290 bool mAutoImport;
291 GpgME::ImportResult mImportResult;
292 const QGpgME::Protocol *mCryptoProto;
293 friend class DefaultRendererPrivate;
294};
295
296class EncapsulatedRfc822MessagePart : public MessagePart
297{
298 Q_OBJECT
299public:
300 typedef QSharedPointer<EncapsulatedRfc822MessagePart> Ptr;
301 EncapsulatedRfc822MessagePart(MimeTreeParser::ObjectTreeParser *otp, KMime::Content *node, const KMime::Message::Ptr &message);
302 virtual ~EncapsulatedRfc822MessagePart();
303
304 QString text() const Q_DECL_OVERRIDE;
305
306 void copyContentFrom() const Q_DECL_OVERRIDE;
307 void fix() const Q_DECL_OVERRIDE;
308private:
309 const KMime::Message::Ptr mMessage;
310 KMime::Content *mNode;
311
312 friend class DefaultRendererPrivate;
313};
314
315class EncryptedMessagePart : public MessagePart
316{
317 Q_OBJECT
318 Q_PROPERTY(bool decryptMessage READ decryptMessage WRITE setDecryptMessage)
319 Q_PROPERTY(bool isEncrypted READ isEncrypted)
320 Q_PROPERTY(bool passphraseError READ passphraseError)
321public:
322 typedef QSharedPointer<EncryptedMessagePart> Ptr;
323 EncryptedMessagePart(ObjectTreeParser *otp,
324 const QString &text,
325 const QGpgME::Protocol *cryptoProto,
326 const QString &fromAddress,
327 KMime::Content *node);
328
329 virtual ~EncryptedMessagePart();
330
331 QString text() const Q_DECL_OVERRIDE;
332
333 void setDecryptMessage(bool decrypt);
334 bool decryptMessage() const;
335
336 void setIsEncrypted(bool encrypted);
337 bool isEncrypted() const;
338
339 bool isDecryptable() const;
340
341 bool passphraseError() const;
342
343 void startDecryption(const QByteArray &text, const QTextCodec *aCodec);
344 void startDecryption(KMime::Content *data = nullptr);
345
346 QByteArray mDecryptedData;
347
348 QString plaintextContent() const Q_DECL_OVERRIDE;
349 QString htmlContent() const Q_DECL_OVERRIDE;
350
351private:
352 /** Handles the dectyptioon of a given content
353 * returns true if the decryption was successfull
354 * if used in async mode, check if mMetaData.inProgress is true, it inicates a running decryption process.
355 */
356 bool okDecryptMIME(KMime::Content &data);
357
358protected:
359 bool mPassphraseError;
360 bool mNoSecKey;
361 const QGpgME::Protocol *mCryptoProto;
362 QString mFromAddress;
363 KMime::Content *mNode;
364 bool mDecryptMessage;
365 QByteArray mVerifiedText;
366 std::vector<GpgME::DecryptionResult::Recipient> mDecryptRecipients;
367
368 friend class DefaultRendererPrivate;
369 friend class ::PartPrivate;
370};
371
372class SignedMessagePart : public MessagePart
373{
374 Q_OBJECT
375 Q_PROPERTY(bool isSigned READ isSigned)
376public:
377 typedef QSharedPointer<SignedMessagePart> Ptr;
378 SignedMessagePart(ObjectTreeParser *otp,
379 const QString &text,
380 const QGpgME::Protocol *cryptoProto,
381 const QString &fromAddress,
382 KMime::Content *node);
383
384 virtual ~SignedMessagePart();
385
386 void setIsSigned(bool isSigned);
387 bool isSigned() const;
388
389 void startVerification(const QByteArray &text, const QTextCodec *aCodec);
390 void startVerificationDetached(const QByteArray &text, KMime::Content *textNode, const QByteArray &signature);
391
392 QByteArray mDecryptedData;
393 std::vector<GpgME::Signature> mSignatures;
394
395 QString plaintextContent() const Q_DECL_OVERRIDE;
396 QString htmlContent() const Q_DECL_OVERRIDE;
397
398private:
399 /** Handles the verification of data
400 * If signature is empty it is handled as inline signature otherwise as detached signature mode.
401 * Returns true if the verfication was successfull and the block is signed.
402 * If used in async mode, check if mMetaData.inProgress is true, it inicates a running verification process.
403 */
404 bool okVerify(const QByteArray &data, const QByteArray &signature, KMime::Content *textNode);
405
406 void sigStatusToMetaData();
407
408 void setVerificationResult(const CryptoBodyPartMemento *m, KMime::Content *textNode);
409protected:
410 const QGpgME::Protocol *mCryptoProto;
411 QString mFromAddress;
412 KMime::Content *mNode;
413 QByteArray mVerifiedText;
414
415 friend EncryptedMessagePart;
416 friend class DefaultRendererPrivate;
417 friend class ::PartPrivate;
418};
419
420}
421
422#endif //__MIMETREEPARSER_MESSAGEPART_H__
diff --git a/framework/src/domain/mimetreeparser/otp/messagepartrenderer.cpp b/framework/src/domain/mimetreeparser/otp/messagepartrenderer.cpp
new file mode 100644
index 00000000..7f622268
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/messagepartrenderer.cpp
@@ -0,0 +1,23 @@
1/*
2 Copyright (C) 2016 Sandro Knauß <sknauss@kde.org>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17*/
18
19#include "messagepartrenderer.h"
20
21MimeTreeParser::Interface::MessagePartRenderer::~MessagePartRenderer()
22{
23}
diff --git a/framework/src/domain/mimetreeparser/otp/messagepartrenderer.h b/framework/src/domain/mimetreeparser/otp/messagepartrenderer.h
new file mode 100644
index 00000000..a90c17e6
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/messagepartrenderer.h
@@ -0,0 +1,43 @@
1/*
2 Copyright (C) 2016 Sandro Knauß <sknauss@kde.org>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17*/
18
19#ifndef __MIMETREEPARSER_MESSAGEPARTRENDERER_IF_H__
20#define __MIMETREEPARSER_MESSAGEPARTRENDERER_IF_H__
21
22#include <QSharedPointer>
23
24namespace MimeTreeParser
25{
26namespace Interface
27{
28/**
29* Interface for rendering messageparts to html.
30* @author Andras Mantia <sknauss@kde.org>
31*/
32class MessagePartRenderer
33{
34public:
35 typedef QSharedPointer<MessagePartRenderer> Ptr;
36
37 virtual ~MessagePartRenderer();
38
39 virtual QString html() const = 0;
40};
41}
42}
43#endif
diff --git a/framework/src/domain/mimetreeparser/otp/mimetreeparser_debug.cpp b/framework/src/domain/mimetreeparser/otp/mimetreeparser_debug.cpp
new file mode 100644
index 00000000..f8ac36cd
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/mimetreeparser_debug.cpp
@@ -0,0 +1,3 @@
1#include "mimetreeparser_debug.h"
2
3Q_LOGGING_CATEGORY(MIMETREEPARSER_LOG, "mimetreeparser")
diff --git a/framework/src/domain/mimetreeparser/otp/mimetreeparser_debug.h b/framework/src/domain/mimetreeparser/otp/mimetreeparser_debug.h
new file mode 100644
index 00000000..ddfa6315
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/mimetreeparser_debug.h
@@ -0,0 +1,4 @@
1#pragma once
2
3#include <QLoggingCategory>
4Q_DECLARE_LOGGING_CATEGORY(MIMETREEPARSER_LOG)
diff --git a/framework/src/domain/mimetreeparser/otp/nodehelper.cpp b/framework/src/domain/mimetreeparser/otp/nodehelper.cpp
new file mode 100644
index 00000000..8e224f1b
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/nodehelper.cpp
@@ -0,0 +1,1069 @@
1/*
2 Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
3 Copyright (c) 2009 Andras Mantia <andras@kdab.net>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18*/
19
20#include "nodehelper.h"
21#include "mimetreeparser_debug.h"
22#include "partmetadata.h"
23#include "bodypart.h"
24#include "attachmenttemporaryfilesdirs.h"
25
26#include <KMime/Content>
27#include <KMime/Message>
28#include <KMime/Headers>
29
30#include <QTemporaryFile>
31#include <KLocalizedString>
32#include <kcharsets.h>
33
34#include <QUrl>
35#include <QDir>
36#include <QTextCodec>
37
38#include <string>
39#include <sstream>
40#include <algorithm>
41#include <KCharsets>
42#include <QMimeDatabase>
43#include <QMimeType>
44#include <QFileDevice>
45
46namespace MimeTreeParser
47{
48
49QStringList replySubjPrefixes(QStringList() << QStringLiteral("Re\\s*:") << QStringLiteral("Re\\[\\d+\\]:") << QStringLiteral("Re\\d+:"));
50QStringList forwardSubjPrefixes(QStringList() << QStringLiteral("Fwd:") << QStringLiteral("FW:"));
51
52NodeHelper::NodeHelper() :
53 mAttachmentFilesDir(new AttachmentTemporaryFilesDirs())
54{
55 //TODO(Andras) add methods to modify these prefixes
56
57 mLocalCodec = QTextCodec::codecForLocale();
58
59 // In the case of Japan. Japanese locale name is "eucjp" but
60 // The Japanese mail systems normally used "iso-2022-jp" of locale name.
61 // We want to change locale name from eucjp to iso-2022-jp at KMail only.
62
63 // (Introduction to i18n, 6.6 Limit of Locale technology):
64 // EUC-JP is the de-facto standard for UNIX systems, ISO 2022-JP
65 // is the standard for Internet, and Shift-JIS is the encoding
66 // for Windows and Macintosh.
67 if (mLocalCodec) {
68 const QByteArray codecNameLower = mLocalCodec->name().toLower();
69 if (codecNameLower == "eucjp"
70#if defined Q_OS_WIN || defined Q_OS_MACX
71 || codecNameLower == "shift-jis" // OK?
72#endif
73 ) {
74 mLocalCodec = QTextCodec::codecForName("jis7");
75 // QTextCodec *cdc = QTextCodec::codecForName("jis7");
76 // QTextCodec::setCodecForLocale(cdc);
77 // KLocale::global()->setEncoding(cdc->mibEnum());
78 }
79 }
80}
81
82NodeHelper::~NodeHelper()
83{
84 if (mAttachmentFilesDir) {
85 mAttachmentFilesDir->forceCleanTempFiles();
86 delete mAttachmentFilesDir;
87 mAttachmentFilesDir = nullptr;
88 }
89 clear();
90}
91
92void NodeHelper::setNodeProcessed(KMime::Content *node, bool recurse)
93{
94 if (!node) {
95 return;
96 }
97 mProcessedNodes.append(node);
98 qCDebug(MIMETREEPARSER_LOG) << "Node processed: " << node->index().toString() << node->contentType()->as7BitString();
99 //<< " decodedContent" << node->decodedContent();
100 if (recurse) {
101 const auto contents = node->contents();
102 for (KMime::Content *c : contents) {
103 setNodeProcessed(c, true);
104 }
105 }
106}
107
108void NodeHelper::setNodeUnprocessed(KMime::Content *node, bool recurse)
109{
110 if (!node) {
111 return;
112 }
113 mProcessedNodes.removeAll(node);
114
115 //avoid double addition of extra nodes, eg. encrypted attachments
116 const QMap<KMime::Content *, QList<KMime::Content *> >::iterator it = mExtraContents.find(node);
117 if (it != mExtraContents.end()) {
118 Q_FOREACH (KMime::Content *c, it.value()) {
119 KMime::Content *p = c->parent();
120 if (p) {
121 p->removeContent(c);
122 }
123 }
124 qDeleteAll(it.value());
125 qCDebug(MIMETREEPARSER_LOG) << "mExtraContents deleted for" << it.key();
126 mExtraContents.erase(it);
127 }
128
129 qCDebug(MIMETREEPARSER_LOG) << "Node UNprocessed: " << node;
130 if (recurse) {
131 const auto contents = node->contents();
132 for (KMime::Content *c : contents) {
133 setNodeUnprocessed(c, true);
134 }
135 }
136}
137
138bool NodeHelper::nodeProcessed(KMime::Content *node) const
139{
140 if (!node) {
141 return true;
142 }
143 return mProcessedNodes.contains(node);
144}
145
146static void clearBodyPartMemento(QMap<QByteArray, Interface::BodyPartMemento *> &bodyPartMementoMap)
147{
148 for (QMap<QByteArray, Interface::BodyPartMemento *>::iterator
149 it = bodyPartMementoMap.begin(), end = bodyPartMementoMap.end();
150 it != end; ++it) {
151 Interface::BodyPartMemento *memento = it.value();
152 memento->detach();
153 delete memento;
154 }
155 bodyPartMementoMap.clear();
156}
157
158void NodeHelper::clear()
159{
160 mProcessedNodes.clear();
161 mEncryptionState.clear();
162 mSignatureState.clear();
163 mOverrideCodecs.clear();
164 std::for_each(mBodyPartMementoMap.begin(), mBodyPartMementoMap.end(),
165 &clearBodyPartMemento);
166 mBodyPartMementoMap.clear();
167 QMap<KMime::Content *, QList<KMime::Content *> >::ConstIterator end(mExtraContents.constEnd());
168
169 for (QMap<KMime::Content *, QList<KMime::Content *> >::ConstIterator it = mExtraContents.constBegin(); it != end; ++it) {
170 Q_FOREACH (KMime::Content *c, it.value()) {
171 KMime::Content *p = c->parent();
172 if (p) {
173 p->removeContent(c);
174 }
175 }
176 qDeleteAll(it.value());
177 qCDebug(MIMETREEPARSER_LOG) << "mExtraContents deleted for" << it.key();
178 }
179 mExtraContents.clear();
180 mDisplayEmbeddedNodes.clear();
181 mDisplayHiddenNodes.clear();
182}
183
184void NodeHelper::setEncryptionState(const KMime::Content *node, const KMMsgEncryptionState state)
185{
186 mEncryptionState[node] = state;
187}
188
189KMMsgEncryptionState NodeHelper::encryptionState(const KMime::Content *node) const
190{
191 return mEncryptionState.value(node, KMMsgNotEncrypted);
192}
193
194void NodeHelper::setSignatureState(const KMime::Content *node, const KMMsgSignatureState state)
195{
196 mSignatureState[node] = state;
197}
198
199KMMsgSignatureState NodeHelper::signatureState(const KMime::Content *node) const
200{
201 return mSignatureState.value(node, KMMsgNotSigned);
202}
203
204PartMetaData NodeHelper::partMetaData(KMime::Content *node)
205{
206 return mPartMetaDatas.value(node, PartMetaData());
207}
208
209void NodeHelper::setPartMetaData(KMime::Content *node, const PartMetaData &metaData)
210{
211 mPartMetaDatas.insert(node, metaData);
212}
213
214QString NodeHelper::writeNodeToTempFile(KMime::Content *node)
215{
216 // If the message part is already written to a file, no point in doing it again.
217 // This function is called twice actually, once from the rendering of the attachment
218 // in the body and once for the header.
219 QUrl existingFileName = tempFileUrlFromNode(node);
220 if (!existingFileName.isEmpty()) {
221 return existingFileName.toLocalFile();
222 }
223
224 QString fname = createTempDir(persistentIndex(node));
225 if (fname.isEmpty()) {
226 return QString();
227 }
228
229 QString fileName = NodeHelper::fileName(node);
230 // strip off a leading path
231 int slashPos = fileName.lastIndexOf(QLatin1Char('/'));
232 if (-1 != slashPos) {
233 fileName = fileName.mid(slashPos + 1);
234 }
235 if (fileName.isEmpty()) {
236 fileName = QStringLiteral("unnamed");
237 }
238 fname += QLatin1Char('/') + fileName;
239
240 qCDebug(MIMETREEPARSER_LOG) << "Create temp file: " << fname;
241 QByteArray data = node->decodedContent();
242 if (node->contentType()->isText() && !data.isEmpty()) {
243 // convert CRLF to LF before writing text attachments to disk
244 data = KMime::CRLFtoLF(data);
245 }
246 QFile f(fname);
247 if (!f.open(QIODevice::ReadWrite)) {
248 qCWarning(MIMETREEPARSER_LOG) << "Failed to write note to file:" << f.errorString();
249 return QString();
250 }
251 f.write(data);
252 mAttachmentFilesDir->addTempFile(fname);
253 // make file read-only so that nobody gets the impression that he might
254 // edit attached files (cf. bug #52813)
255 f.setPermissions(QFileDevice::ReadUser);
256 f.close();
257
258 return fname;
259}
260
261QUrl NodeHelper::tempFileUrlFromNode(const KMime::Content *node)
262{
263 if (!node) {
264 return QUrl();
265 }
266
267 const QString index = persistentIndex(node);
268
269 foreach (const QString &path, mAttachmentFilesDir->temporaryFiles()) {
270 const int right = path.lastIndexOf(QLatin1Char('/'));
271 int left = path.lastIndexOf(QLatin1String(".index."), right);
272 if (left != -1) {
273 left += 7;
274 }
275
276 QStringRef storedIndex(&path, left, right - left);
277 if (left != -1 && storedIndex == index) {
278 return QUrl::fromLocalFile(path);
279 }
280 }
281 return QUrl();
282}
283
284QString NodeHelper::createTempDir(const QString &param)
285{
286 QTemporaryFile *tempFile = new QTemporaryFile(QDir::tempPath() + QLatin1String("/messageviewer_XXXXXX") + QLatin1String(".index.") + param);
287 tempFile->open();
288 const QString fname = tempFile->fileName();
289 delete tempFile;
290
291 QFile fFile(fname);
292 if (!(fFile.permissions() & QFileDevice::WriteUser)) {
293 // Not there or not writable
294 if (!QDir().mkpath(fname) ||
295 !fFile.setPermissions(QFileDevice::WriteUser | QFileDevice::ReadUser | QFileDevice::ExeUser)) {
296 return QString(); //failed create
297 }
298 }
299
300 Q_ASSERT(!fname.isNull());
301
302 mAttachmentFilesDir->addTempDir(fname);
303 return fname;
304}
305
306void NodeHelper::forceCleanTempFiles()
307{
308 mAttachmentFilesDir->forceCleanTempFiles();
309 delete mAttachmentFilesDir;
310 mAttachmentFilesDir = nullptr;
311}
312
313void NodeHelper::removeTempFiles()
314{
315 //Don't delete it it will delete in class
316 mAttachmentFilesDir->removeTempFiles();
317 mAttachmentFilesDir = new AttachmentTemporaryFilesDirs();
318}
319
320void NodeHelper::addTempFile(const QString &file)
321{
322 mAttachmentFilesDir->addTempFile(file);
323}
324
325bool NodeHelper::isInEncapsulatedMessage(KMime::Content *node)
326{
327 const KMime::Content *const topLevel = node->topLevel();
328 const KMime::Content *cur = node;
329 while (cur && cur != topLevel) {
330 const bool parentIsMessage = cur->parent() && cur->parent()->contentType(false) &&
331 cur->parent()->contentType()->mimeType().toLower() == "message/rfc822";
332 if (parentIsMessage && cur->parent() != topLevel) {
333 return true;
334 }
335 cur = cur->parent();
336 }
337 return false;
338}
339
340QByteArray NodeHelper::charset(KMime::Content *node)
341{
342 if (node->contentType(false)) {
343 return node->contentType(false)->charset();
344 } else {
345 return node->defaultCharset();
346 }
347}
348
349KMMsgEncryptionState NodeHelper::overallEncryptionState(KMime::Content *node) const
350{
351 KMMsgEncryptionState myState = KMMsgEncryptionStateUnknown;
352 if (!node) {
353 return myState;
354 }
355
356 KMime::Content *parent = node->parent();
357 auto contents = parent ? parent->contents() : KMime::Content::List();
358 if (contents.isEmpty()) {
359 contents.append(node);
360 }
361 int i = contents.indexOf(const_cast<KMime::Content *>(node));
362 for (; i < contents.size(); ++i) {
363 auto next = contents.at(i);
364 KMMsgEncryptionState otherState = encryptionState(next);
365
366 // NOTE: children are tested ONLY when parent is not encrypted
367 if (otherState == KMMsgNotEncrypted && !next->contents().isEmpty()) {
368 otherState = overallEncryptionState(next->contents().at(0));
369 }
370
371 if (otherState == KMMsgNotEncrypted && !extraContents(next).isEmpty()) {
372 otherState = overallEncryptionState(extraContents(next).at(0));
373 }
374
375 if (next == node) {
376 myState = otherState;
377 }
378
379 switch (otherState) {
380 case KMMsgEncryptionStateUnknown:
381 break;
382 case KMMsgNotEncrypted:
383 if (myState == KMMsgFullyEncrypted) {
384 myState = KMMsgPartiallyEncrypted;
385 } else if (myState != KMMsgPartiallyEncrypted) {
386 myState = KMMsgNotEncrypted;
387 }
388 break;
389 case KMMsgPartiallyEncrypted:
390 myState = KMMsgPartiallyEncrypted;
391 break;
392 case KMMsgFullyEncrypted:
393 if (myState != KMMsgFullyEncrypted) {
394 myState = KMMsgPartiallyEncrypted;
395 }
396 break;
397 case KMMsgEncryptionProblematic:
398 break;
399 }
400 }
401
402 qCDebug(MIMETREEPARSER_LOG) << "\n\n KMMsgEncryptionState:" << myState;
403
404 return myState;
405}
406
407KMMsgSignatureState NodeHelper::overallSignatureState(KMime::Content *node) const
408{
409 KMMsgSignatureState myState = KMMsgSignatureStateUnknown;
410 if (!node) {
411 return myState;
412 }
413
414 KMime::Content *parent = node->parent();
415 auto contents = parent ? parent->contents() : KMime::Content::List();
416 if (contents.isEmpty()) {
417 contents.append(node);
418 }
419 int i = contents.indexOf(const_cast<KMime::Content *>(node));
420 for (; i < contents.size(); ++i) {
421 auto next = contents.at(i);
422 KMMsgSignatureState otherState = signatureState(next);
423
424 // NOTE: children are tested ONLY when parent is not encrypted
425 if (otherState == KMMsgNotSigned && !next->contents().isEmpty()) {
426 otherState = overallSignatureState(next->contents().at(0));
427 }
428
429 if (otherState == KMMsgNotSigned && !extraContents(next).isEmpty()) {
430 otherState = overallSignatureState(extraContents(next).at(0));
431 }
432
433 if (next == node) {
434 myState = otherState;
435 }
436
437 switch (otherState) {
438 case KMMsgSignatureStateUnknown:
439 break;
440 case KMMsgNotSigned:
441 if (myState == KMMsgFullySigned) {
442 myState = KMMsgPartiallySigned;
443 } else if (myState != KMMsgPartiallySigned) {
444 myState = KMMsgNotSigned;
445 }
446 break;
447 case KMMsgPartiallySigned:
448 myState = KMMsgPartiallySigned;
449 break;
450 case KMMsgFullySigned:
451 if (myState != KMMsgFullySigned) {
452 myState = KMMsgPartiallySigned;
453 }
454 break;
455 case KMMsgSignatureProblematic:
456 break;
457 }
458 }
459
460 qCDebug(MIMETREEPARSER_LOG) << "\n\n KMMsgSignatureState:" << myState;
461
462 return myState;
463}
464
465void NodeHelper::magicSetType(KMime::Content *node, bool aAutoDecode)
466{
467 const QByteArray body = (aAutoDecode) ? node->decodedContent() : node->body();
468 QMimeDatabase db;
469 QMimeType mime = db.mimeTypeForData(body);
470
471 QString mimetype = mime.name();
472 node->contentType()->setMimeType(mimetype.toLatin1());
473}
474
475// static
476QString NodeHelper::replacePrefixes(const QString &str,
477 const QStringList &prefixRegExps,
478 bool replace,
479 const QString &newPrefix)
480{
481 bool recognized = false;
482 // construct a big regexp that
483 // 1. is anchored to the beginning of str (sans whitespace)
484 // 2. matches at least one of the part regexps in prefixRegExps
485 QString bigRegExp = QStringLiteral("^(?:\\s+|(?:%1))+\\s*")
486 .arg(prefixRegExps.join(QStringLiteral(")|(?:")));
487 QRegExp rx(bigRegExp, Qt::CaseInsensitive);
488 if (!rx.isValid()) {
489 qCWarning(MIMETREEPARSER_LOG) << "bigRegExp = \""
490 << bigRegExp << "\"\n"
491 << "prefix regexp is invalid!";
492 // try good ole Re/Fwd:
493 recognized = str.startsWith(newPrefix);
494 } else { // valid rx
495 QString tmp = str;
496 if (rx.indexIn(tmp) == 0) {
497 recognized = true;
498 if (replace) {
499 return tmp.replace(0, rx.matchedLength(), newPrefix + QLatin1Char(' '));
500 }
501 }
502 }
503 if (!recognized) {
504 return newPrefix + QLatin1Char(' ') + str;
505 } else {
506 return str;
507 }
508}
509
510QString NodeHelper::cleanSubject(KMime::Message *message)
511{
512 return cleanSubject(message, replySubjPrefixes + forwardSubjPrefixes,
513 true, QString()).trimmed();
514}
515
516QString NodeHelper::cleanSubject(KMime::Message *message,
517 const QStringList &prefixRegExps,
518 bool replace,
519 const QString &newPrefix)
520{
521 QString cleanStr;
522 if (message) {
523 cleanStr =
524 NodeHelper::replacePrefixes(
525 message->subject()->asUnicodeString(), prefixRegExps, replace, newPrefix);
526 }
527 return cleanStr;
528}
529
530void NodeHelper::setOverrideCodec(KMime::Content *node, const QTextCodec *codec)
531{
532 if (!node) {
533 return;
534 }
535
536 mOverrideCodecs[node] = codec;
537}
538
539const QTextCodec *NodeHelper::codec(KMime::Content *node)
540{
541 if (! node) {
542 return mLocalCodec;
543 }
544
545 const QTextCodec *c = mOverrideCodecs.value(node, nullptr);
546 if (!c) {
547 // no override-codec set for this message, try the CT charset parameter:
548 QByteArray charset = node->contentType()->charset();
549
550 // utf-8 is a superset of us-ascii, so we don't loose anything, if we it insead
551 // utf-8 is nowadays that widely, that it is a good guess to use it to fix issus with broken clients.
552 if (charset.toLower() == "us-ascii") {
553 charset = "utf-8";
554 }
555 c = codecForName(charset);
556 }
557 if (!c) {
558 // no charset means us-ascii (RFC 2045), so using local encoding should
559 // be okay
560 c = mLocalCodec;
561 }
562 return c;
563}
564
565const QTextCodec *NodeHelper::codecForName(const QByteArray &_str)
566{
567 if (_str.isEmpty()) {
568 return nullptr;
569 }
570 QByteArray codec = _str.toLower();
571 return KCharsets::charsets()->codecForName(QLatin1String(codec));
572}
573
574QString NodeHelper::fileName(const KMime::Content *node)
575{
576 QString name = const_cast<KMime::Content *>(node)->contentDisposition()->filename();
577 if (name.isEmpty()) {
578 name = const_cast<KMime::Content *>(node)->contentType()->name();
579 }
580
581 name = name.trimmed();
582 return name;
583}
584
585//FIXME(Andras) review it (by Marc?) to see if I got it right. This is supposed to be the partNode::internalBodyPartMemento replacement
586Interface::BodyPartMemento *NodeHelper::bodyPartMemento(KMime::Content *node,
587 const QByteArray &which) const
588{
589 const QMap< QString, QMap<QByteArray, Interface::BodyPartMemento *> >::const_iterator nit
590 = mBodyPartMementoMap.find(persistentIndex(node));
591 if (nit == mBodyPartMementoMap.end()) {
592 return nullptr;
593 }
594 const QMap<QByteArray, Interface::BodyPartMemento *>::const_iterator it =
595 nit->find(which.toLower());
596 return it != nit->end() ? it.value() : nullptr;
597}
598
599//FIXME(Andras) review it (by Marc?) to see if I got it right. This is supposed to be the partNode::internalSetBodyPartMemento replacement
600void NodeHelper::setBodyPartMemento(KMime::Content *node, const QByteArray &which,
601 Interface::BodyPartMemento *memento)
602{
603 QMap<QByteArray, Interface::BodyPartMemento *> &mementos
604 = mBodyPartMementoMap[persistentIndex(node)];
605
606 const QByteArray whichLower = which.toLower();
607 const QMap<QByteArray, Interface::BodyPartMemento *>::iterator it =
608 mementos.lowerBound(whichLower);
609
610 if (it != mementos.end() && it.key() == whichLower) {
611 delete it.value();
612 if (memento) {
613 it.value() = memento;
614 } else {
615 mementos.erase(it);
616 }
617 } else {
618 mementos.insert(whichLower, memento);
619 }
620}
621
622bool NodeHelper::isNodeDisplayedEmbedded(KMime::Content *node) const
623{
624 qCDebug(MIMETREEPARSER_LOG) << "IS NODE: " << mDisplayEmbeddedNodes.contains(node);
625 return mDisplayEmbeddedNodes.contains(node);
626}
627
628void NodeHelper::setNodeDisplayedEmbedded(KMime::Content *node, bool displayedEmbedded)
629{
630 qCDebug(MIMETREEPARSER_LOG) << "SET NODE: " << node << displayedEmbedded;
631 if (displayedEmbedded) {
632 mDisplayEmbeddedNodes.insert(node);
633 } else {
634 mDisplayEmbeddedNodes.remove(node);
635 }
636}
637
638bool NodeHelper::isNodeDisplayedHidden(KMime::Content *node) const
639{
640 return mDisplayHiddenNodes.contains(node);
641}
642
643void NodeHelper::setNodeDisplayedHidden(KMime::Content *node, bool displayedHidden)
644{
645 if (displayedHidden) {
646 mDisplayHiddenNodes.insert(node);
647 } else {
648 mDisplayEmbeddedNodes.remove(node);
649 }
650}
651
652/*!
653 Creates a persistent index string that bridges the gap between the
654 permanent nodes and the temporary ones.
655
656 Used internally for robust indexing.
657*/
658QString NodeHelper::persistentIndex(const KMime::Content *node) const
659{
660 if (!node) {
661 return QString();
662 }
663
664 QString indexStr = node->index().toString();
665 if (indexStr.isEmpty()) {
666 QMapIterator<KMime::Message::Content *, QList<KMime::Content *> > it(mExtraContents);
667 while (it.hasNext()) {
668 it.next();
669 const auto &extraNodes = it.value();
670 for (int i = 0; i < extraNodes.size(); i++) {
671 if (extraNodes[i] == node) {
672 indexStr = QString::fromLatin1("e%1").arg(i);
673 const QString parentIndex = persistentIndex(it.key());
674 if (!parentIndex.isEmpty()) {
675 indexStr = QString::fromLatin1("%1:%2").arg(parentIndex, indexStr);
676 }
677 return indexStr;
678 }
679 }
680 }
681 } else {
682 const KMime::Content *const topLevel = node->topLevel();
683 //if the node is an extra node, prepend the index of the extra node to the url
684 QMapIterator<KMime::Message::Content *, QList<KMime::Content *> > it(mExtraContents);
685 while (it.hasNext()) {
686 it.next();
687 const QList<KMime::Content *> &extraNodes = extraContents(it.key());
688 for (int i = 0; i < extraNodes.size(); ++i) {
689 KMime::Content *const extraNode = extraNodes[i];
690 if (topLevel == extraNode) {
691 indexStr.prepend(QStringLiteral("e%1:").arg(i));
692 const QString parentIndex = persistentIndex(it.key());
693 if (!parentIndex.isEmpty()) {
694 indexStr = QStringLiteral("%1:%2").arg(parentIndex, indexStr);
695 }
696 return indexStr;
697 }
698 }
699 }
700 }
701
702 return indexStr;
703}
704
705KMime::Content *NodeHelper::contentFromIndex(KMime::Content *node, const QString &persistentIndex) const
706{
707 KMime::Content *c = node->topLevel();
708 if (c) {
709 const QStringList pathParts = persistentIndex.split(QLatin1Char(':'), QString::SkipEmptyParts);
710 const int pathPartsSize(pathParts.size());
711 for (int i = 0; i < pathPartsSize; ++i) {
712 const QString &path = pathParts[i];
713 if (path.startsWith(QLatin1Char('e'))) {
714 const QList<KMime::Content *> &extraParts = mExtraContents.value(c);
715 const int idx = path.midRef(1, -1).toInt();
716 c = (idx < extraParts.size()) ? extraParts[idx] : nullptr;
717 } else {
718 c = c->content(KMime::ContentIndex(path));
719 }
720 if (!c) {
721 break;
722 }
723 }
724 }
725 return c;
726}
727
728QString NodeHelper::asHREF(const KMime::Content *node, const QString &place) const
729{
730 return QStringLiteral("attachment:%1?place=%2").arg(persistentIndex(node), place);
731}
732
733KMime::Content *NodeHelper::fromHREF(const KMime::Message::Ptr &mMessage, const QUrl &url) const
734{
735 if (url.isEmpty()) {
736 return mMessage.data();
737 }
738
739 if (!url.isLocalFile()) {
740 return contentFromIndex(mMessage.data(), url.adjusted(QUrl::StripTrailingSlash).path());
741 } else {
742 const QString path = url.toLocalFile();
743 // extract from /<path>/qttestn28554.index.2.3:0:2/unnamed -> "2.3:0:2"
744 // start of the index is something that is not a number followed by a dot: \D.
745 // index is only made of numbers,"." and ":": ([0-9.:]+)
746 // index is the last part of the folder name: /
747 const QRegExp rIndex(QStringLiteral("\\D\\.([e0-9.:]+)/"));
748
749 //search the occurence at most at the end
750 if (rIndex.lastIndexIn(path) != -1) {
751 return contentFromIndex(mMessage.data(), rIndex.cap(1));
752 }
753 return mMessage.data();
754 }
755}
756
757QString NodeHelper::fixEncoding(const QString &encoding)
758{
759 QString returnEncoding = encoding;
760 // According to http://www.iana.org/assignments/character-sets, uppercase is
761 // preferred in MIME headers
762 const QString returnEncodingToUpper = returnEncoding.toUpper();
763 if (returnEncodingToUpper.contains(QStringLiteral("ISO "))) {
764 returnEncoding = returnEncodingToUpper;
765 returnEncoding.replace(QLatin1String("ISO "), QStringLiteral("ISO-"));
766 }
767 return returnEncoding;
768}
769
770//-----------------------------------------------------------------------------
771QString NodeHelper::encodingForName(const QString &descriptiveName)
772{
773 QString encoding = KCharsets::charsets()->encodingForName(descriptiveName);
774 return NodeHelper::fixEncoding(encoding);
775}
776
777QStringList NodeHelper::supportedEncodings(bool usAscii)
778{
779 QStringList encodingNames = KCharsets::charsets()->availableEncodingNames();
780 QStringList encodings;
781 QMap<QString, bool> mimeNames;
782 QStringList::ConstIterator constEnd(encodingNames.constEnd());
783 for (QStringList::ConstIterator it = encodingNames.constBegin();
784 it != constEnd; ++it) {
785 QTextCodec *codec = KCharsets::charsets()->codecForName(*it);
786 QString mimeName = (codec) ? QString::fromLatin1(codec->name()).toLower() : (*it);
787 if (!mimeNames.contains(mimeName)) {
788 encodings.append(KCharsets::charsets()->descriptionForEncoding(*it));
789 mimeNames.insert(mimeName, true);
790 }
791 }
792 encodings.sort();
793 if (usAscii) {
794 encodings.prepend(KCharsets::charsets()->descriptionForEncoding(QStringLiteral("us-ascii")));
795 }
796 return encodings;
797}
798
799QString NodeHelper::fromAsString(KMime::Content *node) const
800{
801 if (auto topLevel = dynamic_cast<KMime::Message *>(node->topLevel())) {
802 return topLevel->from()->asUnicodeString();
803 } else {
804 auto realNode = std::find_if(mExtraContents.cbegin(), mExtraContents.cend(),
805 [node](const QList<KMime::Content *> &nodes) {
806 return nodes.contains(node);
807 });
808 if (realNode != mExtraContents.cend()) {
809 return fromAsString(realNode.key());
810 }
811 }
812
813 return QString();
814}
815
816void NodeHelper::attachExtraContent(KMime::Content *topLevelNode, KMime::Content *content)
817{
818 qCDebug(MIMETREEPARSER_LOG) << "mExtraContents added for" << topLevelNode << " extra content: " << content;
819 mExtraContents[topLevelNode].append(content);
820}
821
822QList< KMime::Content * > NodeHelper::extraContents(KMime::Content *topLevelnode) const
823{
824 return mExtraContents.value(topLevelnode);
825}
826
827void NodeHelper::mergeExtraNodes(KMime::Content *node)
828{
829 if (!node) {
830 return;
831 }
832
833 const QList<KMime::Content * > extraNodes = extraContents(node);
834 for (KMime::Content *extra : extraNodes) {
835 if (node->bodyIsMessage()) {
836 qCWarning(MIMETREEPARSER_LOG) << "Asked to attach extra content to a kmime::message, this does not make sense. Attaching to:" << node <<
837 node->encodedContent() << "\n====== with =======\n" << extra << extra->encodedContent();
838 continue;
839 }
840 KMime::Content *c = new KMime::Content(node);
841 c->setContent(extra->encodedContent());
842 c->parse();
843 node->addContent(c);
844 }
845
846 Q_FOREACH (KMime::Content *child, node->contents()) {
847 mergeExtraNodes(child);
848 }
849}
850
851void NodeHelper::cleanFromExtraNodes(KMime::Content *node)
852{
853 if (!node) {
854 return;
855 }
856 const QList<KMime::Content * > extraNodes = extraContents(node);
857 for (KMime::Content *extra : extraNodes) {
858 QByteArray s = extra->encodedContent();
859 const auto children = node->contents();
860 for (KMime::Content *c : children) {
861 if (c->encodedContent() == s) {
862 node->removeContent(c);
863 }
864 }
865 }
866 Q_FOREACH (KMime::Content *child, node->contents()) {
867 cleanFromExtraNodes(child);
868 }
869}
870
871KMime::Message *NodeHelper::messageWithExtraContent(KMime::Content *topLevelNode)
872{
873 /*The merge is done in several steps:
874 1) merge the extra nodes into topLevelNode
875 2) copy the modified (merged) node tree into a new node tree
876 3) restore the original node tree in topLevelNode by removing the extra nodes from it
877
878 The reason is that extra nodes are assigned by pointer value to the nodes in the original tree.
879 */
880 if (!topLevelNode) {
881 return nullptr;
882 }
883
884 mergeExtraNodes(topLevelNode);
885
886 KMime::Message *m = new KMime::Message;
887 m->setContent(topLevelNode->encodedContent());
888 m->parse();
889
890 cleanFromExtraNodes(topLevelNode);
891// qCDebug(MIMETREEPARSER_LOG) << "MESSAGE WITH EXTRA: " << m->encodedContent();
892// qCDebug(MIMETREEPARSER_LOG) << "MESSAGE WITHOUT EXTRA: " << topLevelNode->encodedContent();
893
894 return m;
895}
896
897KMime::Content *NodeHelper::decryptedNodeForContent(KMime::Content *content) const
898{
899 const QList<KMime::Content *> xc = extraContents(content);
900 if (!xc.empty()) {
901 if (xc.size() == 1) {
902 return xc.front();
903 } else {
904 qCWarning(MIMETREEPARSER_LOG) << "WTF, encrypted node has multiple extra contents?";
905 }
906 }
907 return nullptr;
908}
909
910bool NodeHelper::unencryptedMessage_helper(KMime::Content *node, QByteArray &resultingData, bool addHeaders,
911 int recursionLevel)
912{
913 bool returnValue = false;
914 if (node) {
915 KMime::Content *curNode = node;
916 KMime::Content *decryptedNode = nullptr;
917 const QByteArray type = node->contentType(false) ? QByteArray(node->contentType()->mediaType()).toLower() : "text";
918 const QByteArray subType = node->contentType(false) ? node->contentType()->subType().toLower() : "plain";
919 const bool isMultipart = node->contentType(false) && node->contentType()->isMultipart();
920 bool isSignature = false;
921
922 qCDebug(MIMETREEPARSER_LOG) << "(" << recursionLevel << ") Looking at" << type << "/" << subType;
923
924 if (isMultipart) {
925 if (subType == "signed") {
926 isSignature = true;
927 } else if (subType == "encrypted") {
928 decryptedNode = decryptedNodeForContent(curNode);
929 }
930 } else if (type == "application") {
931 if (subType == "octet-stream") {
932 decryptedNode = decryptedNodeForContent(curNode);
933 } else if (subType == "pkcs7-signature") {
934 isSignature = true;
935 } else if (subType == "pkcs7-mime") {
936 // note: subtype pkcs7-mime can also be signed
937 // and we do NOT want to remove the signature!
938 if (encryptionState(curNode) != KMMsgNotEncrypted) {
939 decryptedNode = decryptedNodeForContent(curNode);
940 }
941 }
942 }
943
944 if (decryptedNode) {
945 qCDebug(MIMETREEPARSER_LOG) << "Current node has an associated decrypted node, adding a modified header "
946 "and then processing the children.";
947
948 Q_ASSERT(addHeaders);
949 KMime::Content headers;
950 headers.setHead(curNode->head());
951 headers.parse();
952 if (decryptedNode->contentType(false)) {
953 headers.contentType()->from7BitString(decryptedNode->contentType()->as7BitString(false));
954 } else {
955 headers.removeHeader<KMime::Headers::ContentType>();
956 }
957 if (decryptedNode->contentTransferEncoding(false)) {
958 headers.contentTransferEncoding()->from7BitString(decryptedNode->contentTransferEncoding()->as7BitString(false));
959 } else {
960 headers.removeHeader<KMime::Headers::ContentTransferEncoding>();
961 }
962 if (decryptedNode->contentDisposition(false)) {
963 headers.contentDisposition()->from7BitString(decryptedNode->contentDisposition()->as7BitString(false));
964 } else {
965 headers.removeHeader<KMime::Headers::ContentDisposition>();
966 }
967 if (decryptedNode->contentDescription(false)) {
968 headers.contentDescription()->from7BitString(decryptedNode->contentDescription()->as7BitString(false));
969 } else {
970 headers.removeHeader<KMime::Headers::ContentDescription>();
971 }
972 headers.assemble();
973
974 resultingData += headers.head() + '\n';
975 unencryptedMessage_helper(decryptedNode, resultingData, false, recursionLevel + 1);
976
977 returnValue = true;
978 }
979
980 else if (isSignature) {
981 qCDebug(MIMETREEPARSER_LOG) << "Current node is a signature, adding it as-is.";
982 // We can't change the nodes under the signature, as that would invalidate it. Add the signature
983 // and its child as-is
984 if (addHeaders) {
985 resultingData += curNode->head() + '\n';
986 }
987 resultingData += curNode->encodedBody();
988 returnValue = false;
989 }
990
991 else if (isMultipart) {
992 qCDebug(MIMETREEPARSER_LOG) << "Current node is a multipart node, adding its header and then processing all children.";
993 // Normal multipart node, add the header and all of its children
994 bool somethingChanged = false;
995 if (addHeaders) {
996 resultingData += curNode->head() + '\n';
997 }
998 const QByteArray boundary = curNode->contentType()->boundary();
999 foreach (KMime::Content *child, curNode->contents()) {
1000 resultingData += "\n--" + boundary + '\n';
1001 const bool changed = unencryptedMessage_helper(child, resultingData, true, recursionLevel + 1);
1002 if (changed) {
1003 somethingChanged = true;
1004 }
1005 }
1006 resultingData += "\n--" + boundary + "--\n\n";
1007 returnValue = somethingChanged;
1008 }
1009
1010 else if (curNode->bodyIsMessage()) {
1011 qCDebug(MIMETREEPARSER_LOG) << "Current node is a message, adding the header and then processing the child.";
1012 if (addHeaders) {
1013 resultingData += curNode->head() + '\n';
1014 }
1015
1016 returnValue = unencryptedMessage_helper(curNode->bodyAsMessage().data(), resultingData, true, recursionLevel + 1);
1017 }
1018
1019 else {
1020 qCDebug(MIMETREEPARSER_LOG) << "Current node is an ordinary leaf node, adding it as-is.";
1021 if (addHeaders) {
1022 resultingData += curNode->head() + '\n';
1023 }
1024 resultingData += curNode->body();
1025 returnValue = false;
1026 }
1027 }
1028
1029 qCDebug(MIMETREEPARSER_LOG) << "(" << recursionLevel << ") done.";
1030 return returnValue;
1031}
1032
1033KMime::Message::Ptr NodeHelper::unencryptedMessage(const KMime::Message::Ptr &originalMessage)
1034{
1035 QByteArray resultingData;
1036 const bool messageChanged = unencryptedMessage_helper(originalMessage.data(), resultingData, true);
1037 if (messageChanged) {
1038#if 0
1039 qCDebug(MIMETREEPARSER_LOG) << "Resulting data is:" << resultingData;
1040 QFile bla("stripped.mbox");
1041 bla.open(QIODevice::WriteOnly);
1042 bla.write(resultingData);
1043 bla.close();
1044#endif
1045 KMime::Message::Ptr newMessage(new KMime::Message);
1046 newMessage->setContent(resultingData);
1047 newMessage->parse();
1048 return newMessage;
1049 } else {
1050 return KMime::Message::Ptr();
1051 }
1052}
1053
1054QVector<KMime::Content *> NodeHelper::attachmentsOfExtraContents() const
1055{
1056 QVector<KMime::Content *> result;
1057 for (auto it = mExtraContents.begin(); it != mExtraContents.end(); ++it) {
1058 foreach (auto content, it.value()) {
1059 if (KMime::isAttachment(content)) {
1060 result.push_back(content);
1061 } else {
1062 result += content->attachments();
1063 }
1064 }
1065 }
1066 return result;
1067}
1068
1069}
diff --git a/framework/src/domain/mimetreeparser/otp/nodehelper.h b/framework/src/domain/mimetreeparser/otp/nodehelper.h
new file mode 100644
index 00000000..70253f21
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/nodehelper.h
@@ -0,0 +1,290 @@
1/*
2 Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
3 Copyright (c) 2009 Andras Mantia <andras@kdab.net>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18*/
19
20#ifndef __MIMETREEPARSER_NODEHELPER_H__
21#define __MIMETREEPARSER_NODEHELPER_H__
22
23#include "partmetadata.h"
24#include "enums.h"
25
26#include <KMime/Message>
27
28#include <QList>
29#include <QMap>
30#include <QSet>
31
32class QUrl;
33class QTextCodec;
34
35namespace MimeTreeParser
36{
37class AttachmentTemporaryFilesDirs;
38namespace Interface
39{
40class BodyPartMemento;
41}
42}
43
44namespace MimeTreeParser
45{
46
47/**
48 * @author Andras Mantia <andras@kdab.net>
49 */
50class NodeHelper: public QObject
51{
52 Q_OBJECT
53public:
54 NodeHelper();
55
56 ~NodeHelper();
57
58 void setNodeProcessed(KMime::Content *node, bool recurse);
59 void setNodeUnprocessed(KMime::Content *node, bool recurse);
60 bool nodeProcessed(KMime::Content *node) const;
61 void clear();
62 void forceCleanTempFiles();
63
64 void setEncryptionState(const KMime::Content *node, const KMMsgEncryptionState state);
65 KMMsgEncryptionState encryptionState(const KMime::Content *node) const;
66
67 void setSignatureState(const KMime::Content *node, const KMMsgSignatureState state);
68 KMMsgSignatureState signatureState(const KMime::Content *node) const;
69
70 KMMsgSignatureState overallSignatureState(KMime::Content *node) const;
71 KMMsgEncryptionState overallEncryptionState(KMime::Content *node) const;
72
73 void setPartMetaData(KMime::Content *node, const PartMetaData &metaData);
74 PartMetaData partMetaData(KMime::Content *node);
75
76 /**
77 * Set the 'Content-Type' by mime-magic from the contents of the body.
78 * If autoDecode is true the decoded body will be used for mime type
79 * determination (this does not change the body itself).
80 */
81 void magicSetType(KMime::Content *node, bool autoDecode = true);
82
83 /**
84 * Return this mails subject, with all "forward" and "reply"
85 * prefixes removed
86 */
87 static QString cleanSubject(KMime::Message *message);
88
89 /** Attach an extra node to an existing node */
90 void attachExtraContent(KMime::Content *topLevelNode, KMime::Content *content);
91
92 /** Get the extra nodes attached to the @param topLevelNode and all sub-nodes of @param topLevelNode */
93 QList<KMime::Content *> extraContents(KMime::Content *topLevelNode) const;
94
95 /** Return a modified message (node tree) starting from @param topLevelNode that has the original nodes and the extra nodes.
96 The caller has the responsibility to delete the new message.
97 */
98 KMime::Message *messageWithExtraContent(KMime::Content *topLevelNode);
99
100 /** Get a QTextCodec suitable for this message part */
101 const QTextCodec *codec(KMime::Content *node);
102
103 /** Set the charset the user selected for the message to display */
104 void setOverrideCodec(KMime::Content *node, const QTextCodec *codec);
105
106 Interface::BodyPartMemento *bodyPartMemento(KMime::Content *node, const QByteArray &which) const;
107
108 void setBodyPartMemento(KMime::Content *node, const QByteArray &which,
109 Interface::BodyPartMemento *memento);
110
111 // A flag to remember if the node was embedded. This is useful for attachment nodes, the reader
112 // needs to know if they were displayed inline or not.
113 bool isNodeDisplayedEmbedded(KMime::Content *node) const;
114 void setNodeDisplayedEmbedded(KMime::Content *node, bool displayedEmbedded);
115
116 // Same as above, but this time determines if the node was hidden or not
117 bool isNodeDisplayedHidden(KMime::Content *node) const;
118 void setNodeDisplayedHidden(KMime::Content *node, bool displayedHidden);
119
120 /**
121 * Writes the given message part to a temporary file and returns the
122 * name of this file or QString() if writing failed.
123 */
124 QString writeNodeToTempFile(KMime::Content *node);
125
126 /**
127 * Returns the temporary file path and name where this node was saved, or an empty url
128 * if it wasn't saved yet with writeNodeToTempFile()
129 */
130 QUrl tempFileUrlFromNode(const KMime::Content *node);
131
132 /**
133 * Creates a temporary dir for saving attachments, etc.
134 * Will be automatically deleted when another message is viewed.
135 * @param param Optional part of the directory name.
136 */
137 QString createTempDir(const QString &param = QString());
138
139 /**
140 * Cleanup the attachment temp files
141 */
142 void removeTempFiles();
143
144 /**
145 * Add a file to the list of managed temporary files
146 */
147 void addTempFile(const QString &file);
148
149 // Get a href in the form attachment:<nodeId>?place=<place>, used by ObjectTreeParser and
150 // UrlHandlerManager.
151 QString asHREF(const KMime::Content *node, const QString &place) const;
152 KMime::Content *fromHREF(const KMime::Message::Ptr &mMessage, const QUrl &href) const;
153
154 /**
155 * @return true if this node is a child or an encapsulated message
156 */
157 static bool isInEncapsulatedMessage(KMime::Content *node);
158
159 /**
160 * Returns the charset for the given node. If no charset is specified
161 * for the node, the defaultCharset() is returned.
162 */
163 static QByteArray charset(KMime::Content *node);
164
165 /**
166 * Check for prefixes @p prefixRegExps in @p str. If none
167 * is found, @p newPrefix + ' ' is prepended to @p str and the
168 * resulting string is returned. If @p replace is true, any
169 * sequence of whitespace-delimited prefixes at the beginning of
170 * @p str is replaced by @p newPrefix.
171 */
172 static QString replacePrefixes(const QString &str,
173 const QStringList &prefixRegExps,
174 bool replace,
175 const QString &newPrefix);
176
177 /**
178 * Return a QTextCodec for the specified charset.
179 * This function is a bit more tolerant, than QTextCodec::codecForName
180 */
181 static const QTextCodec *codecForName(const QByteArray &_str);
182
183 /**
184 * Returns a usable filename for a node, that can be the filename from the
185 * content disposition header, or if that one is empty, the name from the
186 * content type header.
187 */
188 static QString fileName(const KMime::Content *node);
189
190 /**
191 * Fixes an encoding received by a KDE function and returns the proper,
192 * MIME-compilant encoding name instead.
193 * @see encodingForName
194 */
195 static QString fixEncoding(const QString &encoding); //TODO(Andras) move to a utility class?
196
197 /**
198 * Drop-in replacement for KCharsets::encodingForName(). The problem with
199 * the KCharsets function is that it returns "human-readable" encoding names
200 * like "ISO 8859-15" instead of valid encoding names like "ISO-8859-15".
201 * This function fixes this by replacing whitespace with a hyphen.
202 */
203 static QString encodingForName(const QString &descriptiveName); //TODO(Andras) move to a utility class?
204
205 /**
206 * Return a list of the supported encodings
207 * @param usAscii if true, US-Ascii encoding will be prepended to the list.
208 */
209 static QStringList supportedEncodings(bool usAscii); //TODO(Andras) move to a utility class?
210
211 QString fromAsString(KMime::Content *node) const;
212
213 KMime::Content *decryptedNodeForContent(KMime::Content *content) const;
214
215 /**
216 * This function returns the unencrypted message that is based on @p originalMessage.
217 * All encrypted MIME parts are removed and replaced by their decrypted plain-text versions.
218 * Encrypted parts that are within signed parts are not replaced, since that would invalidate
219 * the signature.
220 *
221 * This only works if the message was run through ObjectTreeParser::parseObjectTree() with the
222 * currrent NodeHelper before, because parseObjectTree() actually decrypts the message and stores
223 * the decrypted nodes by calling attachExtraContent().
224 *
225 * @return the unencrypted message or an invalid pointer if the original message didn't contain
226 * a part that needed to be modified.
227 */
228 KMime::Message::Ptr unencryptedMessage(const KMime::Message::Ptr &originalMessage);
229
230 /**
231 * Returns a list of attachments of attached extra content nodes.
232 * This is mainly useful is order to get attachments of encrypted messages.
233 * Note that this does not include attachments from the primary node tree.
234 * @see KMime::Content::attachments().
235 */
236 QVector<KMime::Content *> attachmentsOfExtraContents() const;
237
238Q_SIGNALS:
239 void update(MimeTreeParser::UpdateMode);
240
241private:
242 Q_DISABLE_COPY(NodeHelper)
243 bool unencryptedMessage_helper(KMime::Content *node, QByteArray &resultingData, bool addHeaders,
244 int recursionLevel = 1);
245
246 /** Check for prefixes @p prefixRegExps in #subject(). If none
247 is found, @p newPrefix + ' ' is prepended to the subject and the
248 resulting string is returned. If @p replace is true, any
249 sequence of whitespace-delimited prefixes at the beginning of
250 #subject() is replaced by @p newPrefix
251 **/
252 static QString cleanSubject(KMime::Message *message, const QStringList &prefixRegExps,
253 bool replace, const QString &newPrefix);
254
255 void mergeExtraNodes(KMime::Content *node);
256 void cleanFromExtraNodes(KMime::Content *node);
257
258 /** Creates a persistent index string that bridges the gap between the
259 permanent nodes and the temporary ones.
260
261 Used internally for robust indexing.
262 **/
263 QString persistentIndex(const KMime::Content *node) const;
264
265 /** Translates the persistentIndex into a node back
266
267 node: any node of the actually message to what the persistentIndex is interpreded
268 **/
269 KMime::Content *contentFromIndex(KMime::Content *node, const QString &persistentIndex) const;
270
271private:
272 QList<KMime::Content *> mProcessedNodes;
273 QList<KMime::Content *> mNodesUnderProcess;
274 QMap<const KMime::Content *, KMMsgEncryptionState> mEncryptionState;
275 QMap<const KMime::Content *, KMMsgSignatureState> mSignatureState;
276 QSet<KMime::Content *> mDisplayEmbeddedNodes;
277 QSet<KMime::Content *> mDisplayHiddenNodes;
278 QTextCodec *mLocalCodec;
279 QMap<KMime::Content *, const QTextCodec *> mOverrideCodecs;
280 QMap<QString, QMap<QByteArray, Interface::BodyPartMemento *> > mBodyPartMementoMap;
281 QMap<KMime::Content *, PartMetaData> mPartMetaDatas;
282 QMap<KMime::Message::Content *, QList<KMime::Content *> > mExtraContents;
283 AttachmentTemporaryFilesDirs *mAttachmentFilesDir;
284
285 friend class NodeHelperTest;
286};
287
288}
289
290#endif
diff --git a/framework/src/domain/mimetreeparser/otp/objecttreeparser.cpp b/framework/src/domain/mimetreeparser/otp/objecttreeparser.cpp
new file mode 100644
index 00000000..b0d514b6
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/objecttreeparser.cpp
@@ -0,0 +1,495 @@
1/*
2 objecttreeparser.cpp
3
4 This file is part of KMail, the KDE mail client.
5 Copyright (c) 2003 Marc Mutz <mutz@kde.org>
6 Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
7 Copyright (c) 2009 Andras Mantia <andras@kdab.net>
8 Copyright (c) 2015 Sandro Knauß <sknauss@kde.org>
9
10 KMail is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License, version 2, as
12 published by the Free Software Foundation.
13
14 KMail is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
23 In addition, as a special exception, the copyright holders give
24 permission to link the code of this program with any edition of
25 the Qt library by Trolltech AS, Norway (or with modified versions
26 of Qt that use the same license as Qt), and distribute linked
27 combinations including the two. You must obey the GNU General
28 Public License in all respects for all of the code used other than
29 Qt. If you modify this file, you may extend this exception to
30 your version of the file, but you are not obligated to do so. If
31 you do not wish to do so, delete this exception statement from
32 your version.
33*/
34
35// MessageViewer includes
36
37#include "objecttreeparser.h"
38
39#include "attachmentstrategy.h"
40#include "bodypartformatterbasefactory.h"
41#include "nodehelper.h"
42#include "messagepart.h"
43#include "partnodebodypart.h"
44
45#include "mimetreeparser_debug.h"
46
47#include "utils.h"
48#include "bodypartformatter.h"
49#include "htmlwriter.h"
50#include "messagepartrenderer.h"
51#include "util.h"
52
53#include <KMime/Headers>
54#include <KMime/Message>
55
56// KDE includes
57
58// Qt includes
59#include <QByteArray>
60#include <QTextCodec>
61#include <QUrl>
62
63using namespace MimeTreeParser;
64
65ObjectTreeParser::ObjectTreeParser(const ObjectTreeParser *topLevelParser,
66 bool showOnlyOneMimePart,
67 const AttachmentStrategy *strategy)
68 : mSource(topLevelParser->mSource),
69 mNodeHelper(topLevelParser->mNodeHelper),
70 mHtmlWriter(topLevelParser->mHtmlWriter),
71 mTopLevelContent(topLevelParser->mTopLevelContent),
72 mShowOnlyOneMimePart(showOnlyOneMimePart),
73 mHasPendingAsyncJobs(false),
74 mAllowAsync(topLevelParser->mAllowAsync),
75 mAttachmentStrategy(strategy)
76{
77 init();
78}
79
80ObjectTreeParser::ObjectTreeParser(Interface::ObjectTreeSource *source,
81 MimeTreeParser::NodeHelper *nodeHelper,
82 bool showOnlyOneMimePart,
83 const AttachmentStrategy *strategy)
84 : mSource(source),
85 mNodeHelper(nodeHelper),
86 mHtmlWriter(nullptr),
87 mTopLevelContent(nullptr),
88 mShowOnlyOneMimePart(showOnlyOneMimePart),
89 mHasPendingAsyncJobs(false),
90 mAllowAsync(false),
91 mAttachmentStrategy(strategy)
92{
93 init();
94}
95
96void ObjectTreeParser::init()
97{
98 Q_ASSERT(mSource);
99 if (!attachmentStrategy()) {
100 mAttachmentStrategy = mSource->attachmentStrategy();
101 }
102
103 if (!mNodeHelper) {
104 mNodeHelper = new NodeHelper();
105 mDeleteNodeHelper = true;
106 } else {
107 mDeleteNodeHelper = false;
108 }
109}
110
111ObjectTreeParser::ObjectTreeParser(const ObjectTreeParser &other)
112 : mSource(other.mSource),
113 mNodeHelper(other.nodeHelper()), //TODO(Andras) hm, review what happens if mDeleteNodeHelper was true in the source
114 mHtmlWriter(other.mHtmlWriter),
115 mTopLevelContent(other.mTopLevelContent),
116 mShowOnlyOneMimePart(other.showOnlyOneMimePart()),
117 mHasPendingAsyncJobs(other.hasPendingAsyncJobs()),
118 mAllowAsync(other.allowAsync()),
119 mAttachmentStrategy(other.attachmentStrategy()),
120 mDeleteNodeHelper(false)
121{
122
123}
124
125ObjectTreeParser::~ObjectTreeParser()
126{
127 if (mDeleteNodeHelper) {
128 delete mNodeHelper;
129 mNodeHelper = nullptr;
130 }
131}
132
133void ObjectTreeParser::setAllowAsync(bool allow)
134{
135 Q_ASSERT(!mHasPendingAsyncJobs);
136 mAllowAsync = allow;
137}
138
139bool ObjectTreeParser::allowAsync() const
140{
141 return mAllowAsync;
142}
143
144bool ObjectTreeParser::hasPendingAsyncJobs() const
145{
146 return mHasPendingAsyncJobs;
147}
148
149QString ObjectTreeParser::plainTextContent() const
150{
151 return mPlainTextContent;
152}
153
154QString ObjectTreeParser::htmlContent() const
155{
156 return mHtmlContent;
157}
158
159void ObjectTreeParser::copyContentFrom(const ObjectTreeParser *other)
160{
161 mPlainTextContent += other->plainTextContent();
162 mHtmlContent += other->htmlContent();
163 if (!other->plainTextContentCharset().isEmpty()) {
164 mPlainTextContentCharset = other->plainTextContentCharset();
165 }
166 if (!other->htmlContentCharset().isEmpty()) {
167 mHtmlContentCharset = other->htmlContentCharset();
168 }
169}
170
171//-----------------------------------------------------------------------------
172
173void ObjectTreeParser::parseObjectTree(KMime::Content *node)
174{
175 mTopLevelContent = node;
176 mParsedPart = parseObjectTreeInternal(node, showOnlyOneMimePart());
177
178 if (mParsedPart) {
179 mParsedPart->fix();
180 mParsedPart->copyContentFrom();
181 if (auto mp = toplevelTextNode(mParsedPart)) {
182 if (auto _mp = mp.dynamicCast<TextMessagePart>()) {
183 extractNodeInfos(_mp->mNode, true);
184 } else if (auto _mp = mp.dynamicCast<AlternativeMessagePart>()) {
185 if (_mp->mChildNodes.contains(Util::MultipartPlain)) {
186 extractNodeInfos(_mp->mChildNodes[Util::MultipartPlain], true);
187 }
188 }
189 setPlainTextContent(mp->text());
190 }
191
192 if (htmlWriter()) {
193 const auto renderer = mSource->messagePartTheme(mParsedPart);
194 if (renderer) {
195 mHtmlWriter->queue(renderer->html());
196 }
197 }
198 }
199}
200
201MessagePartPtr ObjectTreeParser::parsedPart() const
202{
203 return mParsedPart;
204}
205
206bool ObjectTreeParser::processType(KMime::Content *node, ProcessResult &processResult, const QByteArray &mediaType, const QByteArray &subType, Interface::MessagePartPtr &mpRet, bool onlyOneMimePart)
207{
208 bool bRendered = false;
209 const auto sub = mSource->bodyPartFormatterFactory()->subtypeRegistry(mediaType.constData());
210 auto range = sub.equal_range(subType.constData());
211 for (auto it = range.first; it != range.second; ++it) {
212 const auto formatter = (*it).second;
213 if (!formatter) {
214 continue;
215 }
216 PartNodeBodyPart part(this, &processResult, mTopLevelContent, node, mNodeHelper);
217 // Set the default display strategy for this body part relying on the
218 // identity of Interface::BodyPart::Display and AttachmentStrategy::Display
219 part.setDefaultDisplay((Interface::BodyPart::Display) attachmentStrategy()->defaultDisplay(node));
220
221 mNodeHelper->setNodeDisplayedEmbedded(node, true);
222
223 const Interface::MessagePart::Ptr result = formatter->process(part);
224 if (!result) {
225 continue;
226 }
227
228 if (const auto mp = result.dynamicCast<MessagePart>()) {
229 mp->setAttachmentFlag(node);
230 mpRet = result;
231 bRendered = true;
232 break;
233 } else if (dynamic_cast<MimeTreeParser::Interface::MessagePart *>(result.data())) {
234 QObject *asyncResultObserver = allowAsync() ? mSource->sourceObject() : nullptr;
235 const auto r = formatter->format(&part, result->htmlWriter(), asyncResultObserver);
236 if (r == Interface::BodyPartFormatter::AsIcon) {
237 processResult.setNeverDisplayInline(true);
238 formatter->adaptProcessResult(processResult);
239 mNodeHelper->setNodeDisplayedEmbedded(node, false);
240 const Interface::MessagePart::Ptr mp = defaultHandling(node, processResult, onlyOneMimePart);
241 if (mp) {
242 if (auto _mp = mp.dynamicCast<MessagePart>()) {
243 _mp->setAttachmentFlag(node);
244 }
245 mpRet = mp;
246 }
247 bRendered = true;
248 break;
249 } else if (r == Interface::BodyPartFormatter::Ok) {
250 processResult.setNeverDisplayInline(true);
251 formatter->adaptProcessResult(processResult);
252 mpRet = result;
253 bRendered = true;
254 break;
255 }
256 continue;
257 } else {
258 continue;
259 }
260 }
261 return bRendered;
262}
263
264MessagePart::Ptr ObjectTreeParser::parseObjectTreeInternal(KMime::Content *node, bool onlyOneMimePart)
265{
266 if (!node) {
267 return MessagePart::Ptr();
268 }
269
270 // reset pending async jobs state (we'll rediscover pending jobs as we go)
271 mHasPendingAsyncJobs = false;
272
273 // reset "processed" flags for...
274 if (onlyOneMimePart) {
275 // ... this node and all descendants
276 mNodeHelper->setNodeUnprocessed(node, false);
277 if (!node->contents().isEmpty()) {
278 mNodeHelper->setNodeUnprocessed(node, true);
279 }
280 } else if (!node->parent()) {
281 // ...this node and all it's siblings and descendants
282 mNodeHelper->setNodeUnprocessed(node, true);
283 }
284
285 const bool isRoot = node->isTopLevel();
286 auto parsedPart = MessagePart::Ptr(new MessagePartList(this));
287 parsedPart->setIsRoot(isRoot);
288 KMime::Content *parent = node->parent();
289 auto contents = parent ? parent->contents() : KMime::Content::List();
290 if (contents.isEmpty()) {
291 contents.append(node);
292 }
293 int i = contents.indexOf(const_cast<KMime::Content *>(node));
294 for (; i < contents.size(); ++i) {
295 node = contents.at(i);
296 if (mNodeHelper->nodeProcessed(node)) {
297 continue;
298 }
299
300 ProcessResult processResult(mNodeHelper);
301
302 QByteArray mediaType("text");
303 QByteArray subType("plain");
304 if (node->contentType(false) && !node->contentType()->mediaType().isEmpty() &&
305 !node->contentType()->subType().isEmpty()) {
306 mediaType = node->contentType()->mediaType();
307 subType = node->contentType()->subType();
308 }
309
310 Interface::MessagePartPtr mp;
311 if (processType(node, processResult, mediaType, subType, mp, onlyOneMimePart)) {
312 if (mp) {
313 parsedPart->appendSubPart(mp);
314 }
315 } else if (processType(node, processResult, mediaType, "*", mp, onlyOneMimePart)) {
316 if (mp) {
317 parsedPart->appendSubPart(mp);
318 }
319 } else {
320 qCWarning(MIMETREEPARSER_LOG) << "THIS SHOULD NO LONGER HAPPEN:" << mediaType << '/' << subType;
321 const auto mp = defaultHandling(node, processResult, onlyOneMimePart);
322 if (mp) {
323 if (auto _mp = mp.dynamicCast<MessagePart>()) {
324 _mp->setAttachmentFlag(node);
325 }
326 parsedPart->appendSubPart(mp);
327 }
328 }
329 mNodeHelper->setNodeProcessed(node, false);
330
331 // adjust signed/encrypted flags if inline PGP was found
332 processResult.adjustCryptoStatesOfNode(node);
333
334 if (onlyOneMimePart) {
335 break;
336 }
337 }
338
339 return parsedPart;
340}
341
342Interface::MessagePart::Ptr ObjectTreeParser::defaultHandling(KMime::Content *node, ProcessResult &result, bool onlyOneMimePart)
343{
344 Interface::MessagePart::Ptr mp;
345 ProcessResult processResult(mNodeHelper);
346
347 if (node->contentType()->mimeType() == QByteArrayLiteral("application/octet-stream") &&
348 (node->contentType()->name().endsWith(QLatin1String("p7m")) ||
349 node->contentType()->name().endsWith(QLatin1String("p7s")) ||
350 node->contentType()->name().endsWith(QLatin1String("p7c"))
351 ) &&
352 processType(node, processResult, "application", "pkcs7-mime", mp, onlyOneMimePart)) {
353 return mp;
354 }
355
356 const auto _mp = AttachmentMessagePart::Ptr(new AttachmentMessagePart(this, node, false, true, mSource->decryptMessage()));
357 result.setInlineSignatureState(_mp->signatureState());
358 result.setInlineEncryptionState(_mp->encryptionState());
359 _mp->setNeverDisplayInline(result.neverDisplayInline());
360 _mp->setIsImage(result.isImage());
361 mp = _mp;
362
363 // always show images in multipart/related when showing in html, not with an additional icon
364 auto preferredMode = mSource->preferredMode();
365 bool isHtmlPreferred = (preferredMode == Util::Html) || (preferredMode == Util::MultipartHtml);
366 if (result.isImage() && node->parent() &&
367 node->parent()->contentType()->subType() == "related" && isHtmlPreferred && !onlyOneMimePart) {
368 QString fileName = mNodeHelper->writeNodeToTempFile(node);
369 QString href = QUrl::fromLocalFile(fileName).url();
370 QByteArray cid = node->contentID()->identifier();
371 if (htmlWriter()) {
372 htmlWriter()->embedPart(cid, href);
373 }
374 nodeHelper()->setNodeDisplayedEmbedded(node, true);
375 mNodeHelper->setNodeDisplayedHidden(node, true);
376 return mp;
377 }
378
379 // Show it inline if showOnlyOneMimePart(), which means the user clicked the image
380 // in the message structure viewer manually, and therefore wants to see the full image
381 if (result.isImage() && onlyOneMimePart && !result.neverDisplayInline()) {
382 mNodeHelper->setNodeDisplayedEmbedded(node, true);
383 }
384
385 return mp;
386}
387
388KMMsgSignatureState ProcessResult::inlineSignatureState() const
389{
390 return mInlineSignatureState;
391}
392
393void ProcessResult::setInlineSignatureState(KMMsgSignatureState state)
394{
395 mInlineSignatureState = state;
396}
397
398KMMsgEncryptionState ProcessResult::inlineEncryptionState() const
399{
400 return mInlineEncryptionState;
401}
402
403void ProcessResult::setInlineEncryptionState(KMMsgEncryptionState state)
404{
405 mInlineEncryptionState = state;
406}
407
408bool ProcessResult::neverDisplayInline() const
409{
410 return mNeverDisplayInline;
411}
412
413void ProcessResult::setNeverDisplayInline(bool display)
414{
415 mNeverDisplayInline = display;
416}
417
418bool ProcessResult::isImage() const
419{
420 return mIsImage;
421}
422
423void ProcessResult::setIsImage(bool image)
424{
425 mIsImage = image;
426}
427
428void ProcessResult::adjustCryptoStatesOfNode(const KMime::Content *node) const
429{
430 if ((inlineSignatureState() != KMMsgNotSigned) ||
431 (inlineEncryptionState() != KMMsgNotEncrypted)) {
432 mNodeHelper->setSignatureState(node, inlineSignatureState());
433 mNodeHelper->setEncryptionState(node, inlineEncryptionState());
434 }
435}
436
437void ObjectTreeParser::extractNodeInfos(KMime::Content *curNode, bool isFirstTextPart)
438{
439 if (isFirstTextPart) {
440 mPlainTextContent += curNode->decodedText();
441 mPlainTextContentCharset += NodeHelper::charset(curNode);
442 }
443}
444
445void ObjectTreeParser::setPlainTextContent(const QString &plainTextContent)
446{
447 mPlainTextContent = plainTextContent;
448}
449
450const QTextCodec *ObjectTreeParser::codecFor(KMime::Content *node) const
451{
452 Q_ASSERT(node);
453 if (mSource->overrideCodec()) {
454 return mSource->overrideCodec();
455 }
456 return mNodeHelper->codec(node);
457}
458
459QByteArray ObjectTreeParser::plainTextContentCharset() const
460{
461 return mPlainTextContentCharset;
462}
463
464QByteArray ObjectTreeParser::htmlContentCharset() const
465{
466 return mHtmlContentCharset;
467}
468
469bool ObjectTreeParser::showOnlyOneMimePart() const
470{
471 return mShowOnlyOneMimePart;
472}
473
474void ObjectTreeParser::setShowOnlyOneMimePart(bool show)
475{
476 mShowOnlyOneMimePart = show;
477}
478
479const AttachmentStrategy *ObjectTreeParser::attachmentStrategy() const
480{
481 return mAttachmentStrategy;
482}
483
484HtmlWriter *ObjectTreeParser::htmlWriter() const
485{
486 if (mHtmlWriter) {
487 return mHtmlWriter;
488 }
489 return mSource->htmlWriter();
490}
491
492MimeTreeParser::NodeHelper *ObjectTreeParser::nodeHelper() const
493{
494 return mNodeHelper;
495}
diff --git a/framework/src/domain/mimetreeparser/otp/objecttreeparser.h b/framework/src/domain/mimetreeparser/otp/objecttreeparser.h
new file mode 100644
index 00000000..3f29a673
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/objecttreeparser.h
@@ -0,0 +1,406 @@
1/*
2 objecttreeparser.h
3
4 This file is part of KMail, the KDE mail client.
5 Copyright (c) 2003 Marc Mutz <mutz@kde.org>
6 Copyright (C) 2002-2003, 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
7 Copyright (c) 2009 Andras Mantia <andras@kdab.net>
8
9 KMail is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License, version 2, as
11 published by the Free Software Foundation.
12
13 KMail is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
22 In addition, as a special exception, the copyright holders give
23 permission to link the code of this program with any edition of
24 the Qt library by Trolltech AS, Norway (or with modified versions
25 of Qt that use the same license as Qt), and distribute linked
26 combinations including the two. You must obey the GNU General
27 Public License in all respects for all of the code used other than
28 Qt. If you modify this file, you may extend this exception to
29 your version of the file, but you are not obligated to do so. If
30 you do not wish to do so, delete this exception statement from
31 your version.
32*/
33
34#ifndef __MIMETREEPARSER_OBJECTTREEPARSER_H__
35#define __MIMETREEPARSER_OBJECTTREEPARSER_H__
36
37#include "nodehelper.h"
38#include "objecttreesource.h"
39
40#include <gpgme++/verificationresult.h>
41
42class QString;
43
44namespace KMime
45{
46class Content;
47}
48
49namespace MimeTreeParser
50{
51
52namespace Interface
53{
54class MessagePart;
55typedef QSharedPointer<MessagePart> MessagePartPtr;
56}
57
58class PartMetaData;
59class ViewerPrivate;
60class HtmlWriter;
61class AttachmentStrategy;
62class NodeHelper;
63class MessagePart;
64class MimeMessagePart;
65
66typedef QSharedPointer<MessagePart> MessagePartPtr;
67typedef QSharedPointer<MimeMessagePart> MimeMessagePartPtr;
68
69class ProcessResult
70{
71public:
72 explicit ProcessResult(NodeHelper *nodeHelper, KMMsgSignatureState inlineSignatureState = KMMsgNotSigned,
73 KMMsgEncryptionState inlineEncryptionState = KMMsgNotEncrypted,
74 bool neverDisplayInline = false,
75 bool isImage = false)
76 : mInlineSignatureState(inlineSignatureState),
77 mInlineEncryptionState(inlineEncryptionState),
78 mNeverDisplayInline(neverDisplayInline),
79 mIsImage(isImage),
80 mNodeHelper(nodeHelper) {}
81
82 KMMsgSignatureState inlineSignatureState() const;
83 void setInlineSignatureState(KMMsgSignatureState state);
84
85 KMMsgEncryptionState inlineEncryptionState() const;
86 void setInlineEncryptionState(KMMsgEncryptionState state);
87
88 bool neverDisplayInline() const;
89 void setNeverDisplayInline(bool display);
90
91 bool isImage() const;
92 void setIsImage(bool image);
93
94 void adjustCryptoStatesOfNode(const KMime::Content *node) const;
95
96private:
97 KMMsgSignatureState mInlineSignatureState;
98 KMMsgEncryptionState mInlineEncryptionState;
99 bool mNeverDisplayInline : 1;
100 bool mIsImage : 1;
101 NodeHelper *mNodeHelper;
102};
103
104/**
105\brief Parses messages and generates HTML display code out of them
106
107\par Introduction
108
109First, have a look at the documentation in Mainpage.dox and at the documentation of ViewerPrivate
110to understand the broader picture.
111
112Just a note on the terminology: 'Node' refers to a MIME part here, which in KMime is a
113KMime::Content.
114
115\par Basics
116
117The ObjectTreeParser basically has two modes: Generating the HTML code for the Viewer, or only
118extracting the plainTextContent() for situations where only the message text is needed, for example
119when inline forwarding a message. The mode depends on the Interface::ObjectTreeSource passed to the
120constructor: If Interface::ObjectTreeSource::htmlWriter() is not 0, then the HTML code generation mode is
121used.
122
123Basically, all the ObjectTreeParser does is going through the tree of MIME parts and operating on
124those nodes. Operating here means creating the HTML code for the node or extracting the textual
125content from it. This process is started with parseObjectTree(), where we loop over the subnodes
126of the current root node. For each of those subnodes, we try to find a BodyPartFormatter that can
127handle the type of the node. This can either be an internal function, such as
128processMultiPartAlternativeSubtype() or processTextHtmlSubtype(), or it can be an external plugin.
129More on external plugins later. When no matching formatter is found, defaultHandling() is called
130for that node.
131
132\par Multipart Nodes
133
134Those nodes that are of type multipart have subnodes. If one of those children needs to be
135processed normally, the processMultipartXXX() functions call stdChildHandling() for the node that
136should be handled normally. stdChildHandling() creates its own ObjectTreeParser, which is a clone
137of the current ObjectTreeParser, and processes the node. stdChildHandling() is not called for all
138children of the multipart node, for example processMultiPartAlternativeSubtype() only calls it on
139one of the children, as the other one doesn't need to be displayed. Similary,
140processMultiPartSignedSubtype() doesn't call stdChildHandling() for the signature node, only for the
141signed node.
142
143\par Processed and Unprocessed Nodes
144
145When a BodyPartFormatter has finished processing a node, it is processed. Nodes are set to being
146not processed at the beginning of parseObjectTree(). The processed state of a node is saved in a
147list in NodeHelper, see NodeHelper::setNodeProcessed(), NodeHelper::nodeProcessed() and the other
148related helper functions.
149
150It is the responsibility of the BodyPartFormatter to correctly call setNodeProcessed() and the
151related functions. This is important so that processing the same node twice can be prevented. The
152check that prevents duplicate processing is in parseObjectTree().
153
154An example where duplicate processing would happen if we didn't check for it is in stdChildHandling(),
155which is for example called from processMultiPartAlternativeSubtype(). Let's say the setting is to
156prefer HTML over plain text. In this case, processMultiPartAlternativeSubtype() would call
157stdChildHandling() on the HTML node, which would create a new ObjectTreeParser and call
158parseObjectTree() on it. parseObjectTree() processes the node and all its siblings, and one of the
159siblings is the plain text node, which shouldn't be processed! Therefore
160processMultiPartAlternativeSubtype() sets the plain text node as been processed already.
161
162\par Plain Text Output
163
164Various nodes have plain text that should be displayed. This plain text is usually processed though
165writeBodyString() first. That method checks if the provided text is an inline PGP text and decrypts
166it if necessary. It also pushes the text through quotedHTML(), which does a number of things like
167coloring quoted lines or detecting links and creating real link tags for them.
168
169\par Modifying the Message
170
171The ObjectTreeParser does not only parse its message, in some circumstances it also modifies it
172before displaying. This is for example the case when displaying a decrypted message: The original
173message only contains a binary blob of crypto data, and processMultiPartEncryptedSubtype() decrypts
174that blob. After decryption, the current node is replaced with the decrypted node, which happens
175in insertAndParseNewChildNode().
176
177\par Crypto Operations
178
179For signature and decryption handling, there are functions which help with generating the HTML code
180for the signature header and footer. These are writeDeferredDecryptionBlock(), writeSigstatFooter()
181and writeSigstatHeader(). As the name writeDeferredDecryptionBlock() suggests, a setting can cause
182the message to not be decrypted unless the user clicks a link. Whether the message should be
183decrypted or not can be controlled by Interface::ObjectTreeSource::decryptMessage(). When the user clicks the
184decryption link, the URLHandler for 'kmail:' URLs sets that variable to true and triggers an update
185of the Viewer, which will cause parseObjectTree() to be called again.
186
187\par Async Crypto Operations
188
189The above case describes decryption the message in place. However, decryption and also verifying of
190the signature can take a long time, so synchronous decryption and verifing would cause the Viewer to
191block. Therefore it is possible to run these operations in async mode, see allowAsync().
192In the first run of the async mode, all the ObjectTreeParser does is starting the decrypt or the
193verify job, and informing the user that the operation is in progress with
194writeDecryptionInProgressBlock() or with writeSigstatHeader(). Then, it creates and associates a
195BodyPartMemento with the current node, for example a VerifyDetachedBodyPartMemento. Each node can
196have multiple mementos associated with it, which are differeniated by name.
197
198NodeHelper::setBodyPartMemento() and NodeHelper::bodyPartMemento() provide means to store and
199retrieve these mementos. A memento is basically a thin wrapper around the crypto job, it stores the
200job pointer, the job input data and the job result. Mementos can be used for any async situation,
201not just for crypto jobs, but I'll describe crypto jobs here.
202
203So in the first run of decrypting or verifying a message, the BodyPartFormatter only starts the
204crypto job, creates the BodyPartMemento and writes the HTML code that tells the user that the
205operation is in progress. parseObjectTree() thus finishes without waiting for anything, and the
206message is displayed.
207
208At some point, the crypto jobs then finish, which will cause slotResult() of the BodyPartMemento
209to be called. slotResult() then saves the result to some member variable and calls
210BodyPartMemento::notify(), which in the end will trigger an update of the Viewer. That update
211will, in ViewerPrivate::parseMsg(), create a new ObjectTreeParser and call parseObjectTree() on it.
212This is where the second run begins.
213
214The functions that deal with decrypting of verifying, like processMultiPartSignedSubtype() or
215processMultiPartEncryptedSubtype() will look if they find a BodyPartMemento that is associated with
216the current node. Now it finds that memento, since it was created in the first run. It checks if the
217memento's job has finished, and if so, the result can be written out (either the decrypted data or
218the verified signature).
219
220When dealing with encrypted nodes, new nodes are created with the decrypted data. It is important to
221note that the original MIME tree is never modified, and remains the same as the original one. The method
222createAndParseTempNode is called with the newly decrypted data, and it generates a new temporary node to
223store the decrypted data. When these nodes are created, it is important to keep track of them as otherwise
224some mementos that are added to the newly created temporary nodes will be constantly regenerated. As the
225regeneration triggers a viewer update when complete, it results in an infinite refresh loop. The function
226NodeHelper::linkAsPermanentDecrypted will create a link between the newly created node and the original parent.
227Conversely, the function NodeHelper::attachExtraContent will create a link in the other direction, from the parent
228node to the newly created temporary node.
229
230When generating some mementos for nodes that may be temporary nodes (for example, contact photo mementos), the
231function NodeHelper::setBodyPartMementoForPermanentParent is used. This will save the given body part memento for
232the closest found permanent parent node, rather than the transient node itself. Then when checking for the existence
233of a certain memento in a node, NodeHelper::findPermanentParentBodyPartMemento will check to see if any parent of the
234given temporary node is a permanent (encrypted) node that has been used to generate the asked-for node.
235
236To conclude: For async operations, parseObjectTree() is called twice: The first call starts the
237crypto operation and creates the BodyPartMemento, the second calls sees that the BodyPartMemento is
238there and can use its result for writing out the HTML.
239
240\par PartMetaData and ProcessResult
241
242For crypto operations, the class PartMetaData is used a lot, mainly to pass around info about the
243crypto state of a node. A PartMetaData can also be associated with a node by using
244NodeHelper::setPartMetaData(). The only user of that however is MessageAnalyzer::processPart() of
245the Nepomuk E-Mail Feeder, which also uses the ObjectTreeParser to analyze the message.
246
247You'll notice that a ProcessResult is passed to each formatter. The formatter is supposed to modify
248the ProcessResult to tell the callers something about the state of the nodes that were processed.
249One example for its use is to tell the caller about the crypto state of the node.
250
251\par BodyPartFormatter Plugins
252
253As mentioned way earlier, BodyPartFormatter can either be plugins or be internal. bodypartformatter.cpp
254contains some trickery so that the processXXX() methods of the ObjectTreeParser are called from
255a BodyPartFormatter associated with them, see the CREATE_BODY_PART_FORMATTER macro.
256
257The BodyPartFormatter code is work in progress, it was supposed to be refactored, but that has not
258yet happened at the time of writing. Therefore the code can seem a bit chaotic.
259
260External plugins are loaded with loadPlugins() in bodypartformatterfactory.cpp. External plugins
261can only use the classes in the interfaces/ directory, they include BodyPart, BodyPartMemento,
262BodyPartFormatterPlugin, BodyPartFormatter, BodyPartURLHandler, HtmlWriter and URLHandler. Therefore
263external plugins have powerful capabilities, which are needed for example in the iCal formatter or
264in the vCard formatter.
265
266\par Special HTML tags
267
268As also mentioned in the documentation of ViewerPrivate, the ObjectTreeParser writes out special
269links that are only understood by the viewer, for example 'kmail:' URLs or 'attachment:' URLs.
270Also, some special HTML tags are created, which the Viewer later uses for post-processing. For
271example a div with the id 'attachmentInjectionPoint', or a div with the id 'attachmentDiv', which
272is used to mark an attachment in the body with a yellow border when the user clicks the attachment
273in the header. Finally, parseObjectTree() creates an anchor with the id 'att%1', which is used in
274the Viewer to scroll to the attachment.
275*/
276class ObjectTreeParser
277{
278 /**
279 * @internal
280 * Copies the context of @p other, but not it's rawDecryptedBody, plainTextContent or htmlContent.
281 */
282 ObjectTreeParser(const ObjectTreeParser &other);
283
284public:
285 explicit ObjectTreeParser(Interface::ObjectTreeSource *source,
286 NodeHelper *nodeHelper = nullptr,
287 bool showOneMimePart = false,
288 const AttachmentStrategy *attachmentStrategy = nullptr);
289
290 explicit ObjectTreeParser(const ObjectTreeParser *topLevelParser,
291 bool showOneMimePart = false,
292 const AttachmentStrategy *attachmentStrategy = nullptr);
293 virtual ~ObjectTreeParser();
294
295 void setAllowAsync(bool allow);
296 bool allowAsync() const;
297
298 bool hasPendingAsyncJobs() const;
299
300 /**
301 * The text of the message, ie. what would appear in the
302 * composer's text editor if this was edited or replied to.
303 * This is usually the content of the first text/plain MIME part.
304 */
305 QString plainTextContent() const;
306
307 /**
308 * Similar to plainTextContent(), but returns the HTML source of the first text/html MIME part.
309 *
310 * Not to be consfused with the HTML code that the message viewer widget displays, that HTML
311 * is written out by htmlWriter() and a totally different pair of shoes.
312 */
313 QString htmlContent() const;
314
315 /**
316 * The original charset of MIME part the plain text was extracted from.
317 *
318 * If there were more than one text/plain MIME parts in the mail, the this is the charset
319 * of the last MIME part processed.
320 */
321 QByteArray plainTextContentCharset() const;
322 QByteArray htmlContentCharset() const;
323
324 bool showOnlyOneMimePart() const;
325 void setShowOnlyOneMimePart(bool show);
326
327 const AttachmentStrategy *attachmentStrategy() const;
328
329 HtmlWriter *htmlWriter() const;
330
331 NodeHelper *nodeHelper() const;
332
333 /** Parse beginning at a given node and recursively parsing
334 the children of that node and it's next sibling. */
335 void parseObjectTree(KMime::Content *node);
336 MessagePartPtr parsedPart() const;
337
338private:
339 void extractNodeInfos(KMime::Content *curNode, bool isFirstTextPart);
340 void setPlainTextContent(const QString &plainTextContent);
341
342 /**
343 * Does the actual work for parseObjectTree. Unlike parseObjectTree(), this does not change the
344 * top-level content.
345 */
346 MessagePartPtr parseObjectTreeInternal(KMime::Content *node, bool mOnlyOneMimePart);
347 bool processType(KMime::Content *node, MimeTreeParser::ProcessResult &processResult, const QByteArray &mediaType, const QByteArray &subType, Interface::MessagePartPtr &mpRet, bool onlyOneMimePart);
348
349 Interface::MessagePartPtr defaultHandling(KMime::Content *node, MimeTreeParser::ProcessResult &result, bool onlyOneMimePart);
350
351private:
352
353 /** ctor helper */
354 void init();
355
356 const QTextCodec *codecFor(KMime::Content *node) const;
357
358 void copyContentFrom(const ObjectTreeParser *other);
359
360private:
361 Interface::ObjectTreeSource *mSource;
362 NodeHelper *mNodeHelper;
363 HtmlWriter *mHtmlWriter;
364 QByteArray mPlainTextContentCharset;
365 QByteArray mHtmlContentCharset;
366 QString mPlainTextContent;
367 QString mHtmlContent;
368 KMime::Content *mTopLevelContent;
369 MessagePartPtr mParsedPart;
370
371 /// Show only one mime part means that the user has selected some node in the message structure
372 /// viewer that is not the root, which means the user wants to only see the selected node and its
373 /// children. If that is the case, this variable is set to true.
374 /// The code needs to behave differently if this is set. For example, it should not process the
375 /// siblings. Also, consider inline images: Normally, those nodes are completely hidden, as the
376 /// HTML node embedds them. However, when showing only the node of the image, one has to show them,
377 /// as their is no HTML node in which they are displayed. There are many more cases where this
378 /// variable needs to be obeyed.
379 /// This variable is set to false again when processing the children in stdChildHandling(), as
380 /// the children can be completely displayed again.
381 bool mShowOnlyOneMimePart;
382
383 bool mHasPendingAsyncJobs;
384 bool mAllowAsync;
385 const AttachmentStrategy *mAttachmentStrategy;
386 // DataUrl Icons cache
387 QString mCollapseIcon;
388 QString mExpandIcon;
389 bool mDeleteNodeHelper;
390
391 friend class PartNodeBodyPart;
392 friend class MessagePart;
393 friend class EncryptedMessagePart;
394 friend class SignedMessagePart;
395 friend class EncapsulatedRfc822MessagePart;
396 friend class TextMessagePart;
397 friend class HtmlMessagePart;
398 friend class TextPlainBodyPartFormatter;
399 friend class MultiPartSignedBodyPartFormatter;
400 friend class ApplicationPkcs7MimeBodyPartFormatter;
401};
402
403}
404
405#endif // __MIMETREEPARSER_OBJECTTREEPARSER_H__
406
diff --git a/framework/src/domain/mimetreeparser/otp/objecttreesource.cpp b/framework/src/domain/mimetreeparser/otp/objecttreesource.cpp
new file mode 100644
index 00000000..45f96c58
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/objecttreesource.cpp
@@ -0,0 +1,28 @@
1/*
2 Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
3 Copyright (c) 2009 Andras Mantia <andras@kdab.net>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18*/
19
20#include "objecttreesource.h"
21#include "bodypartformatter.h"
22#include "messagepart.h"
23
24using namespace MimeTreeParser;
25
26Interface::ObjectTreeSource::~ObjectTreeSource()
27{
28}
diff --git a/framework/src/domain/mimetreeparser/otp/objecttreesource.h b/framework/src/domain/mimetreeparser/otp/objecttreesource.h
new file mode 100644
index 00000000..afada4c4
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/objecttreesource.h
@@ -0,0 +1,109 @@
1/*
2 Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
3 Copyright (c) 2009 Andras Mantia <andras@kdab.net>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18*/
19
20#ifndef __MIMETREEPARSER_OBJECTTREESOURCE_IF_H__
21#define __MIMETREEPARSER_OBJECTTREESOURCE_IF_H__
22
23#include "util.h"
24
25#include <KMime/Message>
26
27#include <QSharedPointer>
28class QTextCodec;
29
30namespace MimeTreeParser
31{
32class HtmlWriter;
33class AttachmentStrategy;
34class BodyPartFormatterBaseFactory;
35namespace Interface
36{
37class MessagePart;
38typedef QSharedPointer<MessagePart> MessagePartPtr;
39class MessagePartRenderer;
40typedef QSharedPointer<MessagePartRenderer> MessagePartRendererPtr;
41}
42}
43
44namespace MimeTreeParser
45{
46namespace Interface
47{
48
49/**
50 * Interface for object tree sources.
51 * @author Andras Mantia <amantia@kdab.net>
52 */
53class ObjectTreeSource
54{
55
56public:
57 virtual ~ObjectTreeSource();
58
59 /**
60 * Sets the type of mail that is currently displayed. Applications can display this
61 * information to the user, for example KMail displays a HTML status bar.
62 * Note: This is not called when the mode is "Normal".
63 */
64 virtual void setHtmlMode(MimeTreeParser::Util::HtmlMode mode, const QList<MimeTreeParser::Util::HtmlMode> &availableModes) = 0;
65
66 /** Return the mode that is the preferred to display */
67 virtual MimeTreeParser::Util::HtmlMode preferredMode() const = 0;
68
69 /** Return true if an encrypted mail should be decrypted */
70 virtual bool decryptMessage() const = 0;
71
72 /** Return true if external sources should be loaded in a html mail */
73 virtual bool htmlLoadExternal() const = 0;
74
75 /** Return true to include the signature details in the generated html */
76 virtual bool showSignatureDetails() const = 0;
77
78 virtual int levelQuote() const = 0;
79
80 /** The override codec that should be used for the mail */
81 virtual const QTextCodec *overrideCodec() = 0;
82
83 virtual QString createMessageHeader(KMime::Message *message) = 0;
84
85 /** Return the wanted attachment startegy */
86 virtual const AttachmentStrategy *attachmentStrategy() = 0;
87
88 /** Return the html write object */
89 virtual HtmlWriter *htmlWriter() = 0;
90
91 /** The source object behind the interface. */
92 virtual QObject *sourceObject() = 0;
93
94 /** should keys be imported automatically **/
95 virtual bool autoImportKeys() const = 0;
96
97 virtual bool showEmoticons() const = 0;
98
99 virtual bool showExpandQuotesMark() const = 0;
100
101 virtual const BodyPartFormatterBaseFactory *bodyPartFormatterFactory() = 0;
102
103 virtual MessagePartRendererPtr messagePartTheme(MessagePartPtr msgPart) = 0;
104
105 virtual bool isPrinting() const = 0;
106};
107}
108}
109#endif
diff --git a/framework/src/domain/mimetreeparser/otp/partmetadata.h b/framework/src/domain/mimetreeparser/otp/partmetadata.h
new file mode 100644
index 00000000..41399837
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/partmetadata.h
@@ -0,0 +1,67 @@
1/* -*- c++ -*-
2 partmetadata.h
3
4 KMail, the KDE mail client.
5 Copyright (c) 2002-2003 Karl-Heinz Zimmer <khz@kde.org>
6 Copyright (c) 2003 Marc Mutz <mutz@kde.org>
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License,
10 version 2.0, as published by the Free Software Foundation.
11 You should have received a copy of the GNU General Public License
12 along with this program; if not, write to the Free Software Foundation,
13 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
14*/
15
16#ifndef __MIMETREEPARSER_PARTMETADATA_H__
17#define __MIMETREEPARSER_PARTMETADATA_H__
18
19#include <gpgme++/verificationresult.h>
20#include <gpgme++/context.h>
21
22#include <QStringList>
23#include <QDateTime>
24
25namespace MimeTreeParser
26{
27
28class PartMetaData
29{
30public:
31 PartMetaData()
32 : sigSummary(GpgME::Signature::None),
33 isSigned(false),
34 isGoodSignature(false),
35 isEncrypted(false),
36 isDecryptable(false),
37 inProgress(false),
38 technicalProblem(false),
39 isEncapsulatedRfc822Message(false)
40 {
41 }
42 GpgME::Signature::Summary sigSummary;
43 QString signClass;
44 QString signer;
45 QStringList signerMailAddresses;
46 QByteArray keyId;
47 GpgME::Signature::Validity keyTrust;
48 QString status; // to be used for unknown plug-ins
49 int status_code; // to be used for i18n of OpenPGP and S/MIME CryptPlugs
50 QString errorText;
51 QDateTime creationTime;
52 QString decryptionError;
53 QString auditLog;
54 GpgME::Error auditLogError;
55 bool isSigned : 1;
56 bool isGoodSignature : 1;
57 bool isEncrypted : 1;
58 bool isDecryptable : 1;
59 bool inProgress : 1;
60 bool technicalProblem : 1;
61 bool isEncapsulatedRfc822Message : 1;
62};
63
64}
65
66#endif // __MIMETREEPARSER_PARTMETADATA_H__
67
diff --git a/framework/src/domain/mimetreeparser/otp/partnodebodypart.cpp b/framework/src/domain/mimetreeparser/otp/partnodebodypart.cpp
new file mode 100644
index 00000000..ec509787
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/partnodebodypart.cpp
@@ -0,0 +1,125 @@
1/*
2 partnodebodypart.cpp
3
4 This file is part of KMail, the KDE mail client.
5 Copyright (c) 2004 Marc Mutz <mutz@kde.org>,
6 Ingo Kloecker <kloecker@kde.org>
7
8 KMail is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 KMail is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
22 In addition, as a special exception, the copyright holders give
23 permission to link the code of this program with any edition of
24 the Qt library by Trolltech AS, Norway (or with modified versions
25 of Qt that use the same license as Qt), and distribute linked
26 combinations including the two. You must obey the GNU General
27 Public License in all respects for all of the code used other than
28 Qt. If you modify this file, you may extend this exception to
29 your version of the file, but you are not obligated to do so. If
30 you do not wish to do so, delete this exception statement from
31 your version.
32*/
33
34#include "partnodebodypart.h"
35#include "nodehelper.h"
36#include "objecttreeparser.h"
37#include "mimetreeparser_debug.h"
38#include <KMime/Content>
39
40#include <QTextCodec>
41#include <QUrl>
42
43using namespace MimeTreeParser;
44
45static int serial = 0;
46
47PartNodeBodyPart::PartNodeBodyPart(ObjectTreeParser *otp, ProcessResult *result, KMime::Content *topLevelContent, KMime::Content *content,
48 NodeHelper *nodeHelper)
49 : Interface::BodyPart(), mTopLevelContent(topLevelContent), mContent(content),
50 mDefaultDisplay(Interface::BodyPart::None), mNodeHelper(nodeHelper)
51 , mObjectTreeParser(otp)
52 , mProcessResult(result)
53{}
54
55QString PartNodeBodyPart::makeLink(const QString &path) const
56{
57 // FIXME: use a PRNG for the first arg, instead of a serial number
58 return QStringLiteral("x-kmail:/bodypart/%1/%2/%3")
59 .arg(serial++).arg(mContent->index().toString())
60 .arg(QString::fromLatin1(QUrl::toPercentEncoding(path, "/")));
61}
62
63QString PartNodeBodyPart::asText() const
64{
65 if (!mContent->contentType()->isText()) {
66 return QString();
67 }
68 return mContent->decodedText();
69}
70
71QByteArray PartNodeBodyPart::asBinary() const
72{
73 return mContent->decodedContent();
74}
75
76QString PartNodeBodyPart::contentTypeParameter(const char *param) const
77{
78 return mContent->contentType()->parameter(QString::fromLatin1(param));
79}
80
81QString PartNodeBodyPart::contentDescription() const
82{
83 return mContent->contentDescription()->asUnicodeString();
84}
85
86QString PartNodeBodyPart::contentDispositionParameter(const char *param) const
87{
88 return mContent->contentDisposition()->parameter(QString::fromLatin1(param));
89}
90
91bool PartNodeBodyPart::hasCompleteBody() const
92{
93 qCWarning(MIMETREEPARSER_LOG) << "Sorry, not yet implemented.";
94 return true;
95}
96
97Interface::BodyPartMemento *PartNodeBodyPart::memento() const
98{
99 /*TODO(Andras) Volker suggests to use a ContentIndex->Mememnto mapping
100 Also review if the reader's bodyPartMemento should be returned or the NodeHelper's one
101 */
102 return mNodeHelper->bodyPartMemento(mContent, "__plugin__");
103}
104
105void PartNodeBodyPart::setBodyPartMemento(Interface::BodyPartMemento *memento)
106{
107 /*TODO(Andras) Volker suggests to use a ContentIndex->Memento mapping
108 Also review if the reader's bodyPartMemento should be set or the NodeHelper's one */
109 mNodeHelper->setBodyPartMemento(mContent, "__plugin__", memento);
110}
111
112Interface::BodyPart::Display PartNodeBodyPart::defaultDisplay() const
113{
114 return mDefaultDisplay;
115}
116
117void PartNodeBodyPart::setDefaultDisplay(Interface::BodyPart::Display d)
118{
119 mDefaultDisplay = d;
120}
121
122Interface::ObjectTreeSource *PartNodeBodyPart::source() const
123{
124 return mObjectTreeParser->mSource;
125}
diff --git a/framework/src/domain/mimetreeparser/otp/partnodebodypart.h b/framework/src/domain/mimetreeparser/otp/partnodebodypart.h
new file mode 100644
index 00000000..ded0ee2c
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/partnodebodypart.h
@@ -0,0 +1,108 @@
1/*
2 partnodebodypart.h
3
4 This file is part of KMail, the KDE mail client.
5 Copyright (c) 2004 Marc Mutz <mutz@kde.org>,
6 Ingo Kloecker <kloecker@kde.org>
7
8 KMail is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 KMail is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
22 In addition, as a special exception, the copyright holders give
23 permission to link the code of this program with any edition of
24 the Qt library by Trolltech AS, Norway (or with modified versions
25 of Qt that use the same license as Qt), and distribute linked
26 combinations including the two. You must obey the GNU General
27 Public License in all respects for all of the code used other than
28 Qt. If you modify this file, you may extend this exception to
29 your version of the file, but you are not obligated to do so. If
30 you do not wish to do so, delete this exception statement from
31 your version.
32*/
33
34#ifndef __MIMETREEPARSER_PARTNODEBODYPART_H__
35#define __MIMETREEPARSER_PARTNODEBODYPART_H__
36
37#include "bodypart.h"
38
39namespace KMime
40{
41class Content;
42}
43
44namespace MimeTreeParser
45{
46class NodeHelper;
47}
48
49namespace MimeTreeParser
50{
51
52/**
53 @short an implementation of the BodyPart interface using KMime::Content's
54*/
55class PartNodeBodyPart : public Interface::BodyPart
56{
57public:
58 explicit PartNodeBodyPart(ObjectTreeParser *otp, ProcessResult *result, KMime::Content *topLevelContent, KMime::Content *content,
59 NodeHelper *nodeHelper);
60
61 QString makeLink(const QString &path) const Q_DECL_OVERRIDE;
62 QString asText() const Q_DECL_OVERRIDE;
63 QByteArray asBinary() const Q_DECL_OVERRIDE;
64 QString contentTypeParameter(const char *param) const Q_DECL_OVERRIDE;
65 QString contentDescription() const Q_DECL_OVERRIDE;
66 QString contentDispositionParameter(const char *param) const Q_DECL_OVERRIDE;
67 bool hasCompleteBody() const Q_DECL_OVERRIDE;
68
69 Interface::BodyPartMemento *memento() const Q_DECL_OVERRIDE;
70 void setBodyPartMemento(Interface::BodyPartMemento *memento) Q_DECL_OVERRIDE;
71 BodyPart::Display defaultDisplay() const Q_DECL_OVERRIDE;
72 void setDefaultDisplay(BodyPart::Display);
73 KMime::Content *content() const Q_DECL_OVERRIDE
74 {
75 return mContent;
76 }
77 KMime::Content *topLevelContent() const Q_DECL_OVERRIDE
78 {
79 return mTopLevelContent;
80 }
81 NodeHelper *nodeHelper() const Q_DECL_OVERRIDE
82 {
83 return mNodeHelper;
84 }
85
86 ObjectTreeParser *objectTreeParser() const Q_DECL_OVERRIDE
87 {
88 return mObjectTreeParser;
89 }
90
91 ProcessResult *processResult() const Q_DECL_OVERRIDE
92 {
93 return mProcessResult;
94 }
95
96 Interface::ObjectTreeSource *source() const Q_DECL_OVERRIDE;
97private:
98 KMime::Content *mTopLevelContent;
99 KMime::Content *mContent;
100 BodyPart::Display mDefaultDisplay;
101 NodeHelper *mNodeHelper;
102 ObjectTreeParser *mObjectTreeParser;
103 ProcessResult *mProcessResult;
104};
105
106}
107
108#endif // __MIMETREEPARSER_PARTNODEBODYPART_H__
diff --git a/framework/src/domain/mimetreeparser/otp/qgpgmejobexecutor.cpp b/framework/src/domain/mimetreeparser/otp/qgpgmejobexecutor.cpp
new file mode 100644
index 00000000..1f453342
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/qgpgmejobexecutor.cpp
@@ -0,0 +1,158 @@
1/*
2 Copyright (c) 2008 Volker Krause <vkrause@kde.org>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17*/
18
19#include "qgpgmejobexecutor.h"
20#include "mimetreeparser_debug.h"
21
22#include <QGpgME/DecryptVerifyJob>
23#include <QGpgME/ImportJob>
24#include <QGpgME/VerifyDetachedJob>
25#include <QGpgME/VerifyOpaqueJob>
26
27#include <QEventLoop>
28
29#include <cassert>
30
31using namespace GpgME;
32using namespace MimeTreeParser;
33
34QGpgMEJobExecutor::QGpgMEJobExecutor(QObject *parent) : QObject(parent)
35{
36 setObjectName(QStringLiteral("KleoJobExecutor"));
37 mEventLoop = new QEventLoop(this);
38}
39
40GpgME::VerificationResult QGpgMEJobExecutor::exec(
41 QGpgME::VerifyDetachedJob *job,
42 const QByteArray &signature,
43 const QByteArray &signedData)
44{
45 qCDebug(MIMETREEPARSER_LOG) << "Starting detached verification job";
46 connect(job, SIGNAL(result(GpgME::VerificationResult)), SLOT(verificationResult(GpgME::VerificationResult)));
47 GpgME::Error err = job->start(signature, signedData);
48 if (err) {
49 return VerificationResult(err);
50 }
51 mEventLoop->exec(QEventLoop::ExcludeUserInputEvents);
52 return mVerificationResult;
53}
54
55GpgME::VerificationResult QGpgMEJobExecutor::exec(
56 QGpgME::VerifyOpaqueJob *job,
57 const QByteArray &signedData,
58 QByteArray &plainText)
59{
60 qCDebug(MIMETREEPARSER_LOG) << "Starting opaque verification job";
61 connect(job, SIGNAL(result(GpgME::VerificationResult,QByteArray)), SLOT(verificationResult(GpgME::VerificationResult,QByteArray)));
62 GpgME::Error err = job->start(signedData);
63 if (err) {
64 plainText.clear();
65 return VerificationResult(err);
66 }
67 mEventLoop->exec(QEventLoop::ExcludeUserInputEvents);
68 plainText = mData;
69 return mVerificationResult;
70}
71
72std::pair< GpgME::DecryptionResult, GpgME::VerificationResult > QGpgMEJobExecutor::exec(
73 QGpgME::DecryptVerifyJob *job,
74 const QByteArray &cipherText,
75 QByteArray &plainText)
76{
77 qCDebug(MIMETREEPARSER_LOG) << "Starting decryption job";
78 connect(job, &QGpgME::DecryptVerifyJob::result, this, &QGpgMEJobExecutor::decryptResult);
79 GpgME::Error err = job->start(cipherText);
80 if (err) {
81 plainText.clear();
82 return std::make_pair(DecryptionResult(err), VerificationResult(err));
83 }
84 mEventLoop->exec(QEventLoop::ExcludeUserInputEvents);
85 plainText = mData;
86 return std::make_pair(mDecryptResult, mVerificationResult);
87}
88
89GpgME::ImportResult QGpgMEJobExecutor::exec(QGpgME::ImportJob *job, const QByteArray &certData)
90{
91 connect(job, SIGNAL(result(GpgME::ImportResult)), SLOT(importResult(GpgME::ImportResult)));
92 GpgME::Error err = job->start(certData);
93 if (err) {
94 return ImportResult(err);
95 }
96 mEventLoop->exec(QEventLoop::ExcludeUserInputEvents);
97 return mImportResult;
98}
99
100Error QGpgMEJobExecutor::auditLogError() const
101{
102 return mAuditLogError;
103}
104
105void QGpgMEJobExecutor::verificationResult(const GpgME::VerificationResult &result)
106{
107 qCDebug(MIMETREEPARSER_LOG) << "Detached verification job finished";
108 QGpgME::Job *job = qobject_cast<QGpgME::Job *>(sender());
109 assert(job);
110 mVerificationResult = result;
111 mAuditLogError = job->auditLogError();
112 mAuditLog = job->auditLogAsHtml();
113 mEventLoop->quit();
114}
115
116void QGpgMEJobExecutor::verificationResult(const GpgME::VerificationResult &result, const QByteArray &plainText)
117{
118 qCDebug(MIMETREEPARSER_LOG) << "Opaque verification job finished";
119 QGpgME::Job *job = qobject_cast<QGpgME::Job *>(sender());
120 assert(job);
121 mVerificationResult = result;
122 mData = plainText;
123 mAuditLogError = job->auditLogError();
124 mAuditLog = job->auditLogAsHtml();
125 mEventLoop->quit();
126}
127
128void QGpgMEJobExecutor::decryptResult(
129 const GpgME::DecryptionResult &decryptionresult,
130 const GpgME::VerificationResult &verificationresult,
131 const QByteArray &plainText)
132{
133 qCDebug(MIMETREEPARSER_LOG) << "Decryption job finished";
134 QGpgME::Job *job = qobject_cast<QGpgME::Job *>(sender());
135 assert(job);
136 mVerificationResult = verificationresult;
137 mDecryptResult = decryptionresult;
138 mData = plainText;
139 mAuditLogError = job->auditLogError();
140 mAuditLog = job->auditLogAsHtml();
141 mEventLoop->quit();
142}
143
144void QGpgMEJobExecutor::importResult(const GpgME::ImportResult &result)
145{
146 QGpgME::Job *job = qobject_cast<QGpgME::Job *>(sender());
147 assert(job);
148 mImportResult = result;
149 mAuditLogError = job->auditLogError();
150 mAuditLog = job->auditLogAsHtml();
151 mEventLoop->quit();
152}
153
154QString QGpgMEJobExecutor::auditLogAsHtml() const
155{
156 return mAuditLog;
157}
158
diff --git a/framework/src/domain/mimetreeparser/otp/qgpgmejobexecutor.h b/framework/src/domain/mimetreeparser/otp/qgpgmejobexecutor.h
new file mode 100644
index 00000000..8a81b078
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/qgpgmejobexecutor.h
@@ -0,0 +1,86 @@
1/*
2 Copyright (c) 2008 Volker Krause <vkrause@kde.org>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17*/
18
19#ifndef __MIMETREEPARSER_KLEOJOBEXECUTOR_H__
20#define __MIMETREEPARSER_KLEOJOBEXECUTOR_H__
21
22#include <gpgme++/decryptionresult.h>
23#include <gpgme++/importresult.h>
24#include <gpgme++/verificationresult.h>
25
26#include <QObject>
27
28#include <utility>
29
30class QEventLoop;
31
32namespace QGpgME
33{
34class DecryptVerifyJob;
35class ImportJob;
36class VerifyDetachedJob;
37class VerifyOpaqueJob;
38}
39
40namespace MimeTreeParser
41{
42
43/**
44 Helper class for synchronous execution of Kleo crypto jobs.
45*/
46class QGpgMEJobExecutor : public QObject
47{
48 Q_OBJECT
49public:
50 explicit QGpgMEJobExecutor(QObject *parent = nullptr);
51
52 GpgME::VerificationResult exec(QGpgME::VerifyDetachedJob *job,
53 const QByteArray &signature,
54 const QByteArray &signedData);
55 GpgME::VerificationResult exec(QGpgME::VerifyOpaqueJob *job,
56 const QByteArray &signedData,
57 QByteArray &plainText);
58 std::pair<GpgME::DecryptionResult, GpgME::VerificationResult> exec(QGpgME::DecryptVerifyJob *job,
59 const QByteArray &cipherText,
60 QByteArray &plainText);
61 GpgME::ImportResult exec(QGpgME::ImportJob *job, const QByteArray &certData);
62
63 GpgME::Error auditLogError() const;
64 QString auditLogAsHtml() const;
65
66private Q_SLOTS:
67 void verificationResult(const GpgME::VerificationResult &result);
68 void verificationResult(const GpgME::VerificationResult &result, const QByteArray &plainText);
69 void decryptResult(const GpgME::DecryptionResult &decryptionresult,
70 const GpgME::VerificationResult &verificationresult,
71 const QByteArray &plainText);
72 void importResult(const GpgME::ImportResult &result);
73
74private:
75 QEventLoop *mEventLoop;
76 GpgME::VerificationResult mVerificationResult;
77 GpgME::DecryptionResult mDecryptResult;
78 GpgME::ImportResult mImportResult;
79 QByteArray mData;
80 GpgME::Error mAuditLogError;
81 QString mAuditLog;
82};
83
84}
85
86#endif
diff --git a/framework/src/domain/mimetreeparser/otp/queuehtmlwriter.cpp b/framework/src/domain/mimetreeparser/otp/queuehtmlwriter.cpp
new file mode 100644
index 00000000..ea17bf5c
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/queuehtmlwriter.cpp
@@ -0,0 +1,136 @@
1/*
2 Copyright (c) 2015 Sandro Knauß <sknauss@kde.org>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20#include "queuehtmlwriter.h"
21
22#include "mimetreeparser_debug.h"
23
24#include<QByteArray>
25#include<QString>
26
27using namespace MimeTreeParser;
28
29QueueHtmlWriter::QueueHtmlWriter(HtmlWriter *base)
30 : HtmlWriter()
31 , mBase(base)
32{
33}
34
35QueueHtmlWriter::~QueueHtmlWriter()
36{
37}
38
39void QueueHtmlWriter::setBase(HtmlWriter *base)
40{
41 mBase = base;
42}
43
44void QueueHtmlWriter::begin(const QString &css)
45{
46 Command cmd;
47 cmd.type = Command::Begin;
48 cmd.s = css;
49 mQueue.append(cmd);
50}
51
52void QueueHtmlWriter::end()
53{
54 Command cmd;
55 cmd.type = Command::End;
56 mQueue.append(cmd);
57}
58
59void QueueHtmlWriter::reset()
60{
61 Command cmd;
62 cmd.type = Command::Reset;
63 mQueue.append(cmd);
64}
65
66void QueueHtmlWriter::write(const QString &str)
67{
68 Command cmd;
69 cmd.type = Command::Write;
70 cmd.s = str;
71 mQueue.append(cmd);
72}
73
74void QueueHtmlWriter::queue(const QString &str)
75{
76 Command cmd;
77 cmd.type = Command::Queue;
78 cmd.s = str;
79 mQueue.append(cmd);
80}
81
82void QueueHtmlWriter::flush()
83{
84 Command cmd;
85 cmd.type = Command::Flush;
86 mQueue.append(cmd);
87}
88
89void QueueHtmlWriter::replay()
90{
91 foreach (const auto &entry, mQueue) {
92 switch (entry.type) {
93 case Command::Begin:
94 mBase->begin(entry.s);
95 break;
96 case Command::End:
97 mBase->end();
98 break;
99 case Command::Reset:
100 mBase->reset();
101 break;
102 case Command::Write:
103 mBase->write(entry.s);
104 break;
105 case Command::Queue:
106 mBase->queue(entry.s);
107 break;
108 case Command::Flush:
109 mBase->flush();
110 break;
111 case Command::EmbedPart:
112 mBase->embedPart(entry.b, entry.s);
113 break;
114 case Command::ExtraHead:
115 mBase->extraHead(entry.s);
116 break;
117 }
118 }
119}
120
121void QueueHtmlWriter::embedPart(const QByteArray &contentId, const QString &url)
122{
123 Command cmd;
124 cmd.type = Command::EmbedPart;
125 cmd.s = url;
126 cmd.b = contentId;
127 mQueue.append(cmd);
128}
129void QueueHtmlWriter::extraHead(const QString &extra)
130{
131 Command cmd;
132 cmd.type = Command::ExtraHead;
133 cmd.s = extra;
134 mQueue.append(cmd);
135}
136
diff --git a/framework/src/domain/mimetreeparser/otp/queuehtmlwriter.h b/framework/src/domain/mimetreeparser/otp/queuehtmlwriter.h
new file mode 100644
index 00000000..9e7a4659
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/queuehtmlwriter.h
@@ -0,0 +1,75 @@
1/*
2 Copyright (c) 2015 Sandro Knauß <sknauss@kde.org>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20#ifndef __MIMETREEPARSER_QUEUEHTMLWRITER_H__
21#define __MIMETREEPARSER_QUEUEHTMLWRITER_H__
22
23#include "htmlwriter.h"
24
25#include<QVector>
26#include<QVariant>
27
28class QString;
29class QByteArray;
30
31namespace MimeTreeParser
32{
33/**
34\brief Cache HTML output and not write them directy.
35
36This class is needed to make it possible to first process the mime tree and
37afterwards render the HTML.
38
39Please do not use this class - it is only added to make it possible to slowly
40move ObjectTreeParser to a process fist / render later.
41
42*/
43struct Command {
44 enum { Begin, End, Reset, Write, Queue, Flush, EmbedPart, ExtraHead } type;
45 QString s;
46 QByteArray b;
47};
48
49class QueueHtmlWriter : public HtmlWriter
50{
51public:
52 explicit QueueHtmlWriter(MimeTreeParser::HtmlWriter *base);
53 virtual ~QueueHtmlWriter();
54
55 void setBase(HtmlWriter *base);
56
57 void begin(const QString &cssDefs) Q_DECL_OVERRIDE;
58 void end() Q_DECL_OVERRIDE;
59 void reset() Q_DECL_OVERRIDE;
60 void write(const QString &str) Q_DECL_OVERRIDE;
61 void queue(const QString &str) Q_DECL_OVERRIDE;
62 void flush() Q_DECL_OVERRIDE;
63 void embedPart(const QByteArray &contentId, const QString &url) Q_DECL_OVERRIDE;
64 void extraHead(const QString &str) Q_DECL_OVERRIDE;
65
66 void replay();
67
68private:
69 HtmlWriter *mBase;
70 QVector<Command> mQueue;
71};
72
73} // namespace MimeTreeParser
74
75#endif // __MIMETREEPARSER_QUEUEHTMLWRITER_H__
diff --git a/framework/src/domain/mimetreeparser/otp/util.cpp b/framework/src/domain/mimetreeparser/otp/util.cpp
new file mode 100644
index 00000000..5ca8d828
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/util.cpp
@@ -0,0 +1,136 @@
1/*
2 Copyright (c) 2016 Sandro Knauß <sknauss@kde.org>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17*/
18
19#include "util.h"
20
21#include "mimetreeparser_debug.h"
22
23#include "nodehelper.h"
24
25#include <KMime/Content>
26
27#include <QMimeDatabase>
28#include <QString>
29
30using namespace MimeTreeParser::Util;
31
32bool MimeTreeParser::Util::isTypeBlacklisted(KMime::Content *node)
33{
34 const QByteArray mediaTypeLower = node->contentType()->mediaType().toLower();
35 bool typeBlacklisted = mediaTypeLower == "multipart";
36 if (!typeBlacklisted) {
37 typeBlacklisted = KMime::isCryptoPart(node);
38 }
39 typeBlacklisted = typeBlacklisted || node == node->topLevel();
40 const bool firstTextChildOfEncapsulatedMsg =
41 mediaTypeLower == "text" &&
42 node->contentType()->subType().toLower() == "plain" &&
43 node->parent() && node->parent()->contentType()->mediaType().toLower() == "message";
44 return typeBlacklisted || firstTextChildOfEncapsulatedMsg;
45}
46
47QString MimeTreeParser::Util::labelForContent(KMime::Content *node)
48{
49 const QString name = node->contentType()->name();
50 QString label = name.isEmpty() ? NodeHelper::fileName(node) : name;
51 if (label.isEmpty()) {
52 label = node->contentDescription()->asUnicodeString();
53 }
54 return label;
55}
56
57QMimeType MimeTreeParser::Util::mimetype(const QString &name)
58{
59 QMimeDatabase db;
60 // consider the filename if mimetype cannot be found by content-type
61 const auto mimeTypes = db.mimeTypesForFileName(name);
62 for (const auto &mt : mimeTypes) {
63 if (mt.name() != QLatin1String("application/octet-stream")) {
64 return mt;
65 }
66 }
67
68 // consider the attachment's contents if neither the Content-Type header
69 // nor the filename give us a clue
70 return db.mimeTypeForFile(name);
71}
72
73QString MimeTreeParser::Util::iconNameForMimetype(const QString &mimeType,
74 const QString &fallbackFileName1,
75 const QString &fallbackFileName2)
76{
77 QString fileName;
78 QString tMimeType = mimeType;
79
80 // convert non-registered types to registered types
81 if (mimeType == QLatin1String("application/x-vnd.kolab.contact")) {
82 tMimeType = QStringLiteral("text/x-vcard");
83 } else if (mimeType == QLatin1String("application/x-vnd.kolab.event")) {
84 tMimeType = QStringLiteral("application/x-vnd.akonadi.calendar.event");
85 } else if (mimeType == QLatin1String("application/x-vnd.kolab.task")) {
86 tMimeType = QStringLiteral("application/x-vnd.akonadi.calendar.todo");
87 } else if (mimeType == QLatin1String("application/x-vnd.kolab.journal")) {
88 tMimeType = QStringLiteral("application/x-vnd.akonadi.calendar.journal");
89 } else if (mimeType == QLatin1String("application/x-vnd.kolab.note")) {
90 tMimeType = QStringLiteral("application/x-vnd.akonadi.note");
91 } else if (mimeType == QLatin1String("image/jpg")) {
92 tMimeType = QStringLiteral("image/jpeg");
93 }
94 QMimeDatabase mimeDb;
95 auto mime = mimeDb.mimeTypeForName(tMimeType);
96 if (mime.isValid()) {
97 fileName = mime.iconName();
98 } else {
99 fileName = QStringLiteral("unknown");
100 if (!tMimeType.isEmpty()) {
101 qCWarning(MIMETREEPARSER_LOG) << "unknown mimetype" << tMimeType;
102 }
103 }
104 //WorkAround for #199083
105 if (fileName == QLatin1String("text-vcard")) {
106 fileName = QStringLiteral("text-x-vcard");
107 }
108
109 if (fileName.isEmpty()) {
110 fileName = fallbackFileName1;
111 if (fileName.isEmpty()) {
112 fileName = fallbackFileName2;
113 }
114 if (!fileName.isEmpty()) {
115 fileName = mimeDb.mimeTypeForFile(QLatin1String("/tmp/") + fileName).iconName();
116 }
117 }
118
119 return fileName;
120}
121
122QString MimeTreeParser::Util::iconNameForContent(KMime::Content *node)
123{
124 if (!node) {
125 return QString();
126 }
127
128 QByteArray mimeType = node->contentType()->mimeType();
129 if (mimeType.isNull() || mimeType == "application/octet-stream") {
130 const QString mime = mimetype(node->contentDisposition()->filename()).name();
131 mimeType = mime.toLatin1();
132 }
133 mimeType = mimeType.toLower();
134 return iconNameForMimetype(QLatin1String(mimeType), node->contentDisposition()->filename(),
135 node->contentType()->name());
136}
diff --git a/framework/src/domain/mimetreeparser/otp/util.h b/framework/src/domain/mimetreeparser/otp/util.h
new file mode 100644
index 00000000..099c647a
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/util.h
@@ -0,0 +1,67 @@
1/*
2 Copyright (c) 2016 Sandro Knauß <sknauss@kde.org>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17*/
18
19#ifndef __MIMETREEPARSER_UTILS_UTIL_H__
20#define __MIMETREEPARSER_UTILS_UTIL_H__
21
22#include <QString>
23
24class QMimeType;
25
26namespace KMime
27{
28class Content;
29}
30
31namespace MimeTreeParser
32{
33
34/**
35 * The Util namespace contains a collection of helper functions use in
36 * various places.
37 */
38namespace Util
39{
40
41/**
42 * Describes the type of the displayed message. This depends on the MIME structure
43 * of the mail and on whether HTML mode is enabled (which is decided by htmlMail())
44 */
45enum HtmlMode {
46 Normal, ///< A normal plaintext message, non-multipart
47 Html, ///< A HTML message, non-multipart
48 MultipartPlain, ///< A multipart/alternative message, the plain text part is currently displayed
49 MultipartHtml, ///< A multipart/altervative message, the HTML part is currently displayed
50 MultipartIcal ///< A multipart/altervative message, the ICal part is currently displayed
51};
52
53bool isTypeBlacklisted(KMime::Content *node);
54
55QString labelForContent(KMime::Content *node);
56
57QMimeType mimetype(const QString &name);
58
59QString iconNameForMimetype(const QString &mimeType,
60 const QString &fallbackFileName1 = QString(),
61 const QString &fallbackFileName2 = QString());
62
63QString iconNameForContent(KMime::Content *node);
64}
65}
66
67#endif
diff --git a/framework/src/domain/mimetreeparser/otp/utils.cpp b/framework/src/domain/mimetreeparser/otp/utils.cpp
new file mode 100644
index 00000000..8f718143
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/utils.cpp
@@ -0,0 +1,70 @@
1/*
2 Copyright (c) 2016 Sandro Knauß <sknauss@kde.org>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20#include "utils.h"
21
22using namespace MimeTreeParser;
23
24MimeMessagePart::Ptr MimeTreeParser::createAndParseTempNode(Interface::BodyPart &part, KMime::Content *parentNode, const char *content, const char *cntDesc)
25{
26 KMime::Content *newNode = new KMime::Content();
27 newNode->setContent(KMime::CRLFtoLF(content));
28 newNode->parse();
29
30 if (!newNode->head().isEmpty()) {
31 newNode->contentDescription()->from7BitString(cntDesc);
32 }
33 part.nodeHelper()->attachExtraContent(parentNode, newNode);
34
35 return MimeMessagePart::Ptr(new MimeMessagePart(part.objectTreeParser(), newNode, false));
36}
37
38KMime::Content *MimeTreeParser::findTypeInDirectChilds(KMime::Content *content, const QByteArray &mimeType)
39{
40 if (mimeType.isEmpty()) {
41 return content;
42 }
43
44 foreach (auto child, content->contents()) {
45 if ((!child->contentType()->isEmpty())
46 && (mimeType == child->contentType()->mimeType())) {
47 return child;
48 }
49 }
50 return nullptr;
51}
52
53MessagePart::Ptr MimeTreeParser::toplevelTextNode(MessagePart::Ptr messageTree)
54{
55 foreach (const auto &mp, messageTree->subParts()) {
56 auto text = mp.dynamicCast<TextMessagePart>();
57 auto attach = mp.dynamicCast<AttachmentMessagePart>();
58 if (text && !attach) {
59 return text;
60 } else if (const auto alternative = mp.dynamicCast<AlternativeMessagePart>()) {
61 return alternative;
62 } else if (const auto m = mp.dynamicCast<MessagePart>()) {
63 auto ret = toplevelTextNode(m);
64 if (ret) {
65 return ret;
66 }
67 }
68 }
69 return MessagePart::Ptr();
70}
diff --git a/framework/src/domain/mimetreeparser/otp/utils.h b/framework/src/domain/mimetreeparser/otp/utils.h
new file mode 100644
index 00000000..d4aaa43a
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/utils.h
@@ -0,0 +1,42 @@
1/*
2 Copyright (c) 2016 Sandro Knauß <sknauss@kde.org>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20#ifndef __MIMETREEPARSER_BODYFORAMATTER_UTILS_H__
21#define __MIMETREEPARSER_BODYFORAMATTER_UTILS_H__
22
23#include "bodypart.h"
24#include "messagepart.h"
25
26#include <KMime/Content>
27
28namespace MimeTreeParser
29{
30/**
31 1. Create a new partNode using 'content' data and Content-Description
32 found in 'cntDesc'.
33 2. Parse the 'node' to display the content.
34*/
35MimeMessagePart::Ptr createAndParseTempNode(Interface::BodyPart &part, KMime::Content *parentNode, const char *content, const char *cntDesc);
36
37KMime::Content *findTypeInDirectChilds(KMime::Content *content, const QByteArray &mimeType);
38
39MessagePart::Ptr toplevelTextNode(MessagePart::Ptr messageTree);
40}
41
42#endif
diff --git a/framework/src/domain/mimetreeparser/otp/verifydetachedbodypartmemento.cpp b/framework/src/domain/mimetreeparser/otp/verifydetachedbodypartmemento.cpp
new file mode 100644
index 00000000..56c1d1a7
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/verifydetachedbodypartmemento.cpp
@@ -0,0 +1,177 @@
1/*
2 Copyright (c) 2014-2017 Montel Laurent <montel@kde.org>
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License, version 2, as
6 published by the Free Software Foundation.
7
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16*/
17
18#include "verifydetachedbodypartmemento.h"
19#include "mimetreeparser_debug.h"
20
21#include <QGpgME/VerifyDetachedJob>
22#include <QGpgME/KeyListJob>
23
24#include <gpgme++/keylistresult.h>
25
26#include <qstringlist.h>
27
28#include <cassert>
29
30using namespace QGpgME;
31using namespace GpgME;
32using namespace MimeTreeParser;
33
34VerifyDetachedBodyPartMemento::VerifyDetachedBodyPartMemento(VerifyDetachedJob *job,
35 KeyListJob *klj,
36 const QByteArray &signature,
37 const QByteArray &plainText)
38 : CryptoBodyPartMemento(),
39 m_signature(signature),
40 m_plainText(plainText),
41 m_job(job),
42 m_keylistjob(klj)
43{
44 assert(m_job);
45}
46
47VerifyDetachedBodyPartMemento::~VerifyDetachedBodyPartMemento()
48{
49 if (m_job) {
50 m_job->slotCancel();
51 }
52 if (m_keylistjob) {
53 m_keylistjob->slotCancel();
54 }
55}
56
57bool VerifyDetachedBodyPartMemento::start()
58{
59 assert(m_job);
60#ifdef DEBUG_SIGNATURE
61 qCDebug(MIMETREEPARSER_LOG) << "tokoe: VerifyDetachedBodyPartMemento started";
62#endif
63 connect(m_job, SIGNAL(result(GpgME::VerificationResult)),
64 this, SLOT(slotResult(GpgME::VerificationResult)));
65 if (const Error err = m_job->start(m_signature, m_plainText)) {
66 m_vr = VerificationResult(err);
67#ifdef DEBUG_SIGNATURE
68 qCDebug(MIMETREEPARSER_LOG) << "tokoe: VerifyDetachedBodyPartMemento stopped with error";
69#endif
70 return false;
71 }
72 setRunning(true);
73 return true;
74}
75
76void VerifyDetachedBodyPartMemento::exec()
77{
78 assert(m_job);
79 setRunning(true);
80#ifdef DEBUG_SIGNATURE
81 qCDebug(MIMETREEPARSER_LOG) << "tokoe: VerifyDetachedBodyPartMemento execed";
82#endif
83 saveResult(m_job->exec(m_signature, m_plainText));
84 m_job->deleteLater(); // exec'ed jobs don't delete themselves
85 m_job = nullptr;
86#ifdef DEBUG_SIGNATURE
87 qCDebug(MIMETREEPARSER_LOG) << "tokoe: VerifyDetachedBodyPartMemento after execed";
88#endif
89 if (canStartKeyListJob()) {
90 std::vector<GpgME::Key> keys;
91 m_keylistjob->exec(keyListPattern(), /*secretOnly=*/false, keys);
92 if (!keys.empty()) {
93 m_key = keys.back();
94 }
95 }
96 if (m_keylistjob) {
97 m_keylistjob->deleteLater(); // exec'ed jobs don't delete themselves
98 }
99 m_keylistjob = nullptr;
100 setRunning(false);
101}
102
103bool VerifyDetachedBodyPartMemento::canStartKeyListJob() const
104{
105 if (!m_keylistjob) {
106 return false;
107 }
108 const char *const fpr = m_vr.signature(0).fingerprint();
109 return fpr && *fpr;
110}
111
112QStringList VerifyDetachedBodyPartMemento::keyListPattern() const
113{
114 assert(canStartKeyListJob());
115 return QStringList(QString::fromLatin1(m_vr.signature(0).fingerprint()));
116}
117
118void VerifyDetachedBodyPartMemento::saveResult(const VerificationResult &vr)
119{
120 assert(m_job);
121#ifdef DEBUG_SIGNATURE
122 qCDebug(MIMETREEPARSER_LOG) << "tokoe: VerifyDetachedBodyPartMemento::saveResult called";
123#endif
124 m_vr = vr;
125 setAuditLog(m_job->auditLogError(), m_job->auditLogAsHtml());
126}
127
128void VerifyDetachedBodyPartMemento::slotResult(const VerificationResult &vr)
129{
130#ifdef DEBUG_SIGNATURE
131 qCDebug(MIMETREEPARSER_LOG) << "tokoe: VerifyDetachedBodyPartMemento::slotResult called";
132#endif
133 saveResult(vr);
134 m_job = nullptr;
135 if (canStartKeyListJob() && startKeyListJob()) {
136#ifdef DEBUG_SIGNATURE
137 qCDebug(MIMETREEPARSER_LOG) << "tokoe: VerifyDetachedBodyPartMemento: canStartKeyListJob && startKeyListJob";
138#endif
139 return;
140 }
141 if (m_keylistjob) {
142 m_keylistjob->deleteLater();
143 }
144 m_keylistjob = nullptr;
145 setRunning(false);
146 notify();
147}
148
149bool VerifyDetachedBodyPartMemento::startKeyListJob()
150{
151 assert(canStartKeyListJob());
152 if (const GpgME::Error err = m_keylistjob->start(keyListPattern())) {
153 return false;
154 }
155 connect(m_keylistjob, SIGNAL(done()), this, SLOT(slotKeyListJobDone()));
156 connect(m_keylistjob, SIGNAL(nextKey(GpgME::Key)),
157 this, SLOT(slotNextKey(GpgME::Key)));
158 return true;
159}
160
161void VerifyDetachedBodyPartMemento::slotNextKey(const GpgME::Key &key)
162{
163#ifdef DEBUG_SIGNATURE
164 qCDebug(MIMETREEPARSER_LOG) << "tokoe: VerifyDetachedBodyPartMemento::slotNextKey called";
165#endif
166 m_key = key;
167}
168
169void VerifyDetachedBodyPartMemento::slotKeyListJobDone()
170{
171#ifdef DEBUG_SIGNATURE
172 qCDebug(MIMETREEPARSER_LOG) << "tokoe: VerifyDetachedBodyPartMemento::slotKeyListJobDone called";
173#endif
174 m_keylistjob = nullptr;
175 setRunning(false);
176 notify();
177}
diff --git a/framework/src/domain/mimetreeparser/otp/verifydetachedbodypartmemento.h b/framework/src/domain/mimetreeparser/otp/verifydetachedbodypartmemento.h
new file mode 100644
index 00000000..f37dfe81
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/verifydetachedbodypartmemento.h
@@ -0,0 +1,87 @@
1/*
2 Copyright (c) 2014-2016 Montel Laurent <montel@kde.org>
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License, version 2, as
6 published by the Free Software Foundation.
7
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16*/
17
18#ifndef __MIMETREEPARSER_VERIFYDETACHEDBODYPARTMEMENTO_H__
19#define __MIMETREEPARSER_VERIFYDETACHEDBODYPARTMEMENTO_H__
20
21#include "cryptobodypartmemento.h"
22#include <gpgme++/verificationresult.h>
23#include <gpgme++/key.h>
24
25#include <QString>
26#include <QPointer>
27
28#include "bodypart.h"
29
30namespace QGpgME
31{
32class VerifyDetachedJob;
33class KeyListJob;
34}
35
36class QStringList;
37
38namespace MimeTreeParser
39{
40
41class VerifyDetachedBodyPartMemento
42 : public CryptoBodyPartMemento
43{
44 Q_OBJECT
45public:
46 VerifyDetachedBodyPartMemento(QGpgME::VerifyDetachedJob *job,
47 QGpgME::KeyListJob *klj,
48 const QByteArray &signature,
49 const QByteArray &plainText);
50 ~VerifyDetachedBodyPartMemento();
51
52 bool start() Q_DECL_OVERRIDE;
53 void exec() Q_DECL_OVERRIDE;
54
55 const GpgME::VerificationResult &verifyResult() const
56 {
57 return m_vr;
58 }
59 const GpgME::Key &signingKey() const
60 {
61 return m_key;
62 }
63
64private Q_SLOTS:
65 void slotResult(const GpgME::VerificationResult &vr);
66 void slotKeyListJobDone();
67 void slotNextKey(const GpgME::Key &);
68
69private:
70 void saveResult(const GpgME::VerificationResult &);
71 bool canStartKeyListJob() const;
72 QStringList keyListPattern() const;
73 bool startKeyListJob();
74private:
75 // input:
76 const QByteArray m_signature;
77 const QByteArray m_plainText;
78 QPointer<QGpgME::VerifyDetachedJob> m_job;
79 QPointer<QGpgME::KeyListJob> m_keylistjob;
80 // output:
81 GpgME::VerificationResult m_vr;
82 GpgME::Key m_key;
83};
84
85}
86
87#endif // __MIMETREEPARSER_VERIFYDETACHEDBODYPARTMEMENTO_H__
diff --git a/framework/src/domain/mimetreeparser/otp/verifyopaquebodypartmemento.cpp b/framework/src/domain/mimetreeparser/otp/verifyopaquebodypartmemento.cpp
new file mode 100644
index 00000000..99eb8b8e
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/verifyopaquebodypartmemento.cpp
@@ -0,0 +1,179 @@
1/*
2 Copyright (c) 2014-2017 Montel Laurent <montel@kde.org>
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License, version 2, as
6 published by the Free Software Foundation.
7
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16*/
17
18#include "verifyopaquebodypartmemento.h"
19#include "mimetreeparser_debug.h"
20
21#include <QGpgME/VerifyOpaqueJob>
22#include <QGpgME/KeyListJob>
23
24#include <gpgme++/keylistresult.h>
25
26#include <qstringlist.h>
27
28#include <cassert>
29
30using namespace QGpgME;
31using namespace GpgME;
32using namespace MimeTreeParser;
33
34VerifyOpaqueBodyPartMemento::VerifyOpaqueBodyPartMemento(VerifyOpaqueJob *job,
35 KeyListJob *klj,
36 const QByteArray &signature)
37 : CryptoBodyPartMemento(),
38 m_signature(signature),
39 m_job(job),
40 m_keylistjob(klj)
41{
42 assert(m_job);
43}
44
45VerifyOpaqueBodyPartMemento::~VerifyOpaqueBodyPartMemento()
46{
47 if (m_job) {
48 m_job->slotCancel();
49 }
50 if (m_keylistjob) {
51 m_keylistjob->slotCancel();
52 }
53}
54
55bool VerifyOpaqueBodyPartMemento::start()
56{
57 assert(m_job);
58#ifdef DEBUG_SIGNATURE
59 qCDebug(MIMETREEPARSER_LOG) << "tokoe: VerifyOpaqueBodyPartMemento started";
60#endif
61 if (const Error err = m_job->start(m_signature)) {
62 m_vr = VerificationResult(err);
63#ifdef DEBUG_SIGNATURE
64 qCDebug(MIMETREEPARSER_LOG) << "tokoe: VerifyOpaqueBodyPartMemento stopped with error";
65#endif
66 return false;
67 }
68 connect(m_job, SIGNAL(result(GpgME::VerificationResult,QByteArray)),
69 this, SLOT(slotResult(GpgME::VerificationResult,QByteArray)));
70 setRunning(true);
71 return true;
72}
73
74void VerifyOpaqueBodyPartMemento::exec()
75{
76 assert(m_job);
77 setRunning(true);
78 QByteArray plainText;
79#ifdef DEBUG_SIGNATURE
80 qCDebug(MIMETREEPARSER_LOG) << "tokoe: VerifyOpaqueBodyPartMemento execed";
81#endif
82 saveResult(m_job->exec(m_signature, plainText), plainText);
83#ifdef DEBUG_SIGNATURE
84 qCDebug(MIMETREEPARSER_LOG) << "tokoe: VerifyOpaqueBodyPartMemento after execed";
85#endif
86 m_job->deleteLater(); // exec'ed jobs don't delete themselves
87 m_job = nullptr;
88 if (canStartKeyListJob()) {
89 std::vector<GpgME::Key> keys;
90 m_keylistjob->exec(keyListPattern(), /*secretOnly=*/false, keys);
91 if (!keys.empty()) {
92 m_key = keys.back();
93 }
94 }
95 if (m_keylistjob) {
96 m_keylistjob->deleteLater(); // exec'ed jobs don't delete themselves
97 }
98 m_keylistjob = nullptr;
99 setRunning(false);
100}
101
102bool VerifyOpaqueBodyPartMemento::canStartKeyListJob() const
103{
104 if (!m_keylistjob) {
105 return false;
106 }
107 const char *const fpr = m_vr.signature(0).fingerprint();
108 return fpr && *fpr;
109}
110
111QStringList VerifyOpaqueBodyPartMemento::keyListPattern() const
112{
113 assert(canStartKeyListJob());
114 return QStringList(QString::fromLatin1(m_vr.signature(0).fingerprint()));
115}
116
117void VerifyOpaqueBodyPartMemento::saveResult(const VerificationResult &vr,
118 const QByteArray &plainText)
119{
120 assert(m_job);
121#ifdef DEBUG_SIGNATURE
122 qCDebug(MIMETREEPARSER_LOG) << "tokoe: VerifyOpaqueBodyPartMemento::saveResult called";
123#endif
124 m_vr = vr;
125 m_plainText = plainText;
126 setAuditLog(m_job->auditLogError(), m_job->auditLogAsHtml());
127}
128
129void VerifyOpaqueBodyPartMemento::slotResult(const VerificationResult &vr,
130 const QByteArray &plainText)
131{
132#ifdef DEBUG_SIGNATURE
133 qCDebug(MIMETREEPARSER_LOG) << "tokoe: VerifyOpaqueBodyPartMemento::slotResult called";
134#endif
135 saveResult(vr, plainText);
136 m_job = nullptr;
137 if (canStartKeyListJob() && startKeyListJob()) {
138#ifdef DEBUG_SIGNATURE
139 qCDebug(MIMETREEPARSER_LOG) << "tokoe: VerifyOpaqueBodyPartMemento: canStartKeyListJob && startKeyListJob";
140#endif
141 return;
142 }
143 if (m_keylistjob) {
144 m_keylistjob->deleteLater();
145 }
146 m_keylistjob = nullptr;
147 setRunning(false);
148 notify();
149}
150
151bool VerifyOpaqueBodyPartMemento::startKeyListJob()
152{
153 assert(canStartKeyListJob());
154 if (const GpgME::Error err = m_keylistjob->start(keyListPattern())) {
155 return false;
156 }
157 connect(m_keylistjob, SIGNAL(done()), this, SLOT(slotKeyListJobDone()));
158 connect(m_keylistjob, SIGNAL(nextKey(GpgME::Key)),
159 this, SLOT(slotNextKey(GpgME::Key)));
160 return true;
161}
162
163void VerifyOpaqueBodyPartMemento::slotNextKey(const GpgME::Key &key)
164{
165#ifdef DEBUG_SIGNATURE
166 qCDebug(MIMETREEPARSER_LOG) << "tokoe: VerifyOpaqueBodyPartMemento::slotNextKey called";
167#endif
168 m_key = key;
169}
170
171void VerifyOpaqueBodyPartMemento::slotKeyListJobDone()
172{
173#ifdef DEBUG_SIGNATURE
174 qCDebug(MIMETREEPARSER_LOG) << "tokoe: VerifyOpaqueBodyPartMemento::slotKeyListJobDone called";
175#endif
176 m_keylistjob = nullptr;
177 setRunning(false);
178 notify();
179}
diff --git a/framework/src/domain/mimetreeparser/otp/verifyopaquebodypartmemento.h b/framework/src/domain/mimetreeparser/otp/verifyopaquebodypartmemento.h
new file mode 100644
index 00000000..02d30a13
--- /dev/null
+++ b/framework/src/domain/mimetreeparser/otp/verifyopaquebodypartmemento.h
@@ -0,0 +1,93 @@
1/*
2 Copyright (c) 2014-2016 Montel Laurent <montel@kde.org>
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License, version 2, as
6 published by the Free Software Foundation.
7
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16*/
17
18#ifndef __MIMETREEPARSER_VERIFYOPAQUEBODYPARTMEMENTO_H__
19#define __MIMETREEPARSER_VERIFYOPAQUEBODYPARTMEMENTO_H__
20
21#include "cryptobodypartmemento.h"
22#include <gpgme++/verificationresult.h>
23#include <gpgme++/decryptionresult.h>
24#include <gpgme++/key.h>
25
26#include <QString>
27#include <QPointer>
28
29#include "bodypart.h"
30
31namespace QGpgME
32{
33class VerifyOpaqueJob;
34class KeyListJob;
35}
36
37class QStringList;
38
39namespace MimeTreeParser
40{
41
42class VerifyOpaqueBodyPartMemento
43 : public CryptoBodyPartMemento
44{
45 Q_OBJECT
46public:
47 VerifyOpaqueBodyPartMemento(QGpgME::VerifyOpaqueJob *job,
48 QGpgME::KeyListJob *klj,
49 const QByteArray &signature);
50 ~VerifyOpaqueBodyPartMemento();
51
52 bool start() Q_DECL_OVERRIDE;
53 void exec() Q_DECL_OVERRIDE;
54
55 const QByteArray &plainText() const
56 {
57 return m_plainText;
58 }
59 const GpgME::VerificationResult &verifyResult() const
60 {
61 return m_vr;
62 }
63 const GpgME::Key &signingKey() const
64 {
65 return m_key;
66 }
67
68private Q_SLOTS:
69 void slotResult(const GpgME::VerificationResult &vr,
70 const QByteArray &plainText);
71 void slotKeyListJobDone();
72 void slotNextKey(const GpgME::Key &);
73
74private:
75 void saveResult(const GpgME::VerificationResult &,
76 const QByteArray &);
77 bool canStartKeyListJob() const;
78 QStringList keyListPattern() const;
79 bool startKeyListJob();
80private:
81 // input:
82 const QByteArray m_signature;
83 QPointer<QGpgME::VerifyOpaqueJob> m_job;
84 QPointer<QGpgME::KeyListJob> m_keylistjob;
85 // output:
86 GpgME::VerificationResult m_vr;
87 QByteArray m_plainText;
88 GpgME::Key m_key;
89};
90
91}
92
93#endif // __MIMETREEPARSER_VERIFYOPAQUEBODYPARTMEMENTO_H__
diff --git a/framework/src/domain/mimetreeparser/stringhtmlwriter.h b/framework/src/domain/mimetreeparser/stringhtmlwriter.h
index fa5b760e..20f6763e 100644
--- a/framework/src/domain/mimetreeparser/stringhtmlwriter.h
+++ b/framework/src/domain/mimetreeparser/stringhtmlwriter.h
@@ -30,7 +30,7 @@
30#ifndef __KUBE_FRAMEWORK_MAIL_STRINGHTMLWRITER_H__ 30#ifndef __KUBE_FRAMEWORK_MAIL_STRINGHTMLWRITER_H__
31#define __KUBE_FRAMEWORK_MAIL_STRINGHTMLWRITER_H__ 31#define __KUBE_FRAMEWORK_MAIL_STRINGHTMLWRITER_H__
32 32
33#include <MimeTreeParser/HtmlWriter> 33#include <otp/htmlwriter.h>
34 34
35#include <QFile> 35#include <QFile>
36#include <QTextStream> 36#include <QTextStream>
diff --git a/framework/src/domain/mimetreeparser/tests/CMakeLists.txt b/framework/src/domain/mimetreeparser/tests/CMakeLists.txt
index 71afb903..a7f28bb1 100644
--- a/framework/src/domain/mimetreeparser/tests/CMakeLists.txt
+++ b/framework/src/domain/mimetreeparser/tests/CMakeLists.txt
@@ -11,13 +11,13 @@ include(ECMAddTests)
11add_executable(mimetreeparsertest interfacetest.cpp) 11add_executable(mimetreeparsertest interfacetest.cpp)
12add_gpg_crypto_test(mimetreeparsertest mimetreeparsertest) 12add_gpg_crypto_test(mimetreeparsertest mimetreeparsertest)
13qt5_use_modules(mimetreeparsertest Core Test) 13qt5_use_modules(mimetreeparsertest Core Test)
14target_link_libraries(mimetreeparsertest mimetreeparser) 14target_link_libraries(mimetreeparsertest mimetreeparser kube_otp)
15 15
16find_package(Gpgmepp 1.7.1 CONFIG) 16#find_package(Gpgmepp 1.7.1 CONFIG)
17find_package(QGpgme 1.7.1 CONFIG) 17#find_package(QGpgme 1.7.1 CONFIG)
18 18#
19ecm_add_test(gpgerrortest.cpp 19#ecm_add_test(gpgerrortest.cpp
20 TEST_NAME "gpgerrortest" 20# TEST_NAME "gpgerrortest"
21 NAME_PREFIX "mimetreeparser-" 21# NAME_PREFIX "mimetreeparser-"
22 LINK_LIBRARIES Qt5::Core Qt5::Test mimetreeparser Gpgmepp QGpgme 22# LINK_LIBRARIES Qt5::Core Qt5::Test mimetreeparser Gpgmepp QGpgme
23) 23#)
diff --git a/framework/src/domain/objecttreesource.cpp b/framework/src/domain/objecttreesource.cpp
index 567f3516..186fdf80 100644
--- a/framework/src/domain/objecttreesource.cpp
+++ b/framework/src/domain/objecttreesource.cpp
@@ -19,10 +19,10 @@
19 19
20#include "objecttreesource.h" 20#include "objecttreesource.h"
21 21
22#include <MimeTreeParser/AttachmentStrategy> 22#include <otp/attachmentstrategy.h>
23#include <MimeTreeParser/BodyPartFormatterBaseFactory> 23#include <otp/bodypartformatterbasefactory.h>
24#include <MimeTreeParser/MessagePart> 24#include <otp/messagepart.h>
25#include <MimeTreeParser/MessagePartRenderer> 25#include <otp/messagepartrenderer.h>
26 26
27class ObjectSourcePrivate 27class ObjectSourcePrivate
28{ 28{
diff --git a/framework/src/domain/objecttreesource.h b/framework/src/domain/objecttreesource.h
index 93812dc3..2167e06f 100644
--- a/framework/src/domain/objecttreesource.h
+++ b/framework/src/domain/objecttreesource.h
@@ -20,7 +20,7 @@
20#ifndef MAILVIEWER_OBJECTTREEEMPTYSOURCE_H 20#ifndef MAILVIEWER_OBJECTTREEEMPTYSOURCE_H
21#define MAILVIEWER_OBJECTTREEEMPTYSOURCE_H 21#define MAILVIEWER_OBJECTTREEEMPTYSOURCE_H
22 22
23#include <MimeTreeParser/ObjectTreeSource> 23#include <otp/objecttreesource.h>
24 24
25class QString; 25class QString;
26 26
diff --git a/framework/src/domain/stringhtmlwriter.h b/framework/src/domain/stringhtmlwriter.h
index fa5b760e..20f6763e 100644
--- a/framework/src/domain/stringhtmlwriter.h
+++ b/framework/src/domain/stringhtmlwriter.h
@@ -30,7 +30,7 @@
30#ifndef __KUBE_FRAMEWORK_MAIL_STRINGHTMLWRITER_H__ 30#ifndef __KUBE_FRAMEWORK_MAIL_STRINGHTMLWRITER_H__
31#define __KUBE_FRAMEWORK_MAIL_STRINGHTMLWRITER_H__ 31#define __KUBE_FRAMEWORK_MAIL_STRINGHTMLWRITER_H__
32 32
33#include <MimeTreeParser/HtmlWriter> 33#include <otp/htmlwriter.h>
34 34
35#include <QFile> 35#include <QFile>
36#include <QTextStream> 36#include <QTextStream>