diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2017-05-23 19:13:13 +0200 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2017-05-23 19:13:13 +0200 |
commit | b968ea8ed364238c57c3e74cf2c122cb897cfbea (patch) | |
tree | 7a2dca2199906413a2d0b7d075ded0e4d5ffb69f /framework/src | |
parent | c1ca732bafc60f5c140ef5516e32bd46503bf68c (diff) | |
download | kube-b968ea8ed364238c57c3e74cf2c122cb897cfbea.tar.gz kube-b968ea8ed364238c57c3e74cf2c122cb897cfbea.zip |
Builds but doesn't link, no formatters yet
Diffstat (limited to 'framework/src')
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 | ||
2 | find_package(Qt5 COMPONENTS REQUIRED Core Qml) | 2 | find_package(Qt5 COMPONENTS REQUIRED Core Qml) |
3 | find_package(KF5MimeTreeParser "5.1.46" CONFIG REQUIRED) | ||
4 | find_package(KF5Mime "4.87.0" CONFIG REQUIRED) | 3 | find_package(KF5Mime "4.87.0" CONFIG REQUIRED) |
5 | find_package(Sink CONFIG REQUIRED) | 4 | find_package(Sink CONFIG REQUIRED) |
6 | find_package(KAsync CONFIG REQUIRED) | 5 | find_package(KAsync CONFIG REQUIRED) |
@@ -10,7 +9,7 @@ find_package(KF5Package CONFIG REQUIRED) | |||
10 | 9 | ||
11 | add_definitions("-Wall -std=c++0x -g") | 10 | add_definitions("-Wall -std=c++0x -g") |
12 | 11 | ||
13 | include_directories(.) | 12 | include_directories(. domain/mimetreeparser) |
14 | 13 | ||
15 | set(SRCS | 14 | set(SRCS |
16 | frameworkplugin.cpp | 15 | frameworkplugin.cpp |
@@ -45,7 +44,7 @@ set(SRCS | |||
45 | 44 | ||
46 | add_library(frameworkplugin SHARED ${SRCS}) | 45 | add_library(frameworkplugin SHARED ${SRCS}) |
47 | qt5_use_modules(frameworkplugin Core Quick Qml WebEngineWidgets Test) | 46 | qt5_use_modules(frameworkplugin Core Quick Qml WebEngineWidgets Test) |
48 | target_link_libraries(frameworkplugin sink mimetreeparser KF5::MimeTreeParser KF5::Codecs KF5::Package KAsync) | 47 | target_link_libraries(frameworkplugin sink mimetreeparser KF5::Codecs KF5::Package KAsync) |
49 | install(TARGETS frameworkplugin DESTINATION ${FRAMEWORK_INSTALL_DIR}) | 48 | install(TARGETS frameworkplugin DESTINATION ${FRAMEWORK_INSTALL_DIR}) |
50 | 49 | ||
51 | add_subdirectory(domain/mimetreeparser) | 50 | add_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 | ||
42 | namespace KMime { | 42 | namespace 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 @@ | |||
1 | include_directories(.) | ||
2 | |||
1 | set(mimetreeparser_SRCS | 3 | set(mimetreeparser_SRCS |
2 | interface.cpp | 4 | interface.cpp |
3 | objecttreesource.cpp | 5 | objecttreesource.cpp |
@@ -7,9 +9,9 @@ set(mimetreeparser_SRCS | |||
7 | add_library(mimetreeparser SHARED ${mimetreeparser_SRCS}) | 9 | add_library(mimetreeparser SHARED ${mimetreeparser_SRCS}) |
8 | 10 | ||
9 | qt5_use_modules(mimetreeparser Core Gui) | 11 | qt5_use_modules(mimetreeparser Core Gui) |
10 | target_link_libraries(mimetreeparser KF5::Mime KF5::MimeTreeParser) | 12 | target_link_libraries(mimetreeparser KF5::Mime kube_otp) |
11 | 13 | ||
12 | install(TARGETS mimetreeparser | 14 | install(TARGETS mimetreeparser DESTINATION ${LIB_INSTALL_DIR}) |
13 | DESTINATION ${LIB_INSTALL_DIR}) | ||
14 | 15 | ||
15 | add_subdirectory(tests) | 16 | add_subdirectory(tests) |
17 | add_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 | ||
27 | class ObjectSourcePrivate | 27 | class 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 | ||
25 | class QString; | 25 | class 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 @@ | |||
1 | add_definitions( -DQT_NO_CAST_FROM_ASCII ) | ||
2 | add_definitions( -DQT_NO_CAST_TO_ASCII ) | ||
3 | add_definitions("-fvisibility=default") | ||
4 | |||
5 | find_package(Qt5 COMPONENTS REQUIRED Core Gui) | ||
6 | find_package(KF5Mime "4.87.0" CONFIG REQUIRED) | ||
7 | find_package(QGpgme CONFIG REQUIRED) | ||
8 | find_package(KF5Codecs CONFIG REQUIRED) | ||
9 | find_package(KF5Package CONFIG REQUIRED) | ||
10 | find_package(KF5I18n CONFIG REQUIRED) | ||
11 | |||
12 | #add_definitions(-DTRANSLATION_DOMAIN=\"libmimetreeparser\") | ||
13 | |||
14 | # target_include_directories does not handle empty include paths | ||
15 | include_directories(${GPGME_INCLUDES}) | ||
16 | |||
17 | set(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 | |||
145 | set(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 | |||
151 | add_library(kube_otp ${libmimetreeparser_SRCS}) | ||
152 | |||
153 | #generate_export_header(KF5MimeTreeParser BASE_NAME mimetreeparser) | ||
154 | |||
155 | #set(mimetreeparser_LINK_LIBRARIES | ||
156 | # ) | ||
157 | |||
158 | target_link_libraries(kube_otp | ||
159 | PRIVATE | ||
160 | QGpgme | ||
161 | KF5::Codecs | ||
162 | KF5::I18n | ||
163 | KF5::Mime | ||
164 | Qt5::Gui | ||
165 | ) | ||
166 | install(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 | |||
45 | using namespace MimeTreeParser; | ||
46 | |||
47 | static 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 | |||
77 | class IconicAttachmentStrategy : public AttachmentStrategy | ||
78 | { | ||
79 | friend class AttachmentStrategy; | ||
80 | protected: | ||
81 | IconicAttachmentStrategy() : AttachmentStrategy() {} | ||
82 | virtual ~IconicAttachmentStrategy() {} | ||
83 | |||
84 | public: | ||
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 | |||
114 | class SmartAttachmentStrategy : public AttachmentStrategy | ||
115 | { | ||
116 | friend class AttachmentStrategy; | ||
117 | protected: | ||
118 | SmartAttachmentStrategy() : AttachmentStrategy() {} | ||
119 | virtual ~SmartAttachmentStrategy() {} | ||
120 | |||
121 | public: | ||
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 | |||
142 | class InlinedAttachmentStrategy : public AttachmentStrategy | ||
143 | { | ||
144 | friend class AttachmentStrategy; | ||
145 | protected: | ||
146 | InlinedAttachmentStrategy() : AttachmentStrategy() {} | ||
147 | virtual ~InlinedAttachmentStrategy() {} | ||
148 | |||
149 | public: | ||
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 | |||
170 | class HiddenAttachmentStrategy : public AttachmentStrategy | ||
171 | { | ||
172 | friend class AttachmentStrategy; | ||
173 | protected: | ||
174 | HiddenAttachmentStrategy() : AttachmentStrategy() {} | ||
175 | virtual ~HiddenAttachmentStrategy() {} | ||
176 | |||
177 | public: | ||
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 | |||
209 | class HeaderOnlyAttachmentStrategy : public AttachmentStrategy | ||
210 | { | ||
211 | friend class AttachmentStrategy; | ||
212 | protected: | ||
213 | HeaderOnlyAttachmentStrategy() : AttachmentStrategy() {} | ||
214 | virtual ~HeaderOnlyAttachmentStrategy() {} | ||
215 | |||
216 | public: | ||
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 | |||
249 | AttachmentStrategy::AttachmentStrategy() | ||
250 | { | ||
251 | |||
252 | } | ||
253 | |||
254 | AttachmentStrategy::~AttachmentStrategy() | ||
255 | { | ||
256 | |||
257 | } | ||
258 | |||
259 | const 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 | |||
273 | const 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 | |||
294 | static const AttachmentStrategy *iconicStrategy = nullptr; | ||
295 | static const AttachmentStrategy *smartStrategy = nullptr; | ||
296 | static const AttachmentStrategy *inlinedStrategy = nullptr; | ||
297 | static const AttachmentStrategy *hiddenStrategy = nullptr; | ||
298 | static const AttachmentStrategy *headerOnlyStrategy = nullptr; | ||
299 | |||
300 | const AttachmentStrategy *AttachmentStrategy::iconic() | ||
301 | { | ||
302 | if (!iconicStrategy) { | ||
303 | iconicStrategy = new IconicAttachmentStrategy(); | ||
304 | } | ||
305 | return iconicStrategy; | ||
306 | } | ||
307 | |||
308 | const AttachmentStrategy *AttachmentStrategy::smart() | ||
309 | { | ||
310 | if (!smartStrategy) { | ||
311 | smartStrategy = new SmartAttachmentStrategy(); | ||
312 | } | ||
313 | return smartStrategy; | ||
314 | } | ||
315 | |||
316 | const AttachmentStrategy *AttachmentStrategy::inlined() | ||
317 | { | ||
318 | if (!inlinedStrategy) { | ||
319 | inlinedStrategy = new InlinedAttachmentStrategy(); | ||
320 | } | ||
321 | return inlinedStrategy; | ||
322 | } | ||
323 | |||
324 | const AttachmentStrategy *AttachmentStrategy::hidden() | ||
325 | { | ||
326 | if (!hiddenStrategy) { | ||
327 | hiddenStrategy = new HiddenAttachmentStrategy(); | ||
328 | } | ||
329 | return hiddenStrategy; | ||
330 | } | ||
331 | |||
332 | const AttachmentStrategy *AttachmentStrategy::headerOnly() | ||
333 | { | ||
334 | if (!headerOnlyStrategy) { | ||
335 | headerOnlyStrategy = new HeaderOnlyAttachmentStrategy(); | ||
336 | } | ||
337 | return headerOnlyStrategy; | ||
338 | } | ||
339 | |||
340 | bool 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 | |||
37 | class QString; | ||
38 | namespace KMime | ||
39 | { | ||
40 | class Content; | ||
41 | } | ||
42 | |||
43 | namespace MimeTreeParser | ||
44 | { | ||
45 | |||
46 | class AttachmentStrategy | ||
47 | { | ||
48 | protected: | ||
49 | AttachmentStrategy(); | ||
50 | virtual ~AttachmentStrategy(); | ||
51 | |||
52 | public: | ||
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 | |||
27 | using namespace MimeTreeParser; | ||
28 | |||
29 | class MimeTreeParser::AttachmentTemporaryFilesDirsPrivate | ||
30 | { | ||
31 | public: | ||
32 | AttachmentTemporaryFilesDirsPrivate() | ||
33 | : mDelayRemoveAll(10000) | ||
34 | { | ||
35 | |||
36 | } | ||
37 | QStringList mTempFiles; | ||
38 | QStringList mTempDirs; | ||
39 | int mDelayRemoveAll; | ||
40 | }; | ||
41 | |||
42 | AttachmentTemporaryFilesDirs::AttachmentTemporaryFilesDirs(QObject *parent) | ||
43 | : QObject(parent), | ||
44 | d(new AttachmentTemporaryFilesDirsPrivate) | ||
45 | { | ||
46 | |||
47 | } | ||
48 | |||
49 | AttachmentTemporaryFilesDirs::~AttachmentTemporaryFilesDirs() | ||
50 | { | ||
51 | delete d; | ||
52 | } | ||
53 | |||
54 | void AttachmentTemporaryFilesDirs::setDelayRemoveAllInMs(int ms) | ||
55 | { | ||
56 | d->mDelayRemoveAll = (ms < 0) ? 0 : ms; | ||
57 | } | ||
58 | |||
59 | void AttachmentTemporaryFilesDirs::removeTempFiles() | ||
60 | { | ||
61 | QTimer::singleShot(d->mDelayRemoveAll, this, &AttachmentTemporaryFilesDirs::slotRemoveTempFiles); | ||
62 | } | ||
63 | |||
64 | void 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 | |||
78 | void AttachmentTemporaryFilesDirs::slotRemoveTempFiles() | ||
79 | { | ||
80 | forceCleanTempFiles(); | ||
81 | //Delete it after cleaning | ||
82 | deleteLater(); | ||
83 | } | ||
84 | |||
85 | void AttachmentTemporaryFilesDirs::addTempFile(const QString &file) | ||
86 | { | ||
87 | if (!d->mTempFiles.contains(file)) { | ||
88 | d->mTempFiles.append(file); | ||
89 | } | ||
90 | } | ||
91 | |||
92 | void AttachmentTemporaryFilesDirs::addTempDir(const QString &dir) | ||
93 | { | ||
94 | if (!d->mTempDirs.contains(dir)) { | ||
95 | d->mTempDirs.append(dir); | ||
96 | } | ||
97 | } | ||
98 | |||
99 | QStringList AttachmentTemporaryFilesDirs::temporaryFiles() const | ||
100 | { | ||
101 | return d->mTempFiles; | ||
102 | } | ||
103 | |||
104 | QStringList 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 | |||
27 | namespace MimeTreeParser | ||
28 | { | ||
29 | class AttachmentTemporaryFilesDirsPrivate; | ||
30 | |||
31 | class AttachmentTemporaryFilesDirs : public QObject | ||
32 | { | ||
33 | Q_OBJECT | ||
34 | public: | ||
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 | |||
48 | private Q_SLOTS: | ||
49 | void slotRemoveTempFiles(); | ||
50 | |||
51 | private: | ||
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 | |||
34 | MimeTreeParser::Interface::BodyPartMemento::~BodyPartMemento() | ||
35 | { | ||
36 | } | ||
37 | |||
38 | MimeTreeParser::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 | |||
40 | namespace KMime | ||
41 | { | ||
42 | class Content; | ||
43 | } | ||
44 | |||
45 | namespace MimeTreeParser | ||
46 | { | ||
47 | class NodeHelper; | ||
48 | class ObjectTreeParser; | ||
49 | class ProcessResult; | ||
50 | |||
51 | namespace Interface | ||
52 | { | ||
53 | |||
54 | class 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 | */ | ||
63 | class BodyPartMemento | ||
64 | { | ||
65 | public: | ||
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 | */ | ||
92 | class BodyPart | ||
93 | { | ||
94 | public: | ||
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 | |||
39 | using namespace MimeTreeParser::Interface; | ||
40 | |||
41 | namespace MimeTreeParser | ||
42 | { | ||
43 | namespace Interface | ||
44 | { | ||
45 | |||
46 | class MessagePartPrivate | ||
47 | { | ||
48 | public: | ||
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 | |||
81 | MessagePart::MessagePart() | ||
82 | : QObject() | ||
83 | , d(new MessagePartPrivate(nullptr)) | ||
84 | { | ||
85 | } | ||
86 | |||
87 | MessagePart::MessagePart(const BodyPart &part) | ||
88 | : QObject() | ||
89 | , d(new MessagePartPrivate(&part)) | ||
90 | { | ||
91 | } | ||
92 | |||
93 | MessagePart::~MessagePart() | ||
94 | { | ||
95 | delete d; | ||
96 | } | ||
97 | |||
98 | void MessagePart::html(bool decorate) | ||
99 | { | ||
100 | Q_UNUSED(decorate); | ||
101 | static_cast<QueueHtmlWriter *>(d->mHtmlWriter)->replay(); | ||
102 | } | ||
103 | |||
104 | QString MessagePart::text() const | ||
105 | { | ||
106 | return QString(); | ||
107 | } | ||
108 | |||
109 | MessagePart *MessagePart::parentPart() const | ||
110 | { | ||
111 | return d->mParentPart; | ||
112 | } | ||
113 | |||
114 | void MessagePart::setParentPart(MessagePart *parentPart) | ||
115 | { | ||
116 | d->mParentPart = parentPart; | ||
117 | } | ||
118 | |||
119 | QString MessagePart::htmlContent() const | ||
120 | { | ||
121 | return text(); | ||
122 | } | ||
123 | |||
124 | QString MessagePart::plaintextContent() const | ||
125 | { | ||
126 | return text(); | ||
127 | } | ||
128 | |||
129 | MimeTreeParser::HtmlWriter *MessagePart::htmlWriter() const | ||
130 | { | ||
131 | return d->htmlWriter(); | ||
132 | } | ||
133 | |||
134 | void MessagePart::setHtmlWriter(MimeTreeParser::HtmlWriter *htmlWriter) const | ||
135 | { | ||
136 | if (d->mHtmlWriter) { | ||
137 | d->mHtmlWriter = htmlWriter; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | MessagePart::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 | |||
42 | namespace MimeTreeParser | ||
43 | { | ||
44 | class HtmlWriter; | ||
45 | |||
46 | namespace Interface | ||
47 | { | ||
48 | |||
49 | class BodyPartURLHandler; | ||
50 | class BodyPart; | ||
51 | class MessagePartPrivate; | ||
52 | |||
53 | class MessagePart : public QObject | ||
54 | { | ||
55 | Q_OBJECT | ||
56 | Q_PROPERTY(QString plaintextContent READ plaintextContent) | ||
57 | Q_PROPERTY(QString htmlContent READ htmlContent) | ||
58 | public: | ||
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; | ||
75 | private: | ||
76 | MessagePartPrivate *d; | ||
77 | |||
78 | friend class BodyPartFormatter; | ||
79 | }; | ||
80 | |||
81 | class BodyPartFormatter | ||
82 | { | ||
83 | public: | ||
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 | */ | ||
134 | class BodyPartFormatterPlugin | ||
135 | { | ||
136 | public: | ||
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 | |||
42 | using namespace MimeTreeParser; | ||
43 | |||
44 | BodyPartFormatterBaseFactoryPrivate::BodyPartFormatterBaseFactoryPrivate(BodyPartFormatterBaseFactory *factory) | ||
45 | : q(factory) | ||
46 | , all(nullptr) | ||
47 | { | ||
48 | } | ||
49 | |||
50 | BodyPartFormatterBaseFactoryPrivate::~BodyPartFormatterBaseFactoryPrivate() | ||
51 | { | ||
52 | if (all) { | ||
53 | delete all; | ||
54 | all = nullptr; | ||
55 | } | ||
56 | } | ||
57 | |||
58 | void BodyPartFormatterBaseFactoryPrivate::setup() | ||
59 | { | ||
60 | if (!all) { | ||
61 | all = new TypeRegistry(); | ||
62 | messageviewer_create_builtin_bodypart_formatters(); | ||
63 | q->loadPlugins(); | ||
64 | } | ||
65 | } | ||
66 | |||
67 | void 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 | |||
86 | void 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 | |||
115 | BodyPartFormatterBaseFactory::BodyPartFormatterBaseFactory() | ||
116 | : d(new BodyPartFormatterBaseFactoryPrivate(this)) | ||
117 | { | ||
118 | } | ||
119 | |||
120 | BodyPartFormatterBaseFactory::~BodyPartFormatterBaseFactory() | ||
121 | { | ||
122 | delete d; | ||
123 | } | ||
124 | |||
125 | void BodyPartFormatterBaseFactory::insert(const char *type, const char *subtype, const Interface::BodyPartFormatter *formatter) | ||
126 | { | ||
127 | d->insert(type, subtype, formatter); | ||
128 | } | ||
129 | |||
130 | const 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 | |||
159 | SubtypeRegistry::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 | |||
205 | void 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 | |||
40 | namespace MimeTreeParser | ||
41 | { | ||
42 | |||
43 | namespace Interface | ||
44 | { | ||
45 | class BodyPartFormatter; | ||
46 | } | ||
47 | |||
48 | struct ltstr { | ||
49 | bool operator()(const char *s1, const char *s2) const | ||
50 | { | ||
51 | return qstricmp(s1, s2) < 0; | ||
52 | } | ||
53 | }; | ||
54 | |||
55 | typedef std::multimap<const char *, const Interface::BodyPartFormatter *, ltstr> SubtypeRegistry; | ||
56 | typedef std::map<const char *, MimeTreeParser::SubtypeRegistry, MimeTreeParser::ltstr> TypeRegistry; | ||
57 | |||
58 | class BodyPartFormatterBaseFactoryPrivate; | ||
59 | |||
60 | class BodyPartFormatterBaseFactory | ||
61 | { | ||
62 | public: | ||
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 | |||
69 | protected: | ||
70 | void insert(const char *type, const char *subtype, const Interface::BodyPartFormatter *formatter); | ||
71 | virtual void loadPlugins(); | ||
72 | private: | ||
73 | static BodyPartFormatterBaseFactory *mSelf; | ||
74 | |||
75 | BodyPartFormatterBaseFactoryPrivate *d; | ||
76 | friend class BodyPartFormatterBaseFactoryPrivate; | ||
77 | private: | ||
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 | |||
37 | namespace MimeTreeParser | ||
38 | { | ||
39 | class BodyPartFormatterBaseFactory; | ||
40 | |||
41 | class BodyPartFormatterBaseFactoryPrivate | ||
42 | { | ||
43 | public: | ||
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 | |||
20 | using namespace GpgME; | ||
21 | using namespace MimeTreeParser; | ||
22 | |||
23 | CryptoBodyPartMemento::CryptoBodyPartMemento() | ||
24 | : QObject(nullptr), | ||
25 | Interface::BodyPartMemento(), | ||
26 | m_running(false) | ||
27 | { | ||
28 | |||
29 | } | ||
30 | |||
31 | CryptoBodyPartMemento::~CryptoBodyPartMemento() | ||
32 | { | ||
33 | |||
34 | } | ||
35 | |||
36 | bool CryptoBodyPartMemento::isRunning() const | ||
37 | { | ||
38 | return m_running; | ||
39 | } | ||
40 | |||
41 | void CryptoBodyPartMemento::setAuditLog(const Error &err, const QString &log) | ||
42 | { | ||
43 | m_auditLogError = err; | ||
44 | m_auditLog = log; | ||
45 | } | ||
46 | |||
47 | void CryptoBodyPartMemento::setRunning(bool running) | ||
48 | { | ||
49 | m_running = running; | ||
50 | } | ||
51 | |||
52 | void 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 | |||
29 | namespace MimeTreeParser | ||
30 | { | ||
31 | |||
32 | class CryptoBodyPartMemento | ||
33 | : public QObject, | ||
34 | public Interface::BodyPartMemento | ||
35 | { | ||
36 | Q_OBJECT | ||
37 | public: | ||
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 | |||
56 | Q_SIGNALS: | ||
57 | void update(MimeTreeParser::UpdateMode); | ||
58 | |||
59 | protected Q_SLOTS: | ||
60 | void notify() | ||
61 | { | ||
62 | Q_EMIT update(MimeTreeParser::Force); | ||
63 | } | ||
64 | |||
65 | protected: | ||
66 | void setAuditLog(const GpgME::Error &err, const QString &log); | ||
67 | void setRunning(bool running); | ||
68 | |||
69 | private: | ||
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 | |||
18 | using namespace MimeTreeParser; | ||
19 | |||
20 | PGPBlockType 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 | |||
47 | QList<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 | |||
129 | Block::Block(const QByteArray &m) | ||
130 | : msg(m) | ||
131 | { | ||
132 | mType = determineType(); | ||
133 | } | ||
134 | |||
135 | Block::Block(const QByteArray &m, PGPBlockType t) | ||
136 | : msg(m) | ||
137 | , mType(t) | ||
138 | { | ||
139 | |||
140 | } | ||
141 | |||
142 | QByteArray MimeTreeParser::Block::text() const | ||
143 | { | ||
144 | return msg; | ||
145 | } | ||
146 | |||
147 | PGPBlockType 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 | |||
24 | namespace MimeTreeParser | ||
25 | { | ||
26 | |||
27 | enum 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 | |||
38 | class Block | ||
39 | { | ||
40 | public: | ||
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 | */ | ||
56 | QList<Block> prepareMessageForDecryption(const QByteArray &msg); | ||
57 | |||
58 | } // namespace MimeTreeParser | ||
59 | |||
60 | Q_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 | |||
24 | using namespace QGpgME; | ||
25 | using namespace GpgME; | ||
26 | using namespace MimeTreeParser; | ||
27 | |||
28 | DecryptVerifyBodyPartMemento::DecryptVerifyBodyPartMemento(DecryptVerifyJob *job, const QByteArray &cipherText) | ||
29 | : CryptoBodyPartMemento(), | ||
30 | m_cipherText(cipherText), | ||
31 | m_job(job) | ||
32 | { | ||
33 | Q_ASSERT(m_job); | ||
34 | } | ||
35 | |||
36 | DecryptVerifyBodyPartMemento::~DecryptVerifyBodyPartMemento() | ||
37 | { | ||
38 | if (m_job) { | ||
39 | m_job->slotCancel(); | ||
40 | } | ||
41 | } | ||
42 | |||
43 | bool 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 | |||
56 | void 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 | |||
67 | void 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 | |||
79 | void 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 | |||
30 | namespace QGpgME | ||
31 | { | ||
32 | class DecryptVerifyJob; | ||
33 | } | ||
34 | |||
35 | namespace MimeTreeParser | ||
36 | { | ||
37 | |||
38 | class DecryptVerifyBodyPartMemento | ||
39 | : public CryptoBodyPartMemento | ||
40 | { | ||
41 | Q_OBJECT | ||
42 | public: | ||
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 | |||
62 | private Q_SLOTS: | ||
63 | void slotResult(const GpgME::DecryptionResult &dr, | ||
64 | const GpgME::VerificationResult &vr, | ||
65 | const QByteArray &plainText); | ||
66 | |||
67 | private: | ||
68 | void saveResult(const GpgME::DecryptionResult &, | ||
69 | const GpgME::VerificationResult &, | ||
70 | const QByteArray &); | ||
71 | private: | ||
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 | |||
22 | namespace MimeTreeParser | ||
23 | { | ||
24 | |||
25 | /** | ||
26 | * The display update mode: Force updates the display immediately, Delayed updates | ||
27 | * after some time (150ms by default) | ||
28 | */ | ||
29 | enum UpdateMode { | ||
30 | Force = 0, | ||
31 | Delayed | ||
32 | }; | ||
33 | |||
34 | /** Flags for the encryption state. */ | ||
35 | typedef enum { | ||
36 | KMMsgEncryptionStateUnknown = ' ', | ||
37 | KMMsgNotEncrypted = 'N', | ||
38 | KMMsgPartiallyEncrypted = 'P', | ||
39 | KMMsgFullyEncrypted = 'F', | ||
40 | KMMsgEncryptionProblematic = 'X' | ||
41 | } KMMsgEncryptionState; | ||
42 | |||
43 | /** Flags for the signature state. */ | ||
44 | typedef 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 | |||
36 | namespace MimeTreeParser | ||
37 | { | ||
38 | |||
39 | FileHtmlWriter::FileHtmlWriter(const QString &filename) | ||
40 | : HtmlWriter(), | ||
41 | mFile(filename.isEmpty() ? QStringLiteral("filehtmlwriter.out") : filename) | ||
42 | { | ||
43 | } | ||
44 | |||
45 | FileHtmlWriter::~FileHtmlWriter() | ||
46 | { | ||
47 | if (mFile.isOpen()) { | ||
48 | qCWarning(MIMETREEPARSER_LOG) << "FileHtmlWriter: file still open!"; | ||
49 | mStream.setDevice(nullptr); | ||
50 | mFile.close(); | ||
51 | } | ||
52 | } | ||
53 | |||
54 | void FileHtmlWriter::begin(const QString &css) | ||
55 | { | ||
56 | openOrWarn(); | ||
57 | if (!css.isEmpty()) { | ||
58 | write(QLatin1String("<!-- CSS Definitions \n") + css + QLatin1String("-->\n")); | ||
59 | } | ||
60 | } | ||
61 | |||
62 | void FileHtmlWriter::end() | ||
63 | { | ||
64 | flush(); | ||
65 | mStream.setDevice(nullptr); | ||
66 | mFile.close(); | ||
67 | } | ||
68 | |||
69 | void FileHtmlWriter::reset() | ||
70 | { | ||
71 | if (mFile.isOpen()) { | ||
72 | mStream.setDevice(nullptr); | ||
73 | mFile.close(); | ||
74 | } | ||
75 | } | ||
76 | |||
77 | void FileHtmlWriter::write(const QString &str) | ||
78 | { | ||
79 | mStream << str; | ||
80 | flush(); | ||
81 | } | ||
82 | |||
83 | void FileHtmlWriter::queue(const QString &str) | ||
84 | { | ||
85 | write(str); | ||
86 | } | ||
87 | |||
88 | void FileHtmlWriter::flush() | ||
89 | { | ||
90 | mStream.flush(); | ||
91 | mFile.flush(); | ||
92 | } | ||
93 | |||
94 | void 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 | |||
109 | void FileHtmlWriter::embedPart(const QByteArray &contentId, const QString &url) | ||
110 | { | ||
111 | mStream << "<!-- embedPart(contentID=" << contentId << ", url=" << url << ") -->" << endl; | ||
112 | flush(); | ||
113 | } | ||
114 | void 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 | |||
41 | class QString; | ||
42 | |||
43 | namespace MimeTreeParser | ||
44 | { | ||
45 | |||
46 | class MIMETREEPARSER_EXPORT FileHtmlWriter : public HtmlWriter | ||
47 | { | ||
48 | public: | ||
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; | ||
60 | private: | ||
61 | void openOrWarn(); | ||
62 | |||
63 | private: | ||
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 | |||
33 | MimeTreeParser::Interface::HtmlWriter::~HtmlWriter() | ||
34 | { | ||
35 | } | ||
36 | |||
37 | MimeTreeParser::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 | |||
36 | class QByteArray; | ||
37 | class QString; | ||
38 | |||
39 | namespace MimeTreeParser | ||
40 | { | ||
41 | /** | ||
42 | * @short An interface for HTML sinks. | ||
43 | * @author Marc Mutz <mutz@kde.org> | ||
44 | * | ||
45 | */ | ||
46 | namespace Interface | ||
47 | { | ||
48 | class HtmlWriter | ||
49 | { | ||
50 | public: | ||
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 | */ | ||
101 | class HtmlWriter : public Interface::HtmlWriter | ||
102 | { | ||
103 | public: | ||
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 | |||
52 | using namespace MimeTreeParser; | ||
53 | |||
54 | //------MessagePart----------------------- | ||
55 | MessagePart::MessagePart(ObjectTreeParser *otp, | ||
56 | const QString &text) | ||
57 | : mText(text) | ||
58 | , mOtp(otp) | ||
59 | , mAttachmentNode(nullptr) | ||
60 | , mRoot(false) | ||
61 | { | ||
62 | } | ||
63 | |||
64 | MessagePart::~MessagePart() | ||
65 | { | ||
66 | } | ||
67 | |||
68 | PartMetaData *MessagePart::partMetaData() | ||
69 | { | ||
70 | return &mMetaData; | ||
71 | } | ||
72 | |||
73 | void MessagePart::setAttachmentFlag(KMime::Content *node) | ||
74 | { | ||
75 | mAttachmentNode = node; | ||
76 | } | ||
77 | |||
78 | bool MessagePart::isAttachment() const | ||
79 | { | ||
80 | return mAttachmentNode; | ||
81 | } | ||
82 | |||
83 | KMime::Content *MessagePart::attachmentNode() const | ||
84 | { | ||
85 | return mAttachmentNode; | ||
86 | } | ||
87 | |||
88 | void MessagePart::setIsRoot(bool root) | ||
89 | { | ||
90 | mRoot = root; | ||
91 | } | ||
92 | |||
93 | bool MessagePart::isRoot() const | ||
94 | { | ||
95 | return mRoot; | ||
96 | } | ||
97 | |||
98 | QString MessagePart::text() const | ||
99 | { | ||
100 | return mText; | ||
101 | } | ||
102 | |||
103 | void MessagePart::setText(const QString &text) | ||
104 | { | ||
105 | mText = text; | ||
106 | } | ||
107 | |||
108 | bool MessagePart::isHtml() const | ||
109 | { | ||
110 | return false; | ||
111 | } | ||
112 | |||
113 | bool MessagePart::isHidden() const | ||
114 | { | ||
115 | return false; | ||
116 | } | ||
117 | |||
118 | Interface::ObjectTreeSource *MessagePart::source() const | ||
119 | { | ||
120 | Q_ASSERT(mOtp); | ||
121 | return mOtp->mSource; | ||
122 | } | ||
123 | |||
124 | HtmlWriter *MessagePart::htmlWriter() const | ||
125 | { | ||
126 | Q_ASSERT(mOtp); | ||
127 | return mOtp->htmlWriter(); | ||
128 | } | ||
129 | |||
130 | void MessagePart::setHtmlWriter(HtmlWriter *htmlWriter) const | ||
131 | { | ||
132 | mOtp->mHtmlWriter = htmlWriter; | ||
133 | } | ||
134 | |||
135 | void 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 | |||
144 | QString MessagePart::renderInternalText() const | ||
145 | { | ||
146 | QString text; | ||
147 | foreach (const auto &mp, subParts()) { | ||
148 | text += mp->text(); | ||
149 | } | ||
150 | return text; | ||
151 | } | ||
152 | |||
153 | void 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 | |||
163 | void 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 | |||
173 | void MessagePart::appendSubPart(const Interface::MessagePart::Ptr &messagePart) | ||
174 | { | ||
175 | messagePart->setParentPart(this); | ||
176 | mBlocks.append(messagePart); | ||
177 | } | ||
178 | |||
179 | const QVector<Interface::MessagePart::Ptr> &MessagePart::subParts() const | ||
180 | { | ||
181 | return mBlocks; | ||
182 | } | ||
183 | |||
184 | bool MessagePart::hasSubParts() const | ||
185 | { | ||
186 | return !mBlocks.isEmpty(); | ||
187 | } | ||
188 | |||
189 | //-----MessagePartList---------------------- | ||
190 | MessagePartList::MessagePartList(ObjectTreeParser *otp) | ||
191 | : MessagePart(otp, QString()) | ||
192 | { | ||
193 | } | ||
194 | |||
195 | MessagePartList::~MessagePartList() | ||
196 | { | ||
197 | |||
198 | } | ||
199 | |||
200 | QString MessagePartList::text() const | ||
201 | { | ||
202 | return renderInternalText(); | ||
203 | } | ||
204 | |||
205 | QString MessagePartList::plaintextContent() const | ||
206 | { | ||
207 | return QString(); | ||
208 | } | ||
209 | |||
210 | QString MessagePartList::htmlContent() const | ||
211 | { | ||
212 | return QString(); | ||
213 | } | ||
214 | |||
215 | //-----TextMessageBlock---------------------- | ||
216 | |||
217 | TextMessagePart::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 | |||
235 | TextMessagePart::~TextMessagePart() | ||
236 | { | ||
237 | |||
238 | } | ||
239 | |||
240 | bool TextMessagePart::decryptMessage() const | ||
241 | { | ||
242 | return mDecryptMessage; | ||
243 | } | ||
244 | |||
245 | void 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 | |||
324 | KMMsgEncryptionState TextMessagePart::encryptionState() const | ||
325 | { | ||
326 | return mEncryptionState; | ||
327 | } | ||
328 | |||
329 | KMMsgSignatureState TextMessagePart::signatureState() const | ||
330 | { | ||
331 | return mSignatureState; | ||
332 | } | ||
333 | |||
334 | bool TextMessagePart::isHidden() const | ||
335 | { | ||
336 | return mIsHidden; | ||
337 | } | ||
338 | |||
339 | bool TextMessagePart::showLink() const | ||
340 | { | ||
341 | return mShowLink; | ||
342 | } | ||
343 | |||
344 | bool TextMessagePart::showTextFrame() const | ||
345 | { | ||
346 | return mDrawFrame; | ||
347 | } | ||
348 | |||
349 | //-----AttachmentMessageBlock---------------------- | ||
350 | |||
351 | AttachmentMessagePart::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 | |||
359 | AttachmentMessagePart::~AttachmentMessagePart() | ||
360 | { | ||
361 | |||
362 | } | ||
363 | |||
364 | bool AttachmentMessagePart::neverDisplayInline() const | ||
365 | { | ||
366 | return mNeverDisplayInline; | ||
367 | } | ||
368 | |||
369 | void AttachmentMessagePart::setNeverDisplayInline(bool displayInline) | ||
370 | { | ||
371 | mNeverDisplayInline = displayInline; | ||
372 | } | ||
373 | |||
374 | bool AttachmentMessagePart::isImage() const | ||
375 | { | ||
376 | return mIsImage; | ||
377 | } | ||
378 | |||
379 | void AttachmentMessagePart::setIsImage(bool image) | ||
380 | { | ||
381 | mIsImage = image; | ||
382 | } | ||
383 | |||
384 | IconType 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 | |||
441 | bool 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 | |||
491 | HtmlMessagePart::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 | |||
506 | HtmlMessagePart::~HtmlMessagePart() | ||
507 | { | ||
508 | } | ||
509 | |||
510 | void HtmlMessagePart::fix() const | ||
511 | { | ||
512 | mOtp->mHtmlContent += mBodyHTML; | ||
513 | mOtp->mHtmlContentCharset = mCharset; | ||
514 | } | ||
515 | |||
516 | QString HtmlMessagePart::text() const | ||
517 | { | ||
518 | return mBodyHTML; | ||
519 | } | ||
520 | |||
521 | bool HtmlMessagePart::isHtml() const | ||
522 | { | ||
523 | return true; | ||
524 | } | ||
525 | |||
526 | //-----MimeMessageBlock---------------------- | ||
527 | |||
528 | MimeMessagePart::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 | |||
541 | MimeMessagePart::~MimeMessagePart() | ||
542 | { | ||
543 | |||
544 | } | ||
545 | |||
546 | QString MimeMessagePart::text() const | ||
547 | { | ||
548 | return renderInternalText(); | ||
549 | } | ||
550 | |||
551 | QString MimeMessagePart::plaintextContent() const | ||
552 | { | ||
553 | return QString(); | ||
554 | } | ||
555 | |||
556 | QString MimeMessagePart::htmlContent() const | ||
557 | { | ||
558 | return QString(); | ||
559 | } | ||
560 | |||
561 | //-----AlternativeMessagePart---------------------- | ||
562 | |||
563 | AlternativeMessagePart::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 | |||
613 | AlternativeMessagePart::~AlternativeMessagePart() | ||
614 | { | ||
615 | |||
616 | } | ||
617 | |||
618 | Util::HtmlMode AlternativeMessagePart::preferredMode() const | ||
619 | { | ||
620 | return mPreferredMode; | ||
621 | } | ||
622 | |||
623 | QList<Util::HtmlMode> AlternativeMessagePart::availableModes() | ||
624 | { | ||
625 | return mChildParts.keys(); | ||
626 | } | ||
627 | |||
628 | QString AlternativeMessagePart::text() const | ||
629 | { | ||
630 | if (mChildParts.contains(Util::MultipartPlain)) { | ||
631 | return mChildParts[Util::MultipartPlain]->text(); | ||
632 | } | ||
633 | return QString(); | ||
634 | } | ||
635 | |||
636 | void 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 | |||
648 | void 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 | |||
660 | bool AlternativeMessagePart::isHtml() const | ||
661 | { | ||
662 | return mChildParts.contains(Util::MultipartHtml); | ||
663 | } | ||
664 | |||
665 | QString AlternativeMessagePart::plaintextContent() const | ||
666 | { | ||
667 | return text(); | ||
668 | } | ||
669 | |||
670 | QString 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 | |||
681 | CertMessagePart::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 | |||
703 | CertMessagePart::~CertMessagePart() | ||
704 | { | ||
705 | |||
706 | } | ||
707 | |||
708 | QString CertMessagePart::text() const | ||
709 | { | ||
710 | return QString(); | ||
711 | } | ||
712 | |||
713 | //-----SignedMessageBlock--------------------- | ||
714 | SignedMessagePart::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 | |||
732 | SignedMessagePart::~SignedMessagePart() | ||
733 | { | ||
734 | |||
735 | } | ||
736 | |||
737 | void SignedMessagePart::setIsSigned(bool isSigned) | ||
738 | { | ||
739 | mMetaData.isSigned = isSigned; | ||
740 | } | ||
741 | |||
742 | bool SignedMessagePart::isSigned() const | ||
743 | { | ||
744 | return mMetaData.isSigned; | ||
745 | } | ||
746 | |||
747 | bool 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 | |||
837 | static 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 | |||
857 | QString prettifyDN(const char *uid) | ||
858 | { | ||
859 | return QGpgME::DN(uid).prettyDN(); | ||
860 | } | ||
861 | |||
862 | void 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 | |||
945 | void 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 | |||
954 | void 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 | |||
970 | void 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 | |||
1020 | QString SignedMessagePart::plaintextContent() const | ||
1021 | { | ||
1022 | if (!mNode) { | ||
1023 | return MessagePart::text(); | ||
1024 | } else { | ||
1025 | return QString(); | ||
1026 | } | ||
1027 | } | ||
1028 | |||
1029 | QString SignedMessagePart::htmlContent() const | ||
1030 | { | ||
1031 | if (!mNode) { | ||
1032 | return MessagePart::text(); | ||
1033 | } else { | ||
1034 | return QString(); | ||
1035 | } | ||
1036 | } | ||
1037 | |||
1038 | //-----CryptMessageBlock--------------------- | ||
1039 | EncryptedMessagePart::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 | |||
1062 | EncryptedMessagePart::~EncryptedMessagePart() | ||
1063 | { | ||
1064 | |||
1065 | } | ||
1066 | |||
1067 | void EncryptedMessagePart::setDecryptMessage(bool decrypt) | ||
1068 | { | ||
1069 | mDecryptMessage = decrypt; | ||
1070 | } | ||
1071 | |||
1072 | bool EncryptedMessagePart::decryptMessage() const | ||
1073 | { | ||
1074 | return mDecryptMessage; | ||
1075 | } | ||
1076 | |||
1077 | void EncryptedMessagePart::setIsEncrypted(bool encrypted) | ||
1078 | { | ||
1079 | mMetaData.isEncrypted = encrypted; | ||
1080 | } | ||
1081 | |||
1082 | bool EncryptedMessagePart::isEncrypted() const | ||
1083 | { | ||
1084 | return mMetaData.isEncrypted; | ||
1085 | } | ||
1086 | |||
1087 | bool EncryptedMessagePart::isDecryptable() const | ||
1088 | { | ||
1089 | return mMetaData.isDecryptable; | ||
1090 | } | ||
1091 | |||
1092 | bool EncryptedMessagePart::passphraseError() const | ||
1093 | { | ||
1094 | return mPassphraseError; | ||
1095 | } | ||
1096 | |||
1097 | void 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 | |||
1119 | bool 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 | |||
1235 | void 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 | |||
1280 | QString EncryptedMessagePart::plaintextContent() const | ||
1281 | { | ||
1282 | if (!mNode) { | ||
1283 | return MessagePart::text(); | ||
1284 | } else { | ||
1285 | return QString(); | ||
1286 | } | ||
1287 | } | ||
1288 | |||
1289 | QString EncryptedMessagePart::htmlContent() const | ||
1290 | { | ||
1291 | if (!mNode) { | ||
1292 | return MessagePart::text(); | ||
1293 | } else { | ||
1294 | return QString(); | ||
1295 | } | ||
1296 | } | ||
1297 | |||
1298 | QString 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 | |||
1312 | EncapsulatedRfc822MessagePart::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 | |||
1336 | EncapsulatedRfc822MessagePart::~EncapsulatedRfc822MessagePart() | ||
1337 | { | ||
1338 | |||
1339 | } | ||
1340 | |||
1341 | QString EncapsulatedRfc822MessagePart::text() const | ||
1342 | { | ||
1343 | return renderInternalText(); | ||
1344 | } | ||
1345 | |||
1346 | void EncapsulatedRfc822MessagePart::copyContentFrom() const | ||
1347 | { | ||
1348 | } | ||
1349 | |||
1350 | void 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 | |||
35 | class QTextCodec; | ||
36 | class PartPrivate; | ||
37 | |||
38 | namespace GpgME | ||
39 | { | ||
40 | class ImportResult; | ||
41 | } | ||
42 | |||
43 | namespace QGpgME | ||
44 | { | ||
45 | class Protocol; | ||
46 | } | ||
47 | |||
48 | namespace KMime | ||
49 | { | ||
50 | class Content; | ||
51 | } | ||
52 | |||
53 | namespace MimeTreeParser | ||
54 | { | ||
55 | class ObjectTreeParser; | ||
56 | class HtmlWriter; | ||
57 | class HTMLBlock; | ||
58 | typedef QSharedPointer<HTMLBlock> HTMLBlockPtr; | ||
59 | class CryptoBodyPartMemento; | ||
60 | class MultiPartAlternativeBodyPartFormatter; | ||
61 | namespace Interface | ||
62 | { | ||
63 | class ObjectTreeSource; | ||
64 | } | ||
65 | |||
66 | class 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) | ||
73 | public: | ||
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 | |||
107 | protected: | ||
108 | void parseInternal(KMime::Content *node, bool onlyOneMimePart); | ||
109 | QString renderInternalText() const; | ||
110 | |||
111 | QString mText; | ||
112 | ObjectTreeParser *mOtp; | ||
113 | PartMetaData mMetaData; | ||
114 | |||
115 | private: | ||
116 | QVector<Interface::MessagePart::Ptr> mBlocks; | ||
117 | |||
118 | KMime::Content *mAttachmentNode; | ||
119 | bool mRoot; | ||
120 | }; | ||
121 | |||
122 | class MimeMessagePart : public MessagePart | ||
123 | { | ||
124 | Q_OBJECT | ||
125 | public: | ||
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; | ||
134 | private: | ||
135 | KMime::Content *mNode; | ||
136 | bool mOnlyOneMimePart; | ||
137 | |||
138 | friend class AlternativeMessagePart; | ||
139 | friend class ::PartPrivate; | ||
140 | }; | ||
141 | |||
142 | class MessagePartList : public MessagePart | ||
143 | { | ||
144 | Q_OBJECT | ||
145 | public: | ||
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; | ||
154 | private: | ||
155 | }; | ||
156 | |||
157 | enum IconType { | ||
158 | NoIcon = 0, | ||
159 | IconExternal, | ||
160 | IconInline | ||
161 | }; | ||
162 | |||
163 | class TextMessagePart : public MessagePartList | ||
164 | { | ||
165 | Q_OBJECT | ||
166 | public: | ||
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 | |||
181 | protected: | ||
182 | KMime::Content *mNode; | ||
183 | |||
184 | private: | ||
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 | |||
199 | class AttachmentMessagePart : public TextMessagePart | ||
200 | { | ||
201 | Q_OBJECT | ||
202 | public: | ||
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 | |||
215 | private: | ||
216 | bool mIsImage; | ||
217 | bool mNeverDisplayInline; | ||
218 | }; | ||
219 | |||
220 | class HtmlMessagePart : public MessagePart | ||
221 | { | ||
222 | Q_OBJECT | ||
223 | public: | ||
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 | |||
233 | private: | ||
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 | |||
243 | class AlternativeMessagePart : public MessagePart | ||
244 | { | ||
245 | Q_OBJECT | ||
246 | public: | ||
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; | ||
264 | private: | ||
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 | |||
278 | class CertMessagePart : public MessagePart | ||
279 | { | ||
280 | Q_OBJECT | ||
281 | public: | ||
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 | |||
288 | private: | ||
289 | KMime::Content *mNode; | ||
290 | bool mAutoImport; | ||
291 | GpgME::ImportResult mImportResult; | ||
292 | const QGpgME::Protocol *mCryptoProto; | ||
293 | friend class DefaultRendererPrivate; | ||
294 | }; | ||
295 | |||
296 | class EncapsulatedRfc822MessagePart : public MessagePart | ||
297 | { | ||
298 | Q_OBJECT | ||
299 | public: | ||
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; | ||
308 | private: | ||
309 | const KMime::Message::Ptr mMessage; | ||
310 | KMime::Content *mNode; | ||
311 | |||
312 | friend class DefaultRendererPrivate; | ||
313 | }; | ||
314 | |||
315 | class 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) | ||
321 | public: | ||
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 | |||
351 | private: | ||
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 | |||
358 | protected: | ||
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 | |||
372 | class SignedMessagePart : public MessagePart | ||
373 | { | ||
374 | Q_OBJECT | ||
375 | Q_PROPERTY(bool isSigned READ isSigned) | ||
376 | public: | ||
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 | |||
398 | private: | ||
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); | ||
409 | protected: | ||
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 | |||
21 | MimeTreeParser::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 | |||
24 | namespace MimeTreeParser | ||
25 | { | ||
26 | namespace Interface | ||
27 | { | ||
28 | /** | ||
29 | * Interface for rendering messageparts to html. | ||
30 | * @author Andras Mantia <sknauss@kde.org> | ||
31 | */ | ||
32 | class MessagePartRenderer | ||
33 | { | ||
34 | public: | ||
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 | |||
3 | Q_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> | ||
4 | Q_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 | |||
46 | namespace MimeTreeParser | ||
47 | { | ||
48 | |||
49 | QStringList replySubjPrefixes(QStringList() << QStringLiteral("Re\\s*:") << QStringLiteral("Re\\[\\d+\\]:") << QStringLiteral("Re\\d+:")); | ||
50 | QStringList forwardSubjPrefixes(QStringList() << QStringLiteral("Fwd:") << QStringLiteral("FW:")); | ||
51 | |||
52 | NodeHelper::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 | |||
82 | NodeHelper::~NodeHelper() | ||
83 | { | ||
84 | if (mAttachmentFilesDir) { | ||
85 | mAttachmentFilesDir->forceCleanTempFiles(); | ||
86 | delete mAttachmentFilesDir; | ||
87 | mAttachmentFilesDir = nullptr; | ||
88 | } | ||
89 | clear(); | ||
90 | } | ||
91 | |||
92 | void 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 | |||
108 | void 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 | |||
138 | bool NodeHelper::nodeProcessed(KMime::Content *node) const | ||
139 | { | ||
140 | if (!node) { | ||
141 | return true; | ||
142 | } | ||
143 | return mProcessedNodes.contains(node); | ||
144 | } | ||
145 | |||
146 | static 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 | |||
158 | void 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 | |||
184 | void NodeHelper::setEncryptionState(const KMime::Content *node, const KMMsgEncryptionState state) | ||
185 | { | ||
186 | mEncryptionState[node] = state; | ||
187 | } | ||
188 | |||
189 | KMMsgEncryptionState NodeHelper::encryptionState(const KMime::Content *node) const | ||
190 | { | ||
191 | return mEncryptionState.value(node, KMMsgNotEncrypted); | ||
192 | } | ||
193 | |||
194 | void NodeHelper::setSignatureState(const KMime::Content *node, const KMMsgSignatureState state) | ||
195 | { | ||
196 | mSignatureState[node] = state; | ||
197 | } | ||
198 | |||
199 | KMMsgSignatureState NodeHelper::signatureState(const KMime::Content *node) const | ||
200 | { | ||
201 | return mSignatureState.value(node, KMMsgNotSigned); | ||
202 | } | ||
203 | |||
204 | PartMetaData NodeHelper::partMetaData(KMime::Content *node) | ||
205 | { | ||
206 | return mPartMetaDatas.value(node, PartMetaData()); | ||
207 | } | ||
208 | |||
209 | void NodeHelper::setPartMetaData(KMime::Content *node, const PartMetaData &metaData) | ||
210 | { | ||
211 | mPartMetaDatas.insert(node, metaData); | ||
212 | } | ||
213 | |||
214 | QString 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 | |||
261 | QUrl 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 | |||
284 | QString NodeHelper::createTempDir(const QString ¶m) | ||
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 | |||
306 | void NodeHelper::forceCleanTempFiles() | ||
307 | { | ||
308 | mAttachmentFilesDir->forceCleanTempFiles(); | ||
309 | delete mAttachmentFilesDir; | ||
310 | mAttachmentFilesDir = nullptr; | ||
311 | } | ||
312 | |||
313 | void NodeHelper::removeTempFiles() | ||
314 | { | ||
315 | //Don't delete it it will delete in class | ||
316 | mAttachmentFilesDir->removeTempFiles(); | ||
317 | mAttachmentFilesDir = new AttachmentTemporaryFilesDirs(); | ||
318 | } | ||
319 | |||
320 | void NodeHelper::addTempFile(const QString &file) | ||
321 | { | ||
322 | mAttachmentFilesDir->addTempFile(file); | ||
323 | } | ||
324 | |||
325 | bool 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 | |||
340 | QByteArray 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 | |||
349 | KMMsgEncryptionState 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 | |||
407 | KMMsgSignatureState 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 | |||
465 | void 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 | ||
476 | QString 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 | |||
510 | QString NodeHelper::cleanSubject(KMime::Message *message) | ||
511 | { | ||
512 | return cleanSubject(message, replySubjPrefixes + forwardSubjPrefixes, | ||
513 | true, QString()).trimmed(); | ||
514 | } | ||
515 | |||
516 | QString 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 | |||
530 | void NodeHelper::setOverrideCodec(KMime::Content *node, const QTextCodec *codec) | ||
531 | { | ||
532 | if (!node) { | ||
533 | return; | ||
534 | } | ||
535 | |||
536 | mOverrideCodecs[node] = codec; | ||
537 | } | ||
538 | |||
539 | const 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 | |||
565 | const 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 | |||
574 | QString 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 | ||
586 | Interface::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 | ||
600 | void 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 | |||
622 | bool NodeHelper::isNodeDisplayedEmbedded(KMime::Content *node) const | ||
623 | { | ||
624 | qCDebug(MIMETREEPARSER_LOG) << "IS NODE: " << mDisplayEmbeddedNodes.contains(node); | ||
625 | return mDisplayEmbeddedNodes.contains(node); | ||
626 | } | ||
627 | |||
628 | void 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 | |||
638 | bool NodeHelper::isNodeDisplayedHidden(KMime::Content *node) const | ||
639 | { | ||
640 | return mDisplayHiddenNodes.contains(node); | ||
641 | } | ||
642 | |||
643 | void 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 | */ | ||
658 | QString 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 | |||
705 | KMime::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 | |||
728 | QString NodeHelper::asHREF(const KMime::Content *node, const QString &place) const | ||
729 | { | ||
730 | return QStringLiteral("attachment:%1?place=%2").arg(persistentIndex(node), place); | ||
731 | } | ||
732 | |||
733 | KMime::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 | |||
757 | QString 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 | //----------------------------------------------------------------------------- | ||
771 | QString NodeHelper::encodingForName(const QString &descriptiveName) | ||
772 | { | ||
773 | QString encoding = KCharsets::charsets()->encodingForName(descriptiveName); | ||
774 | return NodeHelper::fixEncoding(encoding); | ||
775 | } | ||
776 | |||
777 | QStringList 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 | |||
799 | QString 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 | |||
816 | void 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 | |||
822 | QList< KMime::Content * > NodeHelper::extraContents(KMime::Content *topLevelnode) const | ||
823 | { | ||
824 | return mExtraContents.value(topLevelnode); | ||
825 | } | ||
826 | |||
827 | void 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 | |||
851 | void 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 | |||
871 | KMime::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 | |||
897 | KMime::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 | |||
910 | bool 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 | |||
1033 | KMime::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 | |||
1054 | QVector<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 | |||
32 | class QUrl; | ||
33 | class QTextCodec; | ||
34 | |||
35 | namespace MimeTreeParser | ||
36 | { | ||
37 | class AttachmentTemporaryFilesDirs; | ||
38 | namespace Interface | ||
39 | { | ||
40 | class BodyPartMemento; | ||
41 | } | ||
42 | } | ||
43 | |||
44 | namespace MimeTreeParser | ||
45 | { | ||
46 | |||
47 | /** | ||
48 | * @author Andras Mantia <andras@kdab.net> | ||
49 | */ | ||
50 | class NodeHelper: public QObject | ||
51 | { | ||
52 | Q_OBJECT | ||
53 | public: | ||
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 ¶m = 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 | |||
238 | Q_SIGNALS: | ||
239 | void update(MimeTreeParser::UpdateMode); | ||
240 | |||
241 | private: | ||
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 | |||
271 | private: | ||
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 | |||
63 | using namespace MimeTreeParser; | ||
64 | |||
65 | ObjectTreeParser::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 | |||
80 | ObjectTreeParser::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 | |||
96 | void 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 | |||
111 | ObjectTreeParser::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 | |||
125 | ObjectTreeParser::~ObjectTreeParser() | ||
126 | { | ||
127 | if (mDeleteNodeHelper) { | ||
128 | delete mNodeHelper; | ||
129 | mNodeHelper = nullptr; | ||
130 | } | ||
131 | } | ||
132 | |||
133 | void ObjectTreeParser::setAllowAsync(bool allow) | ||
134 | { | ||
135 | Q_ASSERT(!mHasPendingAsyncJobs); | ||
136 | mAllowAsync = allow; | ||
137 | } | ||
138 | |||
139 | bool ObjectTreeParser::allowAsync() const | ||
140 | { | ||
141 | return mAllowAsync; | ||
142 | } | ||
143 | |||
144 | bool ObjectTreeParser::hasPendingAsyncJobs() const | ||
145 | { | ||
146 | return mHasPendingAsyncJobs; | ||
147 | } | ||
148 | |||
149 | QString ObjectTreeParser::plainTextContent() const | ||
150 | { | ||
151 | return mPlainTextContent; | ||
152 | } | ||
153 | |||
154 | QString ObjectTreeParser::htmlContent() const | ||
155 | { | ||
156 | return mHtmlContent; | ||
157 | } | ||
158 | |||
159 | void 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 | |||
173 | void 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 | |||
201 | MessagePartPtr ObjectTreeParser::parsedPart() const | ||
202 | { | ||
203 | return mParsedPart; | ||
204 | } | ||
205 | |||
206 | bool 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 | |||
264 | MessagePart::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 | |||
342 | Interface::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 | |||
388 | KMMsgSignatureState ProcessResult::inlineSignatureState() const | ||
389 | { | ||
390 | return mInlineSignatureState; | ||
391 | } | ||
392 | |||
393 | void ProcessResult::setInlineSignatureState(KMMsgSignatureState state) | ||
394 | { | ||
395 | mInlineSignatureState = state; | ||
396 | } | ||
397 | |||
398 | KMMsgEncryptionState ProcessResult::inlineEncryptionState() const | ||
399 | { | ||
400 | return mInlineEncryptionState; | ||
401 | } | ||
402 | |||
403 | void ProcessResult::setInlineEncryptionState(KMMsgEncryptionState state) | ||
404 | { | ||
405 | mInlineEncryptionState = state; | ||
406 | } | ||
407 | |||
408 | bool ProcessResult::neverDisplayInline() const | ||
409 | { | ||
410 | return mNeverDisplayInline; | ||
411 | } | ||
412 | |||
413 | void ProcessResult::setNeverDisplayInline(bool display) | ||
414 | { | ||
415 | mNeverDisplayInline = display; | ||
416 | } | ||
417 | |||
418 | bool ProcessResult::isImage() const | ||
419 | { | ||
420 | return mIsImage; | ||
421 | } | ||
422 | |||
423 | void ProcessResult::setIsImage(bool image) | ||
424 | { | ||
425 | mIsImage = image; | ||
426 | } | ||
427 | |||
428 | void 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 | |||
437 | void ObjectTreeParser::extractNodeInfos(KMime::Content *curNode, bool isFirstTextPart) | ||
438 | { | ||
439 | if (isFirstTextPart) { | ||
440 | mPlainTextContent += curNode->decodedText(); | ||
441 | mPlainTextContentCharset += NodeHelper::charset(curNode); | ||
442 | } | ||
443 | } | ||
444 | |||
445 | void ObjectTreeParser::setPlainTextContent(const QString &plainTextContent) | ||
446 | { | ||
447 | mPlainTextContent = plainTextContent; | ||
448 | } | ||
449 | |||
450 | const 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 | |||
459 | QByteArray ObjectTreeParser::plainTextContentCharset() const | ||
460 | { | ||
461 | return mPlainTextContentCharset; | ||
462 | } | ||
463 | |||
464 | QByteArray ObjectTreeParser::htmlContentCharset() const | ||
465 | { | ||
466 | return mHtmlContentCharset; | ||
467 | } | ||
468 | |||
469 | bool ObjectTreeParser::showOnlyOneMimePart() const | ||
470 | { | ||
471 | return mShowOnlyOneMimePart; | ||
472 | } | ||
473 | |||
474 | void ObjectTreeParser::setShowOnlyOneMimePart(bool show) | ||
475 | { | ||
476 | mShowOnlyOneMimePart = show; | ||
477 | } | ||
478 | |||
479 | const AttachmentStrategy *ObjectTreeParser::attachmentStrategy() const | ||
480 | { | ||
481 | return mAttachmentStrategy; | ||
482 | } | ||
483 | |||
484 | HtmlWriter *ObjectTreeParser::htmlWriter() const | ||
485 | { | ||
486 | if (mHtmlWriter) { | ||
487 | return mHtmlWriter; | ||
488 | } | ||
489 | return mSource->htmlWriter(); | ||
490 | } | ||
491 | |||
492 | MimeTreeParser::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 | |||
42 | class QString; | ||
43 | |||
44 | namespace KMime | ||
45 | { | ||
46 | class Content; | ||
47 | } | ||
48 | |||
49 | namespace MimeTreeParser | ||
50 | { | ||
51 | |||
52 | namespace Interface | ||
53 | { | ||
54 | class MessagePart; | ||
55 | typedef QSharedPointer<MessagePart> MessagePartPtr; | ||
56 | } | ||
57 | |||
58 | class PartMetaData; | ||
59 | class ViewerPrivate; | ||
60 | class HtmlWriter; | ||
61 | class AttachmentStrategy; | ||
62 | class NodeHelper; | ||
63 | class MessagePart; | ||
64 | class MimeMessagePart; | ||
65 | |||
66 | typedef QSharedPointer<MessagePart> MessagePartPtr; | ||
67 | typedef QSharedPointer<MimeMessagePart> MimeMessagePartPtr; | ||
68 | |||
69 | class ProcessResult | ||
70 | { | ||
71 | public: | ||
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 | |||
96 | private: | ||
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 | |||
109 | First, have a look at the documentation in Mainpage.dox and at the documentation of ViewerPrivate | ||
110 | to understand the broader picture. | ||
111 | |||
112 | Just a note on the terminology: 'Node' refers to a MIME part here, which in KMime is a | ||
113 | KMime::Content. | ||
114 | |||
115 | \par Basics | ||
116 | |||
117 | The ObjectTreeParser basically has two modes: Generating the HTML code for the Viewer, or only | ||
118 | extracting the plainTextContent() for situations where only the message text is needed, for example | ||
119 | when inline forwarding a message. The mode depends on the Interface::ObjectTreeSource passed to the | ||
120 | constructor: If Interface::ObjectTreeSource::htmlWriter() is not 0, then the HTML code generation mode is | ||
121 | used. | ||
122 | |||
123 | Basically, all the ObjectTreeParser does is going through the tree of MIME parts and operating on | ||
124 | those nodes. Operating here means creating the HTML code for the node or extracting the textual | ||
125 | content from it. This process is started with parseObjectTree(), where we loop over the subnodes | ||
126 | of the current root node. For each of those subnodes, we try to find a BodyPartFormatter that can | ||
127 | handle the type of the node. This can either be an internal function, such as | ||
128 | processMultiPartAlternativeSubtype() or processTextHtmlSubtype(), or it can be an external plugin. | ||
129 | More on external plugins later. When no matching formatter is found, defaultHandling() is called | ||
130 | for that node. | ||
131 | |||
132 | \par Multipart Nodes | ||
133 | |||
134 | Those nodes that are of type multipart have subnodes. If one of those children needs to be | ||
135 | processed normally, the processMultipartXXX() functions call stdChildHandling() for the node that | ||
136 | should be handled normally. stdChildHandling() creates its own ObjectTreeParser, which is a clone | ||
137 | of the current ObjectTreeParser, and processes the node. stdChildHandling() is not called for all | ||
138 | children of the multipart node, for example processMultiPartAlternativeSubtype() only calls it on | ||
139 | one of the children, as the other one doesn't need to be displayed. Similary, | ||
140 | processMultiPartSignedSubtype() doesn't call stdChildHandling() for the signature node, only for the | ||
141 | signed node. | ||
142 | |||
143 | \par Processed and Unprocessed Nodes | ||
144 | |||
145 | When a BodyPartFormatter has finished processing a node, it is processed. Nodes are set to being | ||
146 | not processed at the beginning of parseObjectTree(). The processed state of a node is saved in a | ||
147 | list in NodeHelper, see NodeHelper::setNodeProcessed(), NodeHelper::nodeProcessed() and the other | ||
148 | related helper functions. | ||
149 | |||
150 | It is the responsibility of the BodyPartFormatter to correctly call setNodeProcessed() and the | ||
151 | related functions. This is important so that processing the same node twice can be prevented. The | ||
152 | check that prevents duplicate processing is in parseObjectTree(). | ||
153 | |||
154 | An example where duplicate processing would happen if we didn't check for it is in stdChildHandling(), | ||
155 | which is for example called from processMultiPartAlternativeSubtype(). Let's say the setting is to | ||
156 | prefer HTML over plain text. In this case, processMultiPartAlternativeSubtype() would call | ||
157 | stdChildHandling() on the HTML node, which would create a new ObjectTreeParser and call | ||
158 | parseObjectTree() on it. parseObjectTree() processes the node and all its siblings, and one of the | ||
159 | siblings is the plain text node, which shouldn't be processed! Therefore | ||
160 | processMultiPartAlternativeSubtype() sets the plain text node as been processed already. | ||
161 | |||
162 | \par Plain Text Output | ||
163 | |||
164 | Various nodes have plain text that should be displayed. This plain text is usually processed though | ||
165 | writeBodyString() first. That method checks if the provided text is an inline PGP text and decrypts | ||
166 | it if necessary. It also pushes the text through quotedHTML(), which does a number of things like | ||
167 | coloring quoted lines or detecting links and creating real link tags for them. | ||
168 | |||
169 | \par Modifying the Message | ||
170 | |||
171 | The ObjectTreeParser does not only parse its message, in some circumstances it also modifies it | ||
172 | before displaying. This is for example the case when displaying a decrypted message: The original | ||
173 | message only contains a binary blob of crypto data, and processMultiPartEncryptedSubtype() decrypts | ||
174 | that blob. After decryption, the current node is replaced with the decrypted node, which happens | ||
175 | in insertAndParseNewChildNode(). | ||
176 | |||
177 | \par Crypto Operations | ||
178 | |||
179 | For signature and decryption handling, there are functions which help with generating the HTML code | ||
180 | for the signature header and footer. These are writeDeferredDecryptionBlock(), writeSigstatFooter() | ||
181 | and writeSigstatHeader(). As the name writeDeferredDecryptionBlock() suggests, a setting can cause | ||
182 | the message to not be decrypted unless the user clicks a link. Whether the message should be | ||
183 | decrypted or not can be controlled by Interface::ObjectTreeSource::decryptMessage(). When the user clicks the | ||
184 | decryption link, the URLHandler for 'kmail:' URLs sets that variable to true and triggers an update | ||
185 | of the Viewer, which will cause parseObjectTree() to be called again. | ||
186 | |||
187 | \par Async Crypto Operations | ||
188 | |||
189 | The above case describes decryption the message in place. However, decryption and also verifying of | ||
190 | the signature can take a long time, so synchronous decryption and verifing would cause the Viewer to | ||
191 | block. Therefore it is possible to run these operations in async mode, see allowAsync(). | ||
192 | In the first run of the async mode, all the ObjectTreeParser does is starting the decrypt or the | ||
193 | verify job, and informing the user that the operation is in progress with | ||
194 | writeDecryptionInProgressBlock() or with writeSigstatHeader(). Then, it creates and associates a | ||
195 | BodyPartMemento with the current node, for example a VerifyDetachedBodyPartMemento. Each node can | ||
196 | have multiple mementos associated with it, which are differeniated by name. | ||
197 | |||
198 | NodeHelper::setBodyPartMemento() and NodeHelper::bodyPartMemento() provide means to store and | ||
199 | retrieve these mementos. A memento is basically a thin wrapper around the crypto job, it stores the | ||
200 | job pointer, the job input data and the job result. Mementos can be used for any async situation, | ||
201 | not just for crypto jobs, but I'll describe crypto jobs here. | ||
202 | |||
203 | So in the first run of decrypting or verifying a message, the BodyPartFormatter only starts the | ||
204 | crypto job, creates the BodyPartMemento and writes the HTML code that tells the user that the | ||
205 | operation is in progress. parseObjectTree() thus finishes without waiting for anything, and the | ||
206 | message is displayed. | ||
207 | |||
208 | At some point, the crypto jobs then finish, which will cause slotResult() of the BodyPartMemento | ||
209 | to be called. slotResult() then saves the result to some member variable and calls | ||
210 | BodyPartMemento::notify(), which in the end will trigger an update of the Viewer. That update | ||
211 | will, in ViewerPrivate::parseMsg(), create a new ObjectTreeParser and call parseObjectTree() on it. | ||
212 | This is where the second run begins. | ||
213 | |||
214 | The functions that deal with decrypting of verifying, like processMultiPartSignedSubtype() or | ||
215 | processMultiPartEncryptedSubtype() will look if they find a BodyPartMemento that is associated with | ||
216 | the current node. Now it finds that memento, since it was created in the first run. It checks if the | ||
217 | memento's job has finished, and if so, the result can be written out (either the decrypted data or | ||
218 | the verified signature). | ||
219 | |||
220 | When dealing with encrypted nodes, new nodes are created with the decrypted data. It is important to | ||
221 | note that the original MIME tree is never modified, and remains the same as the original one. The method | ||
222 | createAndParseTempNode is called with the newly decrypted data, and it generates a new temporary node to | ||
223 | store the decrypted data. When these nodes are created, it is important to keep track of them as otherwise | ||
224 | some mementos that are added to the newly created temporary nodes will be constantly regenerated. As the | ||
225 | regeneration triggers a viewer update when complete, it results in an infinite refresh loop. The function | ||
226 | NodeHelper::linkAsPermanentDecrypted will create a link between the newly created node and the original parent. | ||
227 | Conversely, the function NodeHelper::attachExtraContent will create a link in the other direction, from the parent | ||
228 | node to the newly created temporary node. | ||
229 | |||
230 | When generating some mementos for nodes that may be temporary nodes (for example, contact photo mementos), the | ||
231 | function NodeHelper::setBodyPartMementoForPermanentParent is used. This will save the given body part memento for | ||
232 | the closest found permanent parent node, rather than the transient node itself. Then when checking for the existence | ||
233 | of a certain memento in a node, NodeHelper::findPermanentParentBodyPartMemento will check to see if any parent of the | ||
234 | given temporary node is a permanent (encrypted) node that has been used to generate the asked-for node. | ||
235 | |||
236 | To conclude: For async operations, parseObjectTree() is called twice: The first call starts the | ||
237 | crypto operation and creates the BodyPartMemento, the second calls sees that the BodyPartMemento is | ||
238 | there and can use its result for writing out the HTML. | ||
239 | |||
240 | \par PartMetaData and ProcessResult | ||
241 | |||
242 | For crypto operations, the class PartMetaData is used a lot, mainly to pass around info about the | ||
243 | crypto state of a node. A PartMetaData can also be associated with a node by using | ||
244 | NodeHelper::setPartMetaData(). The only user of that however is MessageAnalyzer::processPart() of | ||
245 | the Nepomuk E-Mail Feeder, which also uses the ObjectTreeParser to analyze the message. | ||
246 | |||
247 | You'll notice that a ProcessResult is passed to each formatter. The formatter is supposed to modify | ||
248 | the ProcessResult to tell the callers something about the state of the nodes that were processed. | ||
249 | One example for its use is to tell the caller about the crypto state of the node. | ||
250 | |||
251 | \par BodyPartFormatter Plugins | ||
252 | |||
253 | As mentioned way earlier, BodyPartFormatter can either be plugins or be internal. bodypartformatter.cpp | ||
254 | contains some trickery so that the processXXX() methods of the ObjectTreeParser are called from | ||
255 | a BodyPartFormatter associated with them, see the CREATE_BODY_PART_FORMATTER macro. | ||
256 | |||
257 | The BodyPartFormatter code is work in progress, it was supposed to be refactored, but that has not | ||
258 | yet happened at the time of writing. Therefore the code can seem a bit chaotic. | ||
259 | |||
260 | External plugins are loaded with loadPlugins() in bodypartformatterfactory.cpp. External plugins | ||
261 | can only use the classes in the interfaces/ directory, they include BodyPart, BodyPartMemento, | ||
262 | BodyPartFormatterPlugin, BodyPartFormatter, BodyPartURLHandler, HtmlWriter and URLHandler. Therefore | ||
263 | external plugins have powerful capabilities, which are needed for example in the iCal formatter or | ||
264 | in the vCard formatter. | ||
265 | |||
266 | \par Special HTML tags | ||
267 | |||
268 | As also mentioned in the documentation of ViewerPrivate, the ObjectTreeParser writes out special | ||
269 | links that are only understood by the viewer, for example 'kmail:' URLs or 'attachment:' URLs. | ||
270 | Also, some special HTML tags are created, which the Viewer later uses for post-processing. For | ||
271 | example a div with the id 'attachmentInjectionPoint', or a div with the id 'attachmentDiv', which | ||
272 | is used to mark an attachment in the body with a yellow border when the user clicks the attachment | ||
273 | in the header. Finally, parseObjectTree() creates an anchor with the id 'att%1', which is used in | ||
274 | the Viewer to scroll to the attachment. | ||
275 | */ | ||
276 | class 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 | |||
284 | public: | ||
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 | |||
338 | private: | ||
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 | |||
351 | private: | ||
352 | |||
353 | /** ctor helper */ | ||
354 | void init(); | ||
355 | |||
356 | const QTextCodec *codecFor(KMime::Content *node) const; | ||
357 | |||
358 | void copyContentFrom(const ObjectTreeParser *other); | ||
359 | |||
360 | private: | ||
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 | |||
24 | using namespace MimeTreeParser; | ||
25 | |||
26 | Interface::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> | ||
28 | class QTextCodec; | ||
29 | |||
30 | namespace MimeTreeParser | ||
31 | { | ||
32 | class HtmlWriter; | ||
33 | class AttachmentStrategy; | ||
34 | class BodyPartFormatterBaseFactory; | ||
35 | namespace Interface | ||
36 | { | ||
37 | class MessagePart; | ||
38 | typedef QSharedPointer<MessagePart> MessagePartPtr; | ||
39 | class MessagePartRenderer; | ||
40 | typedef QSharedPointer<MessagePartRenderer> MessagePartRendererPtr; | ||
41 | } | ||
42 | } | ||
43 | |||
44 | namespace MimeTreeParser | ||
45 | { | ||
46 | namespace Interface | ||
47 | { | ||
48 | |||
49 | /** | ||
50 | * Interface for object tree sources. | ||
51 | * @author Andras Mantia <amantia@kdab.net> | ||
52 | */ | ||
53 | class ObjectTreeSource | ||
54 | { | ||
55 | |||
56 | public: | ||
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 | |||
25 | namespace MimeTreeParser | ||
26 | { | ||
27 | |||
28 | class PartMetaData | ||
29 | { | ||
30 | public: | ||
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 | |||
43 | using namespace MimeTreeParser; | ||
44 | |||
45 | static int serial = 0; | ||
46 | |||
47 | PartNodeBodyPart::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 | |||
55 | QString 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 | |||
63 | QString PartNodeBodyPart::asText() const | ||
64 | { | ||
65 | if (!mContent->contentType()->isText()) { | ||
66 | return QString(); | ||
67 | } | ||
68 | return mContent->decodedText(); | ||
69 | } | ||
70 | |||
71 | QByteArray PartNodeBodyPart::asBinary() const | ||
72 | { | ||
73 | return mContent->decodedContent(); | ||
74 | } | ||
75 | |||
76 | QString PartNodeBodyPart::contentTypeParameter(const char *param) const | ||
77 | { | ||
78 | return mContent->contentType()->parameter(QString::fromLatin1(param)); | ||
79 | } | ||
80 | |||
81 | QString PartNodeBodyPart::contentDescription() const | ||
82 | { | ||
83 | return mContent->contentDescription()->asUnicodeString(); | ||
84 | } | ||
85 | |||
86 | QString PartNodeBodyPart::contentDispositionParameter(const char *param) const | ||
87 | { | ||
88 | return mContent->contentDisposition()->parameter(QString::fromLatin1(param)); | ||
89 | } | ||
90 | |||
91 | bool PartNodeBodyPart::hasCompleteBody() const | ||
92 | { | ||
93 | qCWarning(MIMETREEPARSER_LOG) << "Sorry, not yet implemented."; | ||
94 | return true; | ||
95 | } | ||
96 | |||
97 | Interface::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 | |||
105 | void 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 | |||
112 | Interface::BodyPart::Display PartNodeBodyPart::defaultDisplay() const | ||
113 | { | ||
114 | return mDefaultDisplay; | ||
115 | } | ||
116 | |||
117 | void PartNodeBodyPart::setDefaultDisplay(Interface::BodyPart::Display d) | ||
118 | { | ||
119 | mDefaultDisplay = d; | ||
120 | } | ||
121 | |||
122 | Interface::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 | |||
39 | namespace KMime | ||
40 | { | ||
41 | class Content; | ||
42 | } | ||
43 | |||
44 | namespace MimeTreeParser | ||
45 | { | ||
46 | class NodeHelper; | ||
47 | } | ||
48 | |||
49 | namespace MimeTreeParser | ||
50 | { | ||
51 | |||
52 | /** | ||
53 | @short an implementation of the BodyPart interface using KMime::Content's | ||
54 | */ | ||
55 | class PartNodeBodyPart : public Interface::BodyPart | ||
56 | { | ||
57 | public: | ||
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; | ||
97 | private: | ||
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 | |||
31 | using namespace GpgME; | ||
32 | using namespace MimeTreeParser; | ||
33 | |||
34 | QGpgMEJobExecutor::QGpgMEJobExecutor(QObject *parent) : QObject(parent) | ||
35 | { | ||
36 | setObjectName(QStringLiteral("KleoJobExecutor")); | ||
37 | mEventLoop = new QEventLoop(this); | ||
38 | } | ||
39 | |||
40 | GpgME::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 | |||
55 | GpgME::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 | |||
72 | std::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 | |||
89 | GpgME::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 | |||
100 | Error QGpgMEJobExecutor::auditLogError() const | ||
101 | { | ||
102 | return mAuditLogError; | ||
103 | } | ||
104 | |||
105 | void 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 | |||
116 | void 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 | |||
128 | void 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 | |||
144 | void 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 | |||
154 | QString 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 | |||
30 | class QEventLoop; | ||
31 | |||
32 | namespace QGpgME | ||
33 | { | ||
34 | class DecryptVerifyJob; | ||
35 | class ImportJob; | ||
36 | class VerifyDetachedJob; | ||
37 | class VerifyOpaqueJob; | ||
38 | } | ||
39 | |||
40 | namespace MimeTreeParser | ||
41 | { | ||
42 | |||
43 | /** | ||
44 | Helper class for synchronous execution of Kleo crypto jobs. | ||
45 | */ | ||
46 | class QGpgMEJobExecutor : public QObject | ||
47 | { | ||
48 | Q_OBJECT | ||
49 | public: | ||
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 | |||
66 | private 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 | |||
74 | private: | ||
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 | |||
27 | using namespace MimeTreeParser; | ||
28 | |||
29 | QueueHtmlWriter::QueueHtmlWriter(HtmlWriter *base) | ||
30 | : HtmlWriter() | ||
31 | , mBase(base) | ||
32 | { | ||
33 | } | ||
34 | |||
35 | QueueHtmlWriter::~QueueHtmlWriter() | ||
36 | { | ||
37 | } | ||
38 | |||
39 | void QueueHtmlWriter::setBase(HtmlWriter *base) | ||
40 | { | ||
41 | mBase = base; | ||
42 | } | ||
43 | |||
44 | void QueueHtmlWriter::begin(const QString &css) | ||
45 | { | ||
46 | Command cmd; | ||
47 | cmd.type = Command::Begin; | ||
48 | cmd.s = css; | ||
49 | mQueue.append(cmd); | ||
50 | } | ||
51 | |||
52 | void QueueHtmlWriter::end() | ||
53 | { | ||
54 | Command cmd; | ||
55 | cmd.type = Command::End; | ||
56 | mQueue.append(cmd); | ||
57 | } | ||
58 | |||
59 | void QueueHtmlWriter::reset() | ||
60 | { | ||
61 | Command cmd; | ||
62 | cmd.type = Command::Reset; | ||
63 | mQueue.append(cmd); | ||
64 | } | ||
65 | |||
66 | void QueueHtmlWriter::write(const QString &str) | ||
67 | { | ||
68 | Command cmd; | ||
69 | cmd.type = Command::Write; | ||
70 | cmd.s = str; | ||
71 | mQueue.append(cmd); | ||
72 | } | ||
73 | |||
74 | void QueueHtmlWriter::queue(const QString &str) | ||
75 | { | ||
76 | Command cmd; | ||
77 | cmd.type = Command::Queue; | ||
78 | cmd.s = str; | ||
79 | mQueue.append(cmd); | ||
80 | } | ||
81 | |||
82 | void QueueHtmlWriter::flush() | ||
83 | { | ||
84 | Command cmd; | ||
85 | cmd.type = Command::Flush; | ||
86 | mQueue.append(cmd); | ||
87 | } | ||
88 | |||
89 | void 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 | |||
121 | void 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 | } | ||
129 | void 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 | |||
28 | class QString; | ||
29 | class QByteArray; | ||
30 | |||
31 | namespace MimeTreeParser | ||
32 | { | ||
33 | /** | ||
34 | \brief Cache HTML output and not write them directy. | ||
35 | |||
36 | This class is needed to make it possible to first process the mime tree and | ||
37 | afterwards render the HTML. | ||
38 | |||
39 | Please do not use this class - it is only added to make it possible to slowly | ||
40 | move ObjectTreeParser to a process fist / render later. | ||
41 | |||
42 | */ | ||
43 | struct Command { | ||
44 | enum { Begin, End, Reset, Write, Queue, Flush, EmbedPart, ExtraHead } type; | ||
45 | QString s; | ||
46 | QByteArray b; | ||
47 | }; | ||
48 | |||
49 | class QueueHtmlWriter : public HtmlWriter | ||
50 | { | ||
51 | public: | ||
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 | |||
68 | private: | ||
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 | |||
30 | using namespace MimeTreeParser::Util; | ||
31 | |||
32 | bool 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 | |||
47 | QString 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 | |||
57 | QMimeType 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 | |||
73 | QString 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 | |||
122 | QString 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 | |||
24 | class QMimeType; | ||
25 | |||
26 | namespace KMime | ||
27 | { | ||
28 | class Content; | ||
29 | } | ||
30 | |||
31 | namespace MimeTreeParser | ||
32 | { | ||
33 | |||
34 | /** | ||
35 | * The Util namespace contains a collection of helper functions use in | ||
36 | * various places. | ||
37 | */ | ||
38 | namespace 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 | */ | ||
45 | enum 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 | |||
53 | bool isTypeBlacklisted(KMime::Content *node); | ||
54 | |||
55 | QString labelForContent(KMime::Content *node); | ||
56 | |||
57 | QMimeType mimetype(const QString &name); | ||
58 | |||
59 | QString iconNameForMimetype(const QString &mimeType, | ||
60 | const QString &fallbackFileName1 = QString(), | ||
61 | const QString &fallbackFileName2 = QString()); | ||
62 | |||
63 | QString 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 | |||
22 | using namespace MimeTreeParser; | ||
23 | |||
24 | MimeMessagePart::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 | |||
38 | KMime::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 | |||
53 | MessagePart::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 | |||
28 | namespace 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 | */ | ||
35 | MimeMessagePart::Ptr createAndParseTempNode(Interface::BodyPart &part, KMime::Content *parentNode, const char *content, const char *cntDesc); | ||
36 | |||
37 | KMime::Content *findTypeInDirectChilds(KMime::Content *content, const QByteArray &mimeType); | ||
38 | |||
39 | MessagePart::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 | |||
30 | using namespace QGpgME; | ||
31 | using namespace GpgME; | ||
32 | using namespace MimeTreeParser; | ||
33 | |||
34 | VerifyDetachedBodyPartMemento::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 | |||
47 | VerifyDetachedBodyPartMemento::~VerifyDetachedBodyPartMemento() | ||
48 | { | ||
49 | if (m_job) { | ||
50 | m_job->slotCancel(); | ||
51 | } | ||
52 | if (m_keylistjob) { | ||
53 | m_keylistjob->slotCancel(); | ||
54 | } | ||
55 | } | ||
56 | |||
57 | bool 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 | |||
76 | void 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 | |||
103 | bool 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 | |||
112 | QStringList VerifyDetachedBodyPartMemento::keyListPattern() const | ||
113 | { | ||
114 | assert(canStartKeyListJob()); | ||
115 | return QStringList(QString::fromLatin1(m_vr.signature(0).fingerprint())); | ||
116 | } | ||
117 | |||
118 | void 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 | |||
128 | void 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 | |||
149 | bool 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 | |||
161 | void 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 | |||
169 | void 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 | |||
30 | namespace QGpgME | ||
31 | { | ||
32 | class VerifyDetachedJob; | ||
33 | class KeyListJob; | ||
34 | } | ||
35 | |||
36 | class QStringList; | ||
37 | |||
38 | namespace MimeTreeParser | ||
39 | { | ||
40 | |||
41 | class VerifyDetachedBodyPartMemento | ||
42 | : public CryptoBodyPartMemento | ||
43 | { | ||
44 | Q_OBJECT | ||
45 | public: | ||
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 | |||
64 | private Q_SLOTS: | ||
65 | void slotResult(const GpgME::VerificationResult &vr); | ||
66 | void slotKeyListJobDone(); | ||
67 | void slotNextKey(const GpgME::Key &); | ||
68 | |||
69 | private: | ||
70 | void saveResult(const GpgME::VerificationResult &); | ||
71 | bool canStartKeyListJob() const; | ||
72 | QStringList keyListPattern() const; | ||
73 | bool startKeyListJob(); | ||
74 | private: | ||
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 | |||
30 | using namespace QGpgME; | ||
31 | using namespace GpgME; | ||
32 | using namespace MimeTreeParser; | ||
33 | |||
34 | VerifyOpaqueBodyPartMemento::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 | |||
45 | VerifyOpaqueBodyPartMemento::~VerifyOpaqueBodyPartMemento() | ||
46 | { | ||
47 | if (m_job) { | ||
48 | m_job->slotCancel(); | ||
49 | } | ||
50 | if (m_keylistjob) { | ||
51 | m_keylistjob->slotCancel(); | ||
52 | } | ||
53 | } | ||
54 | |||
55 | bool 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 | |||
74 | void 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 | |||
102 | bool 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 | |||
111 | QStringList VerifyOpaqueBodyPartMemento::keyListPattern() const | ||
112 | { | ||
113 | assert(canStartKeyListJob()); | ||
114 | return QStringList(QString::fromLatin1(m_vr.signature(0).fingerprint())); | ||
115 | } | ||
116 | |||
117 | void 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 | |||
129 | void 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 | |||
151 | bool 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 | |||
163 | void 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 | |||
171 | void 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 | |||
31 | namespace QGpgME | ||
32 | { | ||
33 | class VerifyOpaqueJob; | ||
34 | class KeyListJob; | ||
35 | } | ||
36 | |||
37 | class QStringList; | ||
38 | |||
39 | namespace MimeTreeParser | ||
40 | { | ||
41 | |||
42 | class VerifyOpaqueBodyPartMemento | ||
43 | : public CryptoBodyPartMemento | ||
44 | { | ||
45 | Q_OBJECT | ||
46 | public: | ||
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 | |||
68 | private Q_SLOTS: | ||
69 | void slotResult(const GpgME::VerificationResult &vr, | ||
70 | const QByteArray &plainText); | ||
71 | void slotKeyListJobDone(); | ||
72 | void slotNextKey(const GpgME::Key &); | ||
73 | |||
74 | private: | ||
75 | void saveResult(const GpgME::VerificationResult &, | ||
76 | const QByteArray &); | ||
77 | bool canStartKeyListJob() const; | ||
78 | QStringList keyListPattern() const; | ||
79 | bool startKeyListJob(); | ||
80 | private: | ||
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) | |||
11 | add_executable(mimetreeparsertest interfacetest.cpp) | 11 | add_executable(mimetreeparsertest interfacetest.cpp) |
12 | add_gpg_crypto_test(mimetreeparsertest mimetreeparsertest) | 12 | add_gpg_crypto_test(mimetreeparsertest mimetreeparsertest) |
13 | qt5_use_modules(mimetreeparsertest Core Test) | 13 | qt5_use_modules(mimetreeparsertest Core Test) |
14 | target_link_libraries(mimetreeparsertest mimetreeparser) | 14 | target_link_libraries(mimetreeparsertest mimetreeparser kube_otp) |
15 | 15 | ||
16 | find_package(Gpgmepp 1.7.1 CONFIG) | 16 | #find_package(Gpgmepp 1.7.1 CONFIG) |
17 | find_package(QGpgme 1.7.1 CONFIG) | 17 | #find_package(QGpgme 1.7.1 CONFIG) |
18 | 18 | # | |
19 | ecm_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 | ||
27 | class ObjectSourcePrivate | 27 | class 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 | ||
25 | class QString; | 25 | class 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> |