summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--framework/domain/CMakeLists.txt4
-rw-r--r--framework/domain/messageparser.cpp49
-rw-r--r--framework/domain/messageparser.h15
-rw-r--r--framework/domain/mimetreeparser/CMakeLists.txt12
-rw-r--r--framework/domain/mimetreeparser/interface.cpp821
-rw-r--r--framework/domain/mimetreeparser/interface.h368
-rw-r--r--framework/domain/mimetreeparser/interface_p.h56
-rw-r--r--framework/domain/mimetreeparser/objecttreesource.cpp147
-rw-r--r--framework/domain/mimetreeparser/objecttreesource.h56
-rw-r--r--framework/domain/mimetreeparser/stringhtmlwriter.cpp150
-rw-r--r--framework/domain/mimetreeparser/stringhtmlwriter.h71
-rw-r--r--framework/domain/mimetreeparser/tests/CMakeLists.txt12
-rw-r--r--framework/domain/mimetreeparser/tests/data/alternative.mbox28
-rw-r--r--framework/domain/mimetreeparser/tests/data/html.mbox15
-rw-r--r--framework/domain/mimetreeparser/tests/data/openpgp-encrypted-attachment-and-non-encrypted-attachment.mbox115
-rw-r--r--framework/domain/mimetreeparser/tests/data/openpgp-inline-charset-encrypted.mbox40
-rw-r--r--framework/domain/mimetreeparser/tests/data/plaintext.mbox13
-rw-r--r--framework/domain/mimetreeparser/tests/data/smime-encrypted.mbox22
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/CMakeLists.txt10
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/DIR.txt3
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/crl-4E31CEB57DDD4A7B9991AB05507B1ED4293FF952.dbbin0 -> 2130 bytes
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/crl-7F2A402CBB016A9146D613568C89D3596A4111AA.dbbin0 -> 2048 bytes
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/dirmngr.conf8
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/gpg-agent.conf.in10
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/gpg.conf244
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/gpgsm.conf.in10
-rwxr-xr-xframework/domain/mimetreeparser/tests/gnupg_home/pinentry-fake.sh9
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/private-keys-v1.d/1AA8BA52430E51AE249AF0DA97D59F869E4101A8.keybin0 -> 528 bytes
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/pubring.gpgbin0 -> 6757 bytes
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/pubring.kbxbin0 -> 2017 bytes
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/scdaemon.conf8
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/secring.gpgbin0 -> 5163 bytes
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/trustdb.gpgbin0 -> 1440 bytes
-rw-r--r--framework/domain/mimetreeparser/tests/gnupg_home/trustlist.txt11
-rw-r--r--framework/domain/mimetreeparser/tests/interfacetest.cpp204
-rw-r--r--framework/domain/mimetreeparser/tests/kdepim_add_gpg_crypto_test.cmake60
-rw-r--r--framework/domain/mimetreeparser/tests/kdepim_generate_crypto_test_wrapper.cmake45
-rw-r--r--framework/domain/mimetreeparser/thoughts.txt148
38 files changed, 2745 insertions, 19 deletions
diff --git a/framework/domain/CMakeLists.txt b/framework/domain/CMakeLists.txt
index ea293655..07f01367 100644
--- a/framework/domain/CMakeLists.txt
+++ b/framework/domain/CMakeLists.txt
@@ -20,9 +20,11 @@ find_package(KF5 REQUIRED COMPONENTS Package)
20add_library(mailplugin SHARED ${mailplugin_SRCS}) 20add_library(mailplugin SHARED ${mailplugin_SRCS})
21 21
22qt5_use_modules(mailplugin Core Quick Qml WebKitWidgets) 22qt5_use_modules(mailplugin Core Quick Qml WebKitWidgets)
23target_link_libraries(mailplugin actionplugin settingsplugin sink KF5::MimeTreeParser KF5::Codecs KF5::Package KF5::Async KF5::IconThemes) 23target_link_libraries(mailplugin actionplugin settingsplugin sink mimetreeparser KF5::MimeTreeParser KF5::Codecs KF5::Package KF5::Async KF5::IconThemes)
24 24
25add_subdirectory(actions/tests) 25add_subdirectory(actions/tests)
26 26
27install(TARGETS mailplugin DESTINATION ${QML_INSTALL_DIR}/org/kube/framework/domain) 27install(TARGETS mailplugin DESTINATION ${QML_INSTALL_DIR}/org/kube/framework/domain)
28install(FILES qmldir DESTINATION ${QML_INSTALL_DIR}/org/kube/framework/domain) 28install(FILES qmldir DESTINATION ${QML_INSTALL_DIR}/org/kube/framework/domain)
29
30add_subdirectory(mimetreeparser) \ No newline at end of file
diff --git a/framework/domain/messageparser.cpp b/framework/domain/messageparser.cpp
index ff763aec..febd1363 100644
--- a/framework/domain/messageparser.cpp
+++ b/framework/domain/messageparser.cpp
@@ -21,6 +21,10 @@
21#include "stringhtmlwriter.h" 21#include "stringhtmlwriter.h"
22#include "objecttreesource.h" 22#include "objecttreesource.h"
23 23
24#include "mimetreeparser/interface.h"
25
26#include <QRegExp>
27
24#include <QFile> 28#include <QFile>
25#include <QImage> 29#include <QImage>
26#include <QDebug> 30#include <QDebug>
@@ -29,7 +33,9 @@
29#include <MimeTreeParser/ObjectTreeParser> 33#include <MimeTreeParser/ObjectTreeParser>
30#include <MimeTreeParser/MessagePart> 34#include <MimeTreeParser/MessagePart>
31 35
32PartModel::PartModel(QSharedPointer<MimeTreeParser::MessagePart> partTree, QMap<QByteArray, QUrl> embeddedPartMap) : mPartTree(partTree), mEmbeddedPartMap(embeddedPartMap) 36PartModel::PartModel(QSharedPointer<MimeTreeParser::MessagePart> partTree, std::shared_ptr<Parser> parser)
37 : mPartTree(partTree)
38 , mParser(parser)
33{ 39{
34} 40}
35 41
@@ -73,8 +79,14 @@ QVariant PartModel::data(const QModelIndex &index, int role) const
73 // qDebug() << "Getting text: " << part->property("text").toString(); 79 // qDebug() << "Getting text: " << part->property("text").toString();
74 // FIXME: we should have a list per part, and not one for all parts. 80 // FIXME: we should have a list per part, and not one for all parts.
75 auto text = part->property("htmlContent").toString(); 81 auto text = part->property("htmlContent").toString();
76 for (const auto &cid : mEmbeddedPartMap.keys()) { 82 auto rx = QRegExp("src=(\"|')cid:([^\1]*)\1");
77 text.replace(QString("src=\"cid:%1\"").arg(QString(cid)), QString("src=\"%1\"").arg(mEmbeddedPartMap.value(cid).toString())); 83 int pos = 0;
84 while ((pos = rx.indexIn(text, pos)) != -1) {
85 auto repl = mParser->getPart(rx.cap(2).toUtf8());
86 if (repl.isValid()) {
87 text.replace(rx.cap(0), QString("src=\"%1\"").arg(repl.toString()));
88 }
89 pos += rx.matchedLength();
78 } 90 }
79 return text; 91 return text;
80 } 92 }
@@ -141,16 +153,31 @@ int PartModel::columnCount(const QModelIndex &parent) const
141 return 1; 153 return 1;
142} 154}
143 155
156class MessagePartPrivate
157{
158public:
159 QSharedPointer<MimeTreeParser::MessagePart> mPartTree;
160 QString mHtml;
161 QMap<QByteArray, QUrl> mEmbeddedPartMap;
162 std::shared_ptr<MimeTreeParser::NodeHelper> mNodeHelper;
163 std::shared_ptr<Parser> mParser;
164};
144 165
145MessageParser::MessageParser(QObject *parent) 166MessageParser::MessageParser(QObject *parent)
146 : QObject(parent) 167 : QObject(parent)
168 , d(std::unique_ptr<MessagePartPrivate>(new MessagePartPrivate))
169{
170
171}
172
173MessageParser::~MessageParser()
147{ 174{
148 175
149} 176}
150 177
151QString MessageParser::html() const 178QString MessageParser::html() const
152{ 179{
153 return mHtml; 180 return d->mHtml;
154} 181}
155 182
156QVariant MessageParser::message() const 183QVariant MessageParser::message() const
@@ -162,6 +189,8 @@ void MessageParser::setMessage(const QVariant &message)
162{ 189{
163 QTime time; 190 QTime time;
164 time.start(); 191 time.start();
192 d->mParser = std::shared_ptr<Parser>(new Parser(message.toByteArray()));
193
165 const auto mailData = KMime::CRLFtoLF(message.toByteArray()); 194 const auto mailData = KMime::CRLFtoLF(message.toByteArray());
166 KMime::Message::Ptr msg(new KMime::Message); 195 KMime::Message::Ptr msg(new KMime::Message);
167 msg->setContent(mailData); 196 msg->setContent(mailData);
@@ -171,20 +200,20 @@ void MessageParser::setMessage(const QVariant &message)
171 // render the mail 200 // render the mail
172 StringHtmlWriter htmlWriter; 201 StringHtmlWriter htmlWriter;
173 //temporary files only have the lifetime of the nodehelper, so we keep it around until the mail changes. 202 //temporary files only have the lifetime of the nodehelper, so we keep it around until the mail changes.
174 mNodeHelper = std::make_shared<MimeTreeParser::NodeHelper>(); 203 d->mNodeHelper = std::make_shared<MimeTreeParser::NodeHelper>();
175 ObjectTreeSource source(&htmlWriter); 204 ObjectTreeSource source(&htmlWriter);
176 MimeTreeParser::ObjectTreeParser otp(&source, mNodeHelper.get()); 205 MimeTreeParser::ObjectTreeParser otp(&source, d->mNodeHelper.get());
177 206
178 otp.parseObjectTree(msg.data()); 207 otp.parseObjectTree(msg.data());
179 mPartTree = otp.parsedPart().dynamicCast<MimeTreeParser::MessagePart>(); 208 d->mPartTree = otp.parsedPart().dynamicCast<MimeTreeParser::MessagePart>();
180 209
181 mEmbeddedPartMap = htmlWriter.embeddedParts(); 210 d->mEmbeddedPartMap = htmlWriter.embeddedParts();
182 mHtml = htmlWriter.html(); 211 d->mHtml = htmlWriter.html();
183 emit htmlChanged(); 212 emit htmlChanged();
184} 213}
185 214
186QAbstractItemModel *MessageParser::partTree() const 215QAbstractItemModel *MessageParser::partTree() const
187{ 216{
188 return new PartModel(mPartTree, mEmbeddedPartMap); 217 return new PartModel(d->mPartTree, d->mParser);
189} 218}
190 219
diff --git a/framework/domain/messageparser.h b/framework/domain/messageparser.h
index 3e0255df..9469f2b5 100644
--- a/framework/domain/messageparser.h
+++ b/framework/domain/messageparser.h
@@ -29,11 +29,11 @@
29#include <memory> 29#include <memory>
30#include <MimeTreeParser/MessagePart> 30#include <MimeTreeParser/MessagePart>
31 31
32namespace MimeTreeParser {
33 class NodeHelper;
34};
35class QAbstractItemModel; 32class QAbstractItemModel;
36 33
34class Parser;
35class MessagePartPrivate;
36
37class MessageParser : public QObject 37class MessageParser : public QObject
38{ 38{
39 Q_OBJECT 39 Q_OBJECT
@@ -43,6 +43,7 @@ class MessageParser : public QObject
43 43
44public: 44public:
45 explicit MessageParser(QObject *parent = Q_NULLPTR); 45 explicit MessageParser(QObject *parent = Q_NULLPTR);
46 ~MessageParser();
46 47
47 QString html() const; 48 QString html() const;
48 49
@@ -54,16 +55,13 @@ signals:
54 void htmlChanged(); 55 void htmlChanged();
55 56
56private: 57private:
57 QSharedPointer<MimeTreeParser::MessagePart> mPartTree; 58 std::unique_ptr<MessagePartPrivate> d;
58 QString mHtml;
59 QMap<QByteArray, QUrl> mEmbeddedPartMap;
60 std::shared_ptr<MimeTreeParser::NodeHelper> mNodeHelper;
61}; 59};
62 60
63class PartModel : public QAbstractItemModel { 61class PartModel : public QAbstractItemModel {
64 Q_OBJECT 62 Q_OBJECT
65public: 63public:
66 PartModel(QSharedPointer<MimeTreeParser::MessagePart> partTree, QMap<QByteArray, QUrl> embeddedPartMap); 64 PartModel(QSharedPointer<MimeTreeParser::MessagePart> partTree, std::shared_ptr<Parser> parser);
67 65
68public: 66public:
69 enum Roles { 67 enum Roles {
@@ -86,5 +84,6 @@ public:
86private: 84private:
87 QSharedPointer<MimeTreeParser::MessagePart> mPartTree; 85 QSharedPointer<MimeTreeParser::MessagePart> mPartTree;
88 QMap<QByteArray, QUrl> mEmbeddedPartMap; 86 QMap<QByteArray, QUrl> mEmbeddedPartMap;
87 std::shared_ptr<Parser> mParser;
89}; 88};
90 89
diff --git a/framework/domain/mimetreeparser/CMakeLists.txt b/framework/domain/mimetreeparser/CMakeLists.txt
new file mode 100644
index 00000000..e1c04893
--- /dev/null
+++ b/framework/domain/mimetreeparser/CMakeLists.txt
@@ -0,0 +1,12 @@
1set(mimetreeparser_SRCS
2 interface.cpp
3 objecttreesource.cpp
4 stringhtmlwriter.cpp
5)
6
7add_library(mimetreeparser SHARED ${mimetreeparser_SRCS})
8
9qt5_use_modules(mimetreeparser Core Gui)
10target_link_libraries(mimetreeparser KF5::Mime KF5::MimeTreeParser)
11
12add_subdirectory(tests) \ No newline at end of file
diff --git a/framework/domain/mimetreeparser/interface.cpp b/framework/domain/mimetreeparser/interface.cpp
new file mode 100644
index 00000000..c3ecf79c
--- /dev/null
+++ b/framework/domain/mimetreeparser/interface.cpp
@@ -0,0 +1,821 @@
1/*
2 Copyright (c) 2016 Sandro Knauß <knauss@kolabsystems.com>
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 "interface.h"
21#include "interface_p.h"
22
23#include "stringhtmlwriter.h"
24#include "objecttreesource.h"
25
26#include <KMime/Content>
27#include <MimeTreeParser/ObjectTreeParser>
28#include <MimeTreeParser/MessagePart>
29#include <MimeTreeParser/NodeHelper>
30
31#include <QMimeDatabase>
32#include <QMimeType>
33#include <QDebug>
34
35class MailMimePrivate
36{
37public:
38 KMime::Content *mNode;
39 MailMime *q;
40};
41
42MailMime::MailMime()
43 : d(std::unique_ptr<MailMimePrivate>(new MailMimePrivate()))
44{
45 d->q = this;
46}
47
48bool MailMime::isFirstTextPart() const
49{
50 if (!d->mNode || !d->mNode->topLevel()) {
51 return false;
52 }
53 return (d->mNode->topLevel()->textContent() == d->mNode);
54}
55
56bool MailMime::isTopLevelPart() const
57{
58 if (!d->mNode) {
59 return false;
60 }
61 return (d->mNode->topLevel() == d->mNode);
62}
63
64MailMime::Disposition MailMime::disposition() const
65{
66 if (!d->mNode) {
67 return Invalid;
68 }
69 const auto cd = d->mNode->contentDisposition(false);
70 if (!cd) {
71 return Invalid;
72 }
73 switch (cd->disposition()){
74 case KMime::Headers::CDinline:
75 return Inline;
76 case KMime::Headers::CDattachment:
77 return Attachment;
78 default:
79 return Invalid;
80 }
81}
82
83QString MailMime::filename() const
84{
85 if (!d->mNode) {
86 return QString();
87 }
88 const auto cd = d->mNode->contentDisposition(false);
89 if (!cd) {
90 return QString();
91 }
92 return cd->filename();
93}
94
95QMimeType MailMime::mimetype() const
96{
97 if (!d->mNode) {
98 return QMimeType();
99 }
100
101 const auto ct = d->mNode->contentType(false);
102 if (!ct) {
103 return QMimeType();
104 }
105
106 QMimeDatabase mimeDb;
107 return mimeDb.mimeTypeForName(ct->mimeType());
108}
109
110class PartPrivate
111{
112public:
113 PartPrivate(Part *part);
114 void appendSubPart(Part::Ptr subpart);
115
116 QVector<Part::Ptr> subParts();
117
118 Part *parent() const;
119
120 const MailMime::Ptr &mailMime() const;
121 void createMailMime(const MimeTreeParser::MimeMessagePart::Ptr &part);
122 void createMailMime(const MimeTreeParser::TextMessagePart::Ptr &part);
123 void createMailMime(const MimeTreeParser::AlternativeMessagePart::Ptr &part);
124 void createMailMime(const MimeTreeParser::HtmlMessagePart::Ptr &part);
125
126 void appendEncryption(const MimeTreeParser::EncryptedMessagePart::Ptr &part);
127 void appendSignature(const MimeTreeParser::SignedMessagePart::Ptr &part);
128
129 void setSignatures(const QVector<Signature::Ptr> &sigs);
130 void setEncryptions(const QVector<Encryption::Ptr> &encs);
131
132 const QVector<Encryption::Ptr> &encryptions() const;
133 const QVector<Signature::Ptr> &signatures() const;
134private:
135 Part *q;
136 Part *mParent;
137 QVector<Part::Ptr> mSubParts;
138 QVector<Encryption::Ptr> mEncryptions;
139 QVector<Signature::Ptr> mSignatures;
140 MailMime::Ptr mMailMime;
141};
142
143PartPrivate::PartPrivate(Part* part)
144 : q(part)
145 , mParent(Q_NULLPTR)
146{
147
148}
149
150void PartPrivate::createMailMime(const MimeTreeParser::HtmlMessagePart::Ptr& part)
151{
152 mMailMime = MailMime::Ptr(new MailMime);
153 mMailMime->d->mNode = part->mNode;
154}
155
156void PartPrivate::createMailMime(const MimeTreeParser::AlternativeMessagePart::Ptr& part)
157{
158 mMailMime = MailMime::Ptr(new MailMime);
159 mMailMime->d->mNode = part->mNode;
160}
161
162void PartPrivate::createMailMime(const MimeTreeParser::TextMessagePart::Ptr& part)
163{
164 mMailMime = MailMime::Ptr(new MailMime);
165 mMailMime->d->mNode = part->mNode;
166}
167
168void PartPrivate::createMailMime(const MimeTreeParser::MimeMessagePart::Ptr& part)
169{
170 mMailMime = MailMime::Ptr(new MailMime);
171 mMailMime->d->mNode = part->mNode;
172}
173
174void PartPrivate::appendSubPart(Part::Ptr subpart)
175{
176 subpart->d->mParent = q;
177 mSubParts.append(subpart);
178}
179
180void PartPrivate::appendEncryption(const MimeTreeParser::EncryptedMessagePart::Ptr& part)
181{
182 mEncryptions.append(Encryption::Ptr(new Encryption));
183}
184
185void PartPrivate::setEncryptions(const QVector< Encryption::Ptr >& encs)
186{
187 mEncryptions = encs;
188}
189
190void PartPrivate::appendSignature(const MimeTreeParser::SignedMessagePart::Ptr& part)
191{
192 mSignatures.append(Signature::Ptr(new Signature));
193}
194
195
196void PartPrivate::setSignatures(const QVector< Signature::Ptr >& sigs)
197{
198 mSignatures = sigs;
199}
200
201Part *PartPrivate::parent() const
202{
203 return mParent;
204}
205
206QVector< Part::Ptr > PartPrivate::subParts()
207{
208 return mSubParts;
209}
210
211const MailMime::Ptr& PartPrivate::mailMime() const
212{
213 return mMailMime;
214}
215
216const QVector< Encryption::Ptr >& PartPrivate::encryptions() const
217{
218 return mEncryptions;
219}
220
221const QVector< Signature::Ptr >& PartPrivate::signatures() const
222{
223 return mSignatures;
224}
225
226Part::Part()
227 : d(std::unique_ptr<PartPrivate>(new PartPrivate(this)))
228{
229
230}
231
232bool Part::hasSubParts() const
233{
234 return !subParts().isEmpty();
235}
236
237QVector<Part::Ptr> Part::subParts() const
238{
239 return d->subParts();
240}
241
242QByteArray Part::type() const
243{
244 return "Part";
245}
246
247QVector<QByteArray> Part::availableContents() const
248{
249 return QVector<QByteArray>();
250}
251
252QVector<Content::Ptr> Part::content() const
253{
254 return content(availableContents().first());
255}
256
257QVector<Content::Ptr> Part::content(const QByteArray& ct) const
258{
259 return QVector<Content::Ptr>();
260}
261
262QVector<Encryption::Ptr> Part::encryptions() const
263{
264 auto ret = d->encryptions();
265 auto parent = d->parent();
266 if (parent) {
267 ret.append(parent->encryptions());
268 }
269 return ret;
270}
271
272QVector<Signature::Ptr> Part::signatures() const
273{
274 auto ret = d->signatures();
275 auto parent = d->parent();
276 if (parent) {
277 ret.append(parent->signatures());
278 }
279 return ret;
280}
281
282MailMime::Ptr Part::mailMime() const
283{
284 return d->mailMime();
285}
286
287class ContentPrivate
288{
289public:
290 QByteArray mContent;
291 QByteArray mCodec;
292 Part *mParent;
293 Content *q;
294 MailMime::Ptr mMailMime;
295 QVector<Encryption::Ptr> mEncryptions;
296 QVector<Signature::Ptr> mSignatures;
297 void appendSignature(const MimeTreeParser::SignedMessagePart::Ptr &sig);
298 void appendEncryption(const MimeTreeParser::EncryptedMessagePart::Ptr &enc);
299};
300
301void ContentPrivate::appendEncryption(const MimeTreeParser::EncryptedMessagePart::Ptr& enc)
302{
303 mEncryptions.append(Encryption::Ptr(new Encryption));
304}
305
306void ContentPrivate::appendSignature(const MimeTreeParser::SignedMessagePart::Ptr& sig)
307{
308 mSignatures.append(Signature::Ptr(new Signature));
309}
310
311
312Content::Content(const QByteArray& content, Part *parent)
313 : d(std::unique_ptr<ContentPrivate>(new ContentPrivate))
314{
315 d->q = this;
316 d->mContent = content;
317 d->mCodec = "utf-8";
318 d->mParent = parent;
319}
320
321Content::Content(ContentPrivate* d_ptr)
322 : d(std::unique_ptr<ContentPrivate>(d_ptr))
323{
324 d->q = this;
325}
326
327Content::~Content()
328{
329}
330
331QVector<Encryption::Ptr> Content::encryptions() const
332{
333 auto ret = d->mEncryptions;
334 if (d->mParent) {
335 ret.append(d->mParent->encryptions());
336 }
337 return ret;
338}
339
340QVector<Signature::Ptr> Content::signatures() const
341{
342 auto ret = d->mSignatures;
343 if (d->mParent) {
344 ret.append(d->mParent->signatures());
345 }
346 return ret;
347}
348
349QByteArray Content::content() const
350{
351 return d->mContent;
352}
353
354QByteArray Content::charset() const
355{
356 return d->mCodec;
357}
358
359QByteArray Content::type() const
360{
361 return "Content";
362}
363
364MailMime::Ptr Content::mailMime() const
365{
366 if (d->mMailMime) {
367 return d->mMailMime;
368 } else {
369 return d->mParent->mailMime();
370 }
371}
372
373Part *Content::parent() const
374{
375 return d->mParent;
376}
377
378HtmlContent::HtmlContent(const QByteArray& content, Part* parent)
379 : Content(content, parent)
380{
381
382}
383
384QByteArray HtmlContent::type() const
385{
386 return "HtmlContent";
387}
388
389PlainTextContent::PlainTextContent(const QByteArray& content, Part* parent)
390 : Content(content, parent)
391{
392
393}
394
395PlainTextContent::PlainTextContent(ContentPrivate* d_ptr)
396 : Content(d_ptr)
397{
398
399}
400
401HtmlContent::HtmlContent(ContentPrivate* d_ptr)
402 : Content(d_ptr)
403{
404
405}
406
407
408QByteArray PlainTextContent::type() const
409{
410 return "PlainTextContent";
411}
412
413class AlternativePartPrivate
414{
415public:
416 void fillFrom(MimeTreeParser::AlternativeMessagePart::Ptr part);
417
418 QVector<Content::Ptr> content(const QByteArray &ct) const;
419
420 AlternativePart *q;
421
422 QVector<QByteArray> types() const;
423
424private:
425 QMap<QByteArray, QVector<Content::Ptr>> mContent;
426 QVector<QByteArray> mTypes;
427};
428
429void AlternativePartPrivate::fillFrom(MimeTreeParser::AlternativeMessagePart::Ptr part)
430{
431 mTypes = QVector<QByteArray>() << "html" << "plaintext";
432
433 Content::Ptr content = std::make_shared<HtmlContent>(part->htmlContent().toLocal8Bit(), q);
434 mContent["html"].append(content);
435 content = std::make_shared<PlainTextContent>(part->plaintextContent().toLocal8Bit(), q);
436 mContent["plaintext"].append(content);
437 q->reachParentD()->createMailMime(part);
438}
439
440QVector<QByteArray> AlternativePartPrivate::types() const
441{
442 return mTypes;
443}
444
445QVector<Content::Ptr> AlternativePartPrivate::content(const QByteArray& ct) const
446{
447 return mContent[ct];
448}
449
450AlternativePart::AlternativePart()
451 : d(std::unique_ptr<AlternativePartPrivate>(new AlternativePartPrivate))
452{
453 d->q = this;
454}
455
456AlternativePart::~AlternativePart()
457{
458
459}
460
461QByteArray AlternativePart::type() const
462{
463 return "AlternativePart";
464}
465
466QVector<QByteArray> AlternativePart::availableContents() const
467{
468 return d->types();
469}
470
471QVector<Content::Ptr> AlternativePart::content(const QByteArray& ct) const
472{
473 return d->content(ct);
474}
475
476PartPrivate* AlternativePart::reachParentD() const
477{
478 return Part::d.get();
479}
480
481class SinglePartPrivate
482{
483public:
484 void fillFrom(MimeTreeParser::TextMessagePart::Ptr part);
485 void fillFrom(MimeTreeParser::HtmlMessagePart::Ptr part);
486 void fillFrom(MimeTreeParser::AttachmentMessagePart::Ptr part);
487 SinglePart *q;
488
489 QVector<Content::Ptr> mContent;
490 QByteArray mType;
491};
492
493void SinglePartPrivate::fillFrom(MimeTreeParser::TextMessagePart::Ptr part)
494{
495 mType = "plaintext";
496 mContent.clear();
497 foreach (const auto &mp, part->subParts()) {
498 auto d_ptr = new ContentPrivate;
499 d_ptr->mContent = part->text().toLocal8Bit();
500 d_ptr->mParent = q;
501 d_ptr->mCodec = "utf-8";
502 const auto enc = mp.dynamicCast<MimeTreeParser::EncryptedMessagePart>();
503 auto sig = mp.dynamicCast<MimeTreeParser::SignedMessagePart>();
504 if (enc) {
505 d_ptr->appendEncryption(enc);
506 const auto s = enc->subParts();
507 if (s.size() == 1) {
508 sig = s[0].dynamicCast<MimeTreeParser::SignedMessagePart>();
509 }
510 }
511 if (sig) {
512 d_ptr->appendSignature(sig);
513 }
514 mContent.append(std::make_shared<PlainTextContent>(d_ptr));
515 q->reachParentD()->createMailMime(part);
516 }
517}
518
519void SinglePartPrivate::fillFrom(MimeTreeParser::HtmlMessagePart::Ptr part)
520{
521 mType = "html";
522 mContent.clear();
523 mContent.append(std::make_shared<HtmlContent>(part->text().toLocal8Bit(), q));
524 q->reachParentD()->createMailMime(part);
525}
526
527void SinglePartPrivate::fillFrom(MimeTreeParser::AttachmentMessagePart::Ptr part)
528{
529 q->reachParentD()->createMailMime(part.staticCast<MimeTreeParser::TextMessagePart>());
530 mType = q->mailMime()->mimetype().name().toUtf8();
531 mContent.clear();
532 mContent.append(std::make_shared<Content>(part->text().toLocal8Bit(), q));
533}
534
535SinglePart::SinglePart()
536 : d(std::unique_ptr<SinglePartPrivate>(new SinglePartPrivate))
537{
538 d->q = this;
539}
540
541SinglePart::~SinglePart()
542{
543
544}
545
546QVector<QByteArray> SinglePart::availableContents() const
547{
548 return QVector<QByteArray>() << d->mType;
549}
550
551QVector< Content::Ptr > SinglePart::content(const QByteArray &ct) const
552{
553 if (ct == d->mType) {
554 return d->mContent;
555 }
556 return QVector<Content::Ptr>();
557}
558
559QByteArray SinglePart::type() const
560{
561 return "SinglePart";
562}
563
564PartPrivate* SinglePart::reachParentD() const
565{
566 return Part::d.get();
567}
568
569class SignaturePrivate
570{
571public:
572 Signature *q;
573};
574
575Signature::Signature()
576 :d(std::unique_ptr<SignaturePrivate>(new SignaturePrivate))
577{
578 d->q = this;
579}
580
581
582Signature::Signature(SignaturePrivate *d_ptr)
583 :d(std::unique_ptr<SignaturePrivate>(d_ptr))
584{
585 d->q = this;
586}
587
588Signature::~Signature()
589{
590
591}
592
593
594class EncryptionPrivate
595{
596public:
597 Encryption *q;
598};
599
600Encryption::Encryption(EncryptionPrivate *d_ptr)
601 :d(std::unique_ptr<EncryptionPrivate>(d_ptr))
602{
603 d->q = this;
604}
605
606Encryption::Encryption()
607 :d(std::unique_ptr<EncryptionPrivate>(new EncryptionPrivate))
608{
609 d->q = this;
610}
611
612Encryption::~Encryption()
613{
614
615}
616
617ParserPrivate::ParserPrivate(Parser* parser)
618 : q(parser)
619 , mNodeHelper(std::make_shared<MimeTreeParser::NodeHelper>())
620{
621
622}
623
624void ParserPrivate::setMessage(const QByteArray& mimeMessage)
625{
626 const auto mailData = KMime::CRLFtoLF(mimeMessage);
627 mMsg = KMime::Message::Ptr(new KMime::Message);
628 mMsg->setContent(mailData);
629 mMsg->parse();
630
631 // render the mail
632 StringHtmlWriter htmlWriter;
633 ObjectTreeSource source(&htmlWriter);
634 MimeTreeParser::ObjectTreeParser otp(&source, mNodeHelper.get());
635
636 otp.parseObjectTree(mMsg.data());
637 mPartTree = otp.parsedPart().dynamicCast<MimeTreeParser::MessagePart>();
638
639 mEmbeddedPartMap = htmlWriter.embeddedParts();
640 mHtml = htmlWriter.html();
641
642 mTree = std::make_shared<Part>();
643 createTree(mPartTree, mTree);
644}
645
646
647void ParserPrivate::createTree(const MimeTreeParser::MessagePart::Ptr &start, const Part::Ptr &tree)
648{
649 foreach (const auto &mp, start->subParts()) {
650 const auto m = mp.dynamicCast<MimeTreeParser::MessagePart>();
651 const auto text = mp.dynamicCast<MimeTreeParser::TextMessagePart>();
652 const auto alternative = mp.dynamicCast<MimeTreeParser::AlternativeMessagePart>();
653 const auto html = mp.dynamicCast<MimeTreeParser::HtmlMessagePart>();
654 const auto attachment = mp.dynamicCast<MimeTreeParser::AttachmentMessagePart>();
655 if (attachment) {
656 auto part = std::make_shared<SinglePart>();
657 part->d->fillFrom(attachment);
658 tree->d->appendSubPart(part);
659 } else if (text) {
660 auto part = std::make_shared<SinglePart>();
661 part->d->fillFrom(text);
662 tree->d->appendSubPart(part);
663 } else if (alternative) {
664 auto part = std::make_shared<AlternativePart>();
665 part->d->fillFrom(alternative);
666 tree->d->appendSubPart(part);
667 } else if (html) {
668 auto part = std::make_shared<SinglePart>();
669 part->d->fillFrom(html);
670 tree->d->appendSubPart(part);
671 } else {
672 const auto enc = mp.dynamicCast<MimeTreeParser::EncryptedMessagePart>();
673 const auto sig = mp.dynamicCast<MimeTreeParser::SignedMessagePart>();
674 if (enc || sig) {
675 auto subTree = std::make_shared<Part>();
676 if (enc) {
677 subTree->d->appendEncryption(enc);
678 }
679 if (sig) {
680 subTree->d->appendSignature(sig);
681 }
682 createTree(m, subTree);
683 foreach(const auto &p, subTree->subParts()) {
684 tree->d->appendSubPart(p);
685 if (enc) {
686 p->d->setEncryptions(subTree->d->encryptions());
687 }
688 if (sig) {
689 p->d->setSignatures(subTree->d->signatures());
690 }
691 }
692 } else {
693 createTree(m, tree);
694 }
695 }
696 }
697}
698
699Parser::Parser(const QByteArray& mimeMessage)
700 :d(std::unique_ptr<ParserPrivate>(new ParserPrivate(this)))
701{
702 d->setMessage(mimeMessage);
703}
704
705Parser::~Parser()
706{
707}
708
709QUrl Parser::getPart(const QByteArray &cid)
710{
711 return d->mEmbeddedPartMap.value(cid);
712}
713
714QVector<Part::Ptr> Parser::collectContentParts() const
715{
716 return collect(d->mTree, [](const Part::Ptr &p){return p->type() != "EncapsulatedPart";},
717 [](const Content::Ptr &content){
718 const auto mime = content->mailMime();
719
720 if (!mime) {
721 return true;
722 }
723
724 if (mime->isFirstTextPart()) {
725 return true;
726 }
727
728 {
729 const auto parent = content->parent();
730 if (parent) {
731 const auto _mime = parent->mailMime();
732 if (_mime && (_mime->isTopLevelPart() || _mime->isFirstTextPart())) {
733 return true;
734 }
735 }
736 }
737 const auto cd = mime->disposition();
738 if (cd && cd == MailMime::Inline) {
739 // explict "inline" disposition:
740 return true;
741 }
742 if (cd && cd == MailMime::Attachment) {
743 // explicit "attachment" disposition:
744 return false;
745 }
746
747 const auto ct = mime->mimetype();
748 if (ct.name().trimmed().toLower() == "text" && ct.name().trimmed().isEmpty() &&
749 (!mime || mime->filename().trimmed().isEmpty())) {
750 // text/* w/o filename parameter:
751 return true;
752 }
753 return false;
754 });
755}
756
757
758QVector<Part::Ptr> Parser::collectAttachmentParts() const
759{
760 return collect(d->mTree, [](const Part::Ptr &p){return p->type() != "EncapsulatedPart";},
761 [](const Content::Ptr &content){
762 const auto mime = content->mailMime();
763
764 if (!mime) {
765 return false;
766 }
767
768 if (mime->isFirstTextPart()) {
769 return false;
770 }
771
772 {
773 const auto parent = content->parent();
774 if (parent) {
775 const auto _mime = parent->mailMime();
776 if (_mime && (_mime->isTopLevelPart() || _mime->isFirstTextPart())) {
777 return false;
778 }
779 }
780 }
781 const auto cd = mime->disposition();
782 if (cd && cd == MailMime::Inline) {
783 // explict "inline" disposition:
784 return false;
785 }
786 if (cd && cd == MailMime::Attachment) {
787 // explicit "attachment" disposition:
788 return true;
789 }
790
791 const auto ct = mime->mimetype();
792 if (ct.name().trimmed().toLower() == "text" && ct.name().trimmed().isEmpty() &&
793 (!mime || mime->filename().trimmed().isEmpty())) {
794 // text/* w/o filename parameter:
795 return false;
796 }
797 return true;
798 });
799}
800QVector<Part::Ptr> Parser::collect(const Part::Ptr &start, std::function<bool(const Part::Ptr &)> select, std::function<bool(const Content::Ptr &)> filter) const
801{
802 QVector<Part::Ptr> ret;
803 foreach (const auto &part, start->subParts()) {
804 QVector<QByteArray> contents;
805 foreach(const auto &ct, part->availableContents()) {
806 foreach(const auto &content, part->content(ct)) {
807 if (filter(content)) {
808 contents.append(ct);
809 break;
810 }
811 }
812 }
813 if (!contents.isEmpty()) {
814 ret.append(part);
815 }
816 if (select(part)){
817 ret += collect(part, select, filter);
818 }
819 }
820 return ret;
821} \ No newline at end of file
diff --git a/framework/domain/mimetreeparser/interface.h b/framework/domain/mimetreeparser/interface.h
new file mode 100644
index 00000000..7eadc311
--- /dev/null
+++ b/framework/domain/mimetreeparser/interface.h
@@ -0,0 +1,368 @@
1/*
2 Copyright (c) 2016 Sandro Knauß <knauss@kolabsystems.com>
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#pragma once
21
22#include <functional>
23#include <memory>
24
25#include <QDateTime>
26#include <QUrl>
27#include <QMimeType>
28
29class Part;
30class PartPrivate;
31
32class MailMime;
33class MailMimePrivate;
34
35class AlternativePart;
36class AlternativePartPrivate;
37
38class SinglePart;
39class SinglePartPrivate;
40
41class EncryptionPart;
42class EncryptionPartPrivate;
43
44class EncapsulatedPart;
45class EncapsulatedPartPrivate;
46
47class Content;
48class ContentPrivate;
49
50class CertContent;
51class CertContentPrivate;
52
53class EncryptionError;
54
55class Key;
56class Signature;
57class SignaturePrivate;
58class Encryption;
59class EncryptionPrivate;
60
61typedef std::shared_ptr<Signature> SignaturePtr;
62typedef std::shared_ptr<Encryption> EncryptionPtr;
63
64class Parser;
65class ParserPrivate;
66
67/*
68 * A MessagePart that is based on a KMime::Content
69 */
70class MailMime
71{
72public:
73 typedef std::shared_ptr<MailMime> Ptr;
74 /**
75 * Various possible values for the "Content-Disposition" header.
76 */
77 enum Disposition {
78 Invalid, ///< Default, invalid value
79 Inline, ///< inline
80 Attachment ///< attachment
81 };
82
83 MailMime();
84
85 // interessting header parts of a KMime::Content
86 QMimeType mimetype() const;
87 Disposition disposition() const;
88 QUrl label() const;
89 QByteArray cid() const;
90 QByteArray charset() const;
91 QString filename() const;
92
93 // Unique identifier to ecactly this KMime::Content
94 QByteArray link() const;
95
96 QByteArray content() const;
97 //Use default charset
98 QString encodedContent() const;
99
100 // overwrite default charset with given charset
101 QString encodedContent(QByteArray charset) const;
102
103 bool isFirstTextPart() const;
104 bool isTopLevelPart() const;
105
106private:
107 std::unique_ptr<MailMimePrivate> d;
108
109 friend class PartPrivate;
110};
111
112class Content
113{
114public:
115 typedef std::shared_ptr<Content> Ptr;
116 Content(const QByteArray &content, Part *parent);
117 Content(ContentPrivate *d_ptr);
118 virtual ~Content();
119
120 QByteArray content() const;
121
122 QByteArray charset() const;
123
124 //Use default charset
125 QString encodedContent() const;
126
127 // overwrite default charset with given charset
128 QString encodedContent(QByteArray charset) const;
129
130 QVector<SignaturePtr> signatures() const;
131 QVector<EncryptionPtr> encryptions() const;
132 MailMime::Ptr mailMime() const;
133 virtual QByteArray type() const;
134 Part* parent() const;
135private:
136 std::unique_ptr<ContentPrivate> d;
137};
138
139class PlainTextContent : public Content
140{
141public:
142 PlainTextContent(const QByteArray &content, Part *parent);
143 PlainTextContent(ContentPrivate *d_ptr);
144 QByteArray type() const Q_DECL_OVERRIDE;
145};
146
147class HtmlContent : public Content
148{
149public:
150 HtmlContent(const QByteArray &content, Part *parent);
151 HtmlContent(ContentPrivate* d_ptr);
152 QByteArray type() const Q_DECL_OVERRIDE;
153};
154
155/*
156 * importing a cert GpgMe::ImportResult
157 * checking a cert (if it is a valid cert)
158 */
159
160class CertContent : public Content
161{
162public:
163 typedef std::shared_ptr<CertContent> Ptr;
164 CertContent(const QByteArray &content, Part *parent);
165
166 QByteArray type() const Q_DECL_OVERRIDE;
167 enum CertType {
168 Pgp,
169 SMime
170 };
171
172 enum CertSubType {
173 Public,
174 Private
175 };
176
177 CertType certType() const;
178 CertSubType certSubType() const;
179 int keyLength() const;
180
181private:
182 std::unique_ptr<CertContentPrivate> d;
183};
184
185class Part
186{
187public:
188 typedef std::shared_ptr<Part> Ptr;
189 Part();
190 virtual QByteArray type() const;
191
192 virtual QVector<QByteArray> availableContents() const;
193 virtual QVector<Content::Ptr> content(const QByteArray& ct) const;
194 QVector<Content::Ptr> content() const;
195
196 bool hasSubParts() const;
197 QVector<Part::Ptr> subParts() const;
198 Part *parent() const;
199
200 QVector<SignaturePtr> signatures() const;
201 QVector<EncryptionPtr> encryptions() const;
202 virtual MailMime::Ptr mailMime() const;
203protected:
204 std::unique_ptr<PartPrivate> d;
205private:
206 friend class ParserPrivate;
207 friend class PartPrivate;
208};
209
210class AlternativePart : public Part
211{
212public:
213 typedef std::shared_ptr<AlternativePart> Ptr;
214
215 AlternativePart();
216 virtual ~AlternativePart();
217
218 QVector<QByteArray> availableContents() const Q_DECL_OVERRIDE;
219 QVector<Content::Ptr> content(const QByteArray& ct) const Q_DECL_OVERRIDE;
220
221 QByteArray type() const Q_DECL_OVERRIDE;
222
223private:
224 PartPrivate *reachParentD() const;
225 std::unique_ptr<AlternativePartPrivate> d;
226
227 friend class ParserPrivate;
228 friend class AlternativePartPrivate;
229};
230
231class SinglePart : public Part
232{
233 public:
234 typedef std::shared_ptr<SinglePart> Ptr;
235
236 SinglePart();
237 virtual ~SinglePart();
238
239 QVector<Content::Ptr> content(const QByteArray& ct) const Q_DECL_OVERRIDE;
240 QVector<QByteArray> availableContents() const Q_DECL_OVERRIDE;
241
242 QByteArray type() const Q_DECL_OVERRIDE;
243private:
244 PartPrivate *reachParentD() const;
245 std::unique_ptr<SinglePartPrivate> d;
246
247 friend class ParserPrivate;
248 friend class SinglePartPrivate;
249};
250
251
252class EncryptionPart : public Part
253{
254public:
255 typedef std::shared_ptr<EncryptionPart> Ptr;
256 QByteArray type() const Q_DECL_OVERRIDE;
257
258 EncryptionError error() const;
259private:
260 std::unique_ptr<EncryptionPartPrivate> d;
261};
262
263
264/*
265 * we want to request complete headers like:
266 * from/to...
267 */
268
269class EncapsulatedPart : public SinglePart
270{
271public:
272 typedef std::shared_ptr<EncapsulatedPart> Ptr;
273 QByteArray type() const Q_DECL_OVERRIDE;
274
275 //template <class T> QByteArray header<T>();
276private:
277 std::unique_ptr<EncapsulatedPartPrivate> d;
278};
279
280class EncryptionError
281{
282public:
283 int errorId() const;
284 QString errorString() const;
285};
286
287class Key
288{
289 QString keyid() const;
290 QString name() const;
291 QString email() const;
292 QString comment() const;
293 QVector<QString> emails() const;
294 enum KeyTrust {
295 Unknown, Undefined, Never, Marginal, Full, Ultimate
296 };
297 KeyTrust keyTrust() const;
298
299 bool isRevokation() const;
300 bool isInvalid() const;
301 bool isExpired() const;
302
303 std::vector<Key> subkeys();
304 Key parentkey() const;
305};
306
307class Signature
308{
309public:
310 typedef std::shared_ptr<Signature> Ptr;
311 Signature();
312 Signature(SignaturePrivate *);
313 ~Signature();
314
315 Key key() const;
316 QDateTime creationDateTime() const;
317 QDateTime expirationTime() const;
318 bool neverExpires() const;
319
320 //template <> StatusObject<SignatureVerificationResult> verify() const;
321 private:
322 std::unique_ptr<SignaturePrivate> d;
323};
324
325/*
326 * Normally the Keys for encryption are subkeys
327 * for clients the parentkeys are "more interessting", because they store the name, email etc.
328 * but a client may also wants show to what subkey the mail is really encrypted, an if this subkey isRevoked or something else
329 */
330class Encryption
331{
332public:
333 typedef std::shared_ptr<Encryption> Ptr;
334 Encryption();
335 Encryption(EncryptionPrivate *);
336 ~Encryption();
337 std::vector<Key> recipients() const;
338private:
339 std::unique_ptr<EncryptionPrivate> d;
340};
341
342class Parser
343{
344public:
345 typedef std::shared_ptr<Parser> Ptr;
346 Parser(const QByteArray &mimeMessage);
347 ~Parser();
348
349 Part::Ptr getPart(QUrl url);
350 QUrl getPart(const QByteArray &cid);
351
352 QVector<Part::Ptr> collect(const Part::Ptr &start, std::function<bool(const Part::Ptr &)> select, std::function<bool(const Content::Ptr &)> filter) const;
353 QVector<Part::Ptr> collectContentParts() const;
354 QVector<Part::Ptr> collectAttachmentParts() const;
355 //template <> QVector<ContentPart::Ptr> collect<ContentPart>() const;
356
357 //template <> static StatusObject<SignatureVerificationResult> verifySignature(const Signature signature) const;
358 //template <> static StatusObject<Part> decrypt(const EncryptedPart part) const;
359
360signals:
361 void partsChanged();
362
363private:
364 std::unique_ptr<ParserPrivate> d;
365
366 friend class InterfaceTest;
367};
368
diff --git a/framework/domain/mimetreeparser/interface_p.h b/framework/domain/mimetreeparser/interface_p.h
new file mode 100644
index 00000000..55d1a5cc
--- /dev/null
+++ b/framework/domain/mimetreeparser/interface_p.h
@@ -0,0 +1,56 @@
1/*
2 Copyright (c) 2016 Sandro Knauß <knauss@kolabsystems.com>
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#pragma once
21
22#include "interface.h"
23
24#include <QSharedPointer>
25#include <QMap>
26
27namespace KMime
28{
29 class Message;
30 typedef QSharedPointer<Message> MessagePtr;
31}
32
33namespace MimeTreeParser
34{
35 class MessagePart;
36 class NodeHelper;
37 typedef QSharedPointer<MessagePart> MessagePartPtr;
38}
39
40class ParserPrivate
41{
42public:
43 ParserPrivate(Parser *parser);
44
45 void setMessage(const QByteArray &mimeMessage);
46 void createTree(const MimeTreeParser::MessagePartPtr& start, const Part::Ptr& tree);
47
48 Part::Ptr mTree;
49 Parser *q;
50
51 MimeTreeParser::MessagePartPtr mPartTree;
52 KMime::MessagePtr mMsg;
53 std::shared_ptr<MimeTreeParser::NodeHelper> mNodeHelper;
54 QString mHtml;
55 QMap<QByteArray, QUrl> mEmbeddedPartMap;
56}; \ No newline at end of file
diff --git a/framework/domain/mimetreeparser/objecttreesource.cpp b/framework/domain/mimetreeparser/objecttreesource.cpp
new file mode 100644
index 00000000..58667444
--- /dev/null
+++ b/framework/domain/mimetreeparser/objecttreesource.cpp
@@ -0,0 +1,147 @@
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
22#include <MimeTreeParser/AttachmentStrategy>
23#include <MimeTreeParser/BodyPartFormatterBaseFactory>
24#include <MimeTreeParser/MessagePart>
25#include <MimeTreeParser/MessagePartRenderer>
26
27class ObjectSourcePrivate
28{
29public:
30 ObjectSourcePrivate()
31 : mWriter(0)
32 , mAllowDecryption(true)
33 , mHtmlLoadExternal(true)
34 , mPreferredMode(MimeTreeParser::Util::Html)
35 {
36
37 }
38 MimeTreeParser::HtmlWriter *mWriter;
39 MimeTreeParser::BodyPartFormatterBaseFactory mBodyPartFormatterBaseFactory;
40 bool mAllowDecryption;
41 bool mHtmlLoadExternal;
42 MimeTreeParser::Util::HtmlMode mPreferredMode;
43};
44
45ObjectTreeSource::ObjectTreeSource(MimeTreeParser::HtmlWriter *writer)
46 : MimeTreeParser::Interface::ObjectTreeSource()
47 , d(new ObjectSourcePrivate)
48 {
49 d->mWriter = writer;
50 }
51
52ObjectTreeSource::~ObjectTreeSource()
53{
54 delete d;
55}
56
57void ObjectTreeSource::setAllowDecryption(bool allowDecryption)
58{
59 d->mAllowDecryption = allowDecryption;
60}
61
62MimeTreeParser::HtmlWriter *ObjectTreeSource::htmlWriter()
63{
64 return d->mWriter;
65}
66
67bool ObjectTreeSource::htmlLoadExternal() const
68{
69 return d->mHtmlLoadExternal;
70}
71
72void ObjectTreeSource::setHtmlLoadExternal(bool loadExternal)
73{
74 d->mHtmlLoadExternal = loadExternal;
75}
76
77bool ObjectTreeSource::decryptMessage() const
78{
79 return d->mAllowDecryption;
80}
81
82bool ObjectTreeSource::showSignatureDetails() const
83{
84 return true;
85}
86
87int ObjectTreeSource::levelQuote() const
88{
89 return 1;
90}
91
92const QTextCodec *ObjectTreeSource::overrideCodec()
93{
94 return Q_NULLPTR;
95}
96
97QString ObjectTreeSource::createMessageHeader(KMime::Message *message)
98{
99 return QString();
100}
101
102const MimeTreeParser::AttachmentStrategy *ObjectTreeSource::attachmentStrategy()
103{
104 return MimeTreeParser::AttachmentStrategy::smart();
105}
106
107QObject *ObjectTreeSource::sourceObject()
108{
109 return Q_NULLPTR;
110}
111
112void ObjectTreeSource::setHtmlMode(MimeTreeParser::Util::HtmlMode mode, const QList<MimeTreeParser::Util::HtmlMode> &availableModes)
113{
114 Q_UNUSED(mode);
115 Q_UNUSED(availableModes);
116}
117
118MimeTreeParser::Util::HtmlMode ObjectTreeSource::preferredMode() const
119{
120 return d->mPreferredMode;
121}
122
123bool ObjectTreeSource::autoImportKeys() const
124{
125 return false;
126}
127
128bool ObjectTreeSource::showEmoticons() const
129{
130 return false;
131}
132
133bool ObjectTreeSource::showExpandQuotesMark() const
134{
135 return false;
136}
137
138const MimeTreeParser::BodyPartFormatterBaseFactory *ObjectTreeSource::bodyPartFormatterFactory()
139{
140 return &(d->mBodyPartFormatterBaseFactory);
141}
142
143MimeTreeParser::Interface::MessagePartRenderer::Ptr ObjectTreeSource::messagePartTheme(MimeTreeParser::Interface::MessagePart::Ptr msgPart)
144{
145 Q_UNUSED(msgPart);
146 return MimeTreeParser::Interface::MessagePartRenderer::Ptr();
147}
diff --git a/framework/domain/mimetreeparser/objecttreesource.h b/framework/domain/mimetreeparser/objecttreesource.h
new file mode 100644
index 00000000..42433e71
--- /dev/null
+++ b/framework/domain/mimetreeparser/objecttreesource.h
@@ -0,0 +1,56 @@
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 MAILVIEWER_OBJECTTREEEMPTYSOURCE_H
21#define MAILVIEWER_OBJECTTREEEMPTYSOURCE_H
22
23#include <MimeTreeParser/ObjectTreeSource>
24
25class QString;
26
27class ObjectSourcePrivate;
28class ObjectTreeSource : public MimeTreeParser::Interface::ObjectTreeSource
29{
30public:
31 ObjectTreeSource(MimeTreeParser::HtmlWriter *writer);
32 virtual ~ObjectTreeSource();
33 void setHtmlLoadExternal(bool loadExternal);
34 bool decryptMessage() const Q_DECL_OVERRIDE;
35 bool htmlLoadExternal() const Q_DECL_OVERRIDE;
36 bool showSignatureDetails() const Q_DECL_OVERRIDE;
37 void setHtmlMode(MimeTreeParser::Util::HtmlMode mode, const QList<MimeTreeParser::Util::HtmlMode> &availableModes) Q_DECL_OVERRIDE;
38 MimeTreeParser::Util::HtmlMode preferredMode() const Q_DECL_OVERRIDE;
39 void setAllowDecryption(bool allowDecryption);
40 int levelQuote() const Q_DECL_OVERRIDE;
41 const QTextCodec *overrideCodec() Q_DECL_OVERRIDE;
42 QString createMessageHeader(KMime::Message *message) Q_DECL_OVERRIDE;
43 const MimeTreeParser::AttachmentStrategy *attachmentStrategy() Q_DECL_OVERRIDE;
44 MimeTreeParser::HtmlWriter *htmlWriter() Q_DECL_OVERRIDE;
45 QObject *sourceObject() Q_DECL_OVERRIDE;
46 bool autoImportKeys() const Q_DECL_OVERRIDE;
47 bool showEmoticons() const Q_DECL_OVERRIDE;
48 bool showExpandQuotesMark() const Q_DECL_OVERRIDE;
49 const MimeTreeParser::BodyPartFormatterBaseFactory *bodyPartFormatterFactory() Q_DECL_OVERRIDE;
50 MimeTreeParser::Interface::MessagePartRendererPtr messagePartTheme(MimeTreeParser::Interface::MessagePartPtr msgPart) Q_DECL_OVERRIDE;
51private:
52 ObjectSourcePrivate *const d;
53};
54
55#endif
56
diff --git a/framework/domain/mimetreeparser/stringhtmlwriter.cpp b/framework/domain/mimetreeparser/stringhtmlwriter.cpp
new file mode 100644
index 00000000..88034492
--- /dev/null
+++ b/framework/domain/mimetreeparser/stringhtmlwriter.cpp
@@ -0,0 +1,150 @@
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 "stringhtmlwriter.h"
33
34#include <QDebug>
35#include <QTextStream>
36#include <QUrl>
37
38StringHtmlWriter::StringHtmlWriter()
39 : MimeTreeParser::HtmlWriter()
40 , mState(Ended)
41{
42}
43
44StringHtmlWriter::~StringHtmlWriter()
45{
46}
47
48void StringHtmlWriter::begin(const QString &css)
49{
50 if (mState != Ended) {
51 qWarning() << "begin() called on non-ended session!";
52 reset();
53 }
54
55 mState = Begun;
56 mExtraHead.clear();
57 mHtml.clear();
58
59 if (!css.isEmpty()) {
60 write(QLatin1String("<!-- CSS Definitions \n") + css + QLatin1String("-->\n"));
61 }
62}
63
64void StringHtmlWriter::end()
65{
66 if (mState != Begun) {
67 qWarning() << "Called on non-begun or queued session!";
68 }
69
70 if (!mExtraHead.isEmpty()) {
71 insertExtraHead();
72 mExtraHead.clear();
73 }
74 resolveCidUrls();
75 mState = Ended;
76}
77
78void StringHtmlWriter::reset()
79{
80 if (mState != Ended) {
81 mHtml.clear();
82 mExtraHead.clear();
83 mState = Begun; // don't run into end()'s warning
84 end();
85 mState = Ended;
86 }
87}
88
89void StringHtmlWriter::write(const QString &str)
90{
91 if (mState != Begun) {
92 qWarning() << "Called in Ended or Queued state!";
93 }
94 mHtml.append(str);
95}
96
97void StringHtmlWriter::queue(const QString &str)
98{
99 write(str);
100}
101
102void StringHtmlWriter::flush()
103{
104 mState = Begun; // don't run into end()'s warning
105 end();
106}
107
108void StringHtmlWriter::embedPart(const QByteArray &contentId, const QString &url)
109{
110 write("<!-- embedPart(contentID=" + contentId + ", url=" + url + ") -->\n");
111 mEmbeddedPartMap.insert(contentId, url);
112}
113
114void StringHtmlWriter::resolveCidUrls()
115{
116 for (const auto &cid : mEmbeddedPartMap.keys()) {
117 mHtml.replace(QString("src=\"cid:%1\"").arg(QString(cid)), QString("src=\"%1\"").arg(mEmbeddedPartMap.value(cid).toString()));
118 }
119}
120
121void StringHtmlWriter::extraHead(const QString &extraHead)
122{
123 if (mState != Ended) {
124 qWarning() << "Called on non-started session!";
125 }
126 mExtraHead.append(extraHead);
127}
128
129
130void StringHtmlWriter::insertExtraHead()
131{
132 const QString headTag(QStringLiteral("<head>"));
133 const int index = mHtml.indexOf(headTag);
134 if (index != -1) {
135 mHtml.insert(index + headTag.length(), mExtraHead);
136 }
137}
138
139QMap<QByteArray, QUrl> StringHtmlWriter::embeddedParts() const
140{
141 return mEmbeddedPartMap;
142}
143
144QString StringHtmlWriter::html() const
145{
146 if (mState != Ended) {
147 qWarning() << "Called on non-ended session!";
148 }
149 return mHtml;
150}
diff --git a/framework/domain/mimetreeparser/stringhtmlwriter.h b/framework/domain/mimetreeparser/stringhtmlwriter.h
new file mode 100644
index 00000000..fa5b760e
--- /dev/null
+++ b/framework/domain/mimetreeparser/stringhtmlwriter.h
@@ -0,0 +1,71 @@
1/* -*- c++ -*-
2
3 Copyright (c) 2016 Sandro Knauß <sknauss@kde.org>
4
5 Kube is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License, version 2, as
7 published by the Free Software Foundation.
8
9 Kube is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 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 In addition, as a special exception, the copyright holders give
19 permission to link the code of this program with any edition of
20 the Qt library by Trolltech AS, Norway (or with modified versions
21 of Qt that use the same license as Qt), and distribute linked
22 combinations including the two. You must obey the GNU General
23 Public License in all respects for all of the code used other than
24 Qt. If you modify this file, you may extend this exception to
25 your version of the file, but you are not obligated to do so. If
26 you do not wish to do so, delete this exception statement from
27 your version.
28*/
29
30#ifndef __KUBE_FRAMEWORK_MAIL_STRINGHTMLWRITER_H__
31#define __KUBE_FRAMEWORK_MAIL_STRINGHTMLWRITER_H__
32
33#include <MimeTreeParser/HtmlWriter>
34
35#include <QFile>
36#include <QTextStream>
37
38class QString;
39
40class StringHtmlWriter : public MimeTreeParser::HtmlWriter
41{
42public:
43 explicit StringHtmlWriter();
44 virtual ~StringHtmlWriter();
45
46 void begin(const QString &cssDefs) Q_DECL_OVERRIDE;
47 void end() Q_DECL_OVERRIDE;
48 void reset() Q_DECL_OVERRIDE;
49 void write(const QString &str) Q_DECL_OVERRIDE;
50 void queue(const QString &str) Q_DECL_OVERRIDE;
51 void flush() Q_DECL_OVERRIDE;
52 void embedPart(const QByteArray &contentId, const QString &url) Q_DECL_OVERRIDE;
53 void extraHead(const QString &str) Q_DECL_OVERRIDE;
54
55 QString html() const;
56 QMap<QByteArray, QUrl> embeddedParts() const;
57private:
58 void insertExtraHead();
59 void resolveCidUrls();
60
61 QString mHtml;
62 QString mExtraHead;
63 enum State {
64 Begun,
65 Queued,
66 Ended
67 } mState;
68 QMap<QByteArray, QUrl> mEmbeddedPartMap;
69};
70
71#endif // __MESSAGEVIEWER_FILEHTMLWRITER_H__
diff --git a/framework/domain/mimetreeparser/tests/CMakeLists.txt b/framework/domain/mimetreeparser/tests/CMakeLists.txt
new file mode 100644
index 00000000..7945c5a0
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/CMakeLists.txt
@@ -0,0 +1,12 @@
1add_subdirectory(gnupg_home)
2add_definitions( -DMAIL_DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data" )
3include(${CMAKE_CURRENT_SOURCE_DIR}/kdepim_add_gpg_crypto_test.cmake)
4include_directories(
5 ${CMAKE_CURRENT_BINARY_DIR}
6 ${CMAKE_CURRENT_SOURCE_DIR}/..
7 )
8
9add_executable(mimetreeparsertest interfacetest.cpp)
10add_gpg_crypto_test(mimetreeparsertest mimetreeparsertest)
11qt5_use_modules(mimetreeparsertest Core Test)
12target_link_libraries(mimetreeparsertest mimetreeparser)
diff --git a/framework/domain/mimetreeparser/tests/data/alternative.mbox b/framework/domain/mimetreeparser/tests/data/alternative.mbox
new file mode 100644
index 00000000..6522c34b
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/data/alternative.mbox
@@ -0,0 +1,28 @@
1Return-Path: <konqi@example.org>
2Date: Wed, 8 Jun 2016 20:34:44 -0700
3From: Konqi <konqi@example.org>
4To: konqi@kde.org
5Subject: A random subject with alternative contenttype
6MIME-Version: 1.0
7Content-Type: multipart/alternative;
8 boundary="----=_Part_12345678_12345678"
9
10
11------=_Part_12345678_12345678
12Content-Type: text/plain; charset=utf-8
13Content-Transfer-Encoding: quoted-printable
14
15If you can see this text it means that your email client couldn't display o=
16ur newsletter properly.
17Please visit this link to view the newsletter on our website: http://www.go=
18g.com/newsletter/
19
20
21------=_Part_12345678_12345678
22Content-Transfer-Encoding: 7Bit
23Content-Type: text/html; charset="windows-1252"
24
25<html><body><p><span>HTML</span> text</p></body></html>
26
27
28------=_Part_12345678_12345678--
diff --git a/framework/domain/mimetreeparser/tests/data/html.mbox b/framework/domain/mimetreeparser/tests/data/html.mbox
new file mode 100644
index 00000000..bf5c685d
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/data/html.mbox
@@ -0,0 +1,15 @@
1From foo@example.com Thu, 26 May 2011 01:16:54 +0100
2From: Thomas McGuire <foo@example.com>
3Subject: HTML test
4Date: Thu, 26 May 2011 01:16:54 +0100
5Message-ID: <1501334.pROlBb7MZF@herrwackelpudding.localhost>
6X-KMail-Transport: GMX
7X-KMail-Fcc: 28
8X-KMail-Drafts: 7
9X-KMail-Templates: 9
10User-Agent: KMail/4.6 beta5 (Linux/2.6.34.7-0.7-desktop; KDE/4.6.41; x86_64; git-0269848; 2011-04-19)
11MIME-Version: 1.0
12Content-Transfer-Encoding: 7Bit
13Content-Type: text/html; charset="windows-1252"
14
15<html><body><p><span>HTML</span> text</p></body></html> \ No newline at end of file
diff --git a/framework/domain/mimetreeparser/tests/data/openpgp-encrypted-attachment-and-non-encrypted-attachment.mbox b/framework/domain/mimetreeparser/tests/data/openpgp-encrypted-attachment-and-non-encrypted-attachment.mbox
new file mode 100644
index 00000000..2d9726ea
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/data/openpgp-encrypted-attachment-and-non-encrypted-attachment.mbox
@@ -0,0 +1,115 @@
1From test@kolab.org Fri May 01 15:12:47 2015
2From: testkey <test@kolab.org>
3To: you@you.com
4Subject: enc & non enc attachment
5Date: Fri, 01 May 2015 17:12:47 +0200
6Message-ID: <13897561.XENKdJMSlR@tabin.local>
7X-KMail-Identity: 1197256126
8User-Agent: KMail/4.13.0.1 (Linux/3.19.1-towo.1-siduction-amd64; KDE/4.14.2; x86_64; git-cd33034; 2015-04-11)
9MIME-Version: 1.0
10Content-Type: multipart/mixed; boundary="nextPart1939768.sIoLGH0PD8"
11Content-Transfer-Encoding: 7Bit
12
13This is a multi-part message in MIME format.
14
15--nextPart1939768.sIoLGH0PD8
16Content-Type: multipart/encrypted; boundary="nextPart2814166.CHKktCGlQ3"; protocol="application/pgp-encrypted"
17
18
19--nextPart2814166.CHKktCGlQ3
20Content-Type: application/pgp-encrypted
21Content-Disposition: attachment
22Content-Transfer-Encoding: 7Bit
23
24Version: 1
25--nextPart2814166.CHKktCGlQ3
26Content-Type: application/octet-stream
27Content-Disposition: inline; filename="msg.asc"
28Content-Transfer-Encoding: 7Bit
29
30-----BEGIN PGP MESSAGE-----
31Version: GnuPG v2
32
33hIwDGJlthTT7oq0BA/9cXFQ6mN9Vxnc2B9M10odS3/6z1tsIY9oJdsiOjpfxqapX
34P7nOzR/jNWdFQanXoG1SjAcY2FeZEN0c3SkxEM6R5QVF1vMh/Xsni1clI+peZyVT
35Z4OSU74YCfYLg+cgDnPCF3kyNPVe6Z1pnfWOCZNCG3rpApw6UVLN63ScWC6eQIUB
36DAMMzkNap8zaOwEIANKHn1svvj+hBOIZYf8R+q2Bw7cd4xEChiJ7uQLnD98j0Fh1
3785v7/8JbZx6rEDDenPp1mCciDodb0aCmi0XLuzJz2ANGTVflfq+ZA+v1pwLksWCs
380YcHLEjOJzjr3KKmvu6wqnun5J2yV69K3OW3qTTGhNvcYZulqQ617pPa48+sFCgh
39nM8TMAD0ElVEwmMtrS3AWoJz52Af+R3YzpAnX8NzV317/JG+b6e2ksl3tR7TWp1q
402FOqC1sXAxuv+DIz4GgRfaK1+xYr2ckkg+H/3HJqa5LmJ7rGCyv+Epfp9u+OvdBG
41PBvuCtO3tm0crmnttMw57Gy35BKutRf/8MpBj/nS6QFX0t7XOLeL4Me7/a2H20wz
42HZsuRGDXMCh0lL0FYCBAwdbbYvvy0gz/5iaNvoADtaIu+VtbFNrTUN0SwuL+AIFS
43+WIiaSbFt4Ng3t9YmqL6pqB7fjxI10S+PK0s7ABqe4pgbzUWWt1yzBcxfk8l/47Q
44JrlvcE7HuDOhNOHfZIgUP2Dbeu+pVvHIJbmLsNWpl4s+nHhoxc9HrVhYG/MTZtQ3
45kkUWviegO6mwEZjQvgBxjWib7090sCxkO847b8A93mfQNHnuy2ZEEJ+9xyk7nIWs
464RsiNR8pYc/SMvdocyAvQMH/qSvmn/IFJ+jHhtT8UJlXJ0bHvXTHjHMqBp6fP69z
47Jh1ERadWQdMaTkzQ+asl+kl/x3p6RZP8MEVbZIl/3pcV+xiFCYcFu2TETKMtbW+b
48NYOlrltFxFDvyu3WeNNp0g9k0nFpD/T1OXHRBRcbUDWE4QF6NWTm6NO9wy2UYHCi
497QTSecBWgMaw7cUdwvnW6chIVoov1pm69BI9D0PoV76zCI7KzpiDsTFxdilKwbQf
50K/PDnv9Adx3ERh0/F8llBHrj2UGsRs4aHSEBDBJIHDCp8+lqtsRcINQBKEU3qIjt
51wf5vizdaVIgQnsD2z8QmBQ7QCCipI0ur6GKl+YWDDOSDLDUs9dK4A6xo/4Q0bsnI
52rH63ti5HslGq6uArfFkewH2MWff/8Li3uGEqzpK5NhP5UpbArelK+QaQQP5SdsmW
53XFwUqDS4QTCKNJXw/5SQMl8UE10l2Xaav3TkiOYTcBcvPNDovYgnMyRff/tTeFa8
5483STkvpGtkULkCntp22fydv5rg6DZ7eJrYfC2oZXdM87hHhUALUO6Y/VtVmNdNYw
55F3Uim4PDuLIKt+mFqRtFqnWm+5X/AslC31qLkjH+Fbb83TY+mC9gbIn7CZGJRCjn
56zzzMX2h15V/VHzNUgx9V/h28T0/z25FxoozZiJxpmhOtqoxMHp+y6nXXfMoIAD1D
57963Pc7u1HS0ny54A7bqc6KKd4W9IF7HkXn3SoBwCyn0IOPoKQTDD8mW3lbBI6+h9
58vP+MAQpfD8s+3VZ9r7OKYCVmUv47ViTRlf428Co6WT7rTHjGM09tqz826fTOXA==
59=6Eu9
60-----END PGP MESSAGE-----
61
62--nextPart2814166.CHKktCGlQ3--
63
64--nextPart1939768.sIoLGH0PD8
65Content-Disposition: attachment; filename="image.png"
66Content-Transfer-Encoding: base64
67Content-Type: image/png; name="image.png"
68
69iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAlwSFlzAAAb
70rwAAG68BXhqRHAAAAAd0SU1FB9gHFg8aNG8uqeIAAAAGYktHRAD/AP8A/6C9p5MAAAkqSURBVHja
715VV7cFTVGf/OPefeu3fv3t1NdhMSCHkKASEpyEsaGwalWEWntLV1Wu0fdOxAx9Iq0xntAwac6ehY
72p+rwKLbjjLRFh9JadURKRGgFQTTECCYQE9nNgzzYZDe7m33d1+l3tpOOU61T2tF/+s1s7pzn9/t+
73v993Av/3QT6FO6WdO/d+M55Il8rMOdrT0x3Zt++3+c8EgM/nozseeviJiYmpe1zOQdM8BOOCIku/
74lIj1VrQ/0r9n9+78xwLgeAA3w4fHXV1d5Omnn6aapumlJSVVqalUJJvJZRdcu0RSfZQsaW7mjfPm
75cbF9+/btEIlEaq6Z03whXyhIjDFuGIZEKSP5fMFRVcVNT2Vf0jzsmMxYGtel9rff/vM/M8bjcZpM
76Jp1XX32VNDc3e7ovRP3JyZGVNdXVd1FGGwKBQEM8njiWTKV36IHgEACwibGx62LjU/cBd01Zljoc
77p9DHmLbHsmyK1UuKooJt24IMcLE+y3L45eEYLS8LgWH4YXR0bAPZtGmTVFvfoBZMEzKpFKmqqmqp
78qane4DhOteH3L1FkWZVlGSzLAtd1Oe4773C4LxoZvDWXh82OY2MtwAuFvCvSyDIFXdelYDDIvF4d
79xPzA0AgXFStMcWPxBPGoKvXpPh6JDG5hK1Zcv1H36Xc6tsMs21EMQ69CLSts2wGkDygTyW2CP8gX
80TKLIyvx0OrdDUXyLKXVUkdSne4QKtFAwuWmabjAYkDyqAgG/jziORh1EKaonkkQt2yRZRC5JHEGn
81L7OKyopNqqo2IbWQjqWgLOwFBFKsuGDa4PVyIssMk1sCACCjimXbrbquYKW41zJJOpXkeARyeZNQ
82SUKwHEqCKnBuAybkZeFSmssVSDKdhlBpCRgIcnQsdvKPB19sY4rMNIaH0BhQUVHKvXgpIiQF0wK/
834QORnOEayoDzOSBMXK4BSgpeTcMECqiqTDKZHDKmct3LCI55Kp0mQgK/3yDYkgIc3kNhfHzCkRk9
84p6nk+yPD3SmWzeZiKNkciUrg2g5BjQWdSBchiEvQjzoWAFkUYPDrCjBFUEJ8AhSIRyl2jcfjEL9h
85AFJODL8B6H7IZrNIt2g3B1mysShdQhmbT58+ExRdx3L5/PNomGU4kJkuA9ILYn+JP4CXOoDUoWO9
86IBhCSBCLTYCK+rqOg8CKvY6JPQhGxjkX1zyAdwrgAhTKWBDmxTUTC7Tcy5dHBiilL7cdaTsNGAwP
877o32D4Q9HnWTrvsCiqIgdWgqDkJfkKgDU1MZcBGMhbKgj2B0LIle8eNhgiBsoMwFEY7rQDqVwlo5
88esUE/AAR81gUYIUT8UR2//4/rK+pLjs3MhIFEVJN9WwXK2oM+P1BREpQO0hjwkw+BzJWY1oOXB5L
89w9DIOGTQvYS4UFqigR9ZwUqEXFghVop059AjonqcAIZrqCKg31AS3OU66Adf4sabWqKvvHIYpoNh
90y+Vj4xMHVEW93eUuo0izhT4oRbcSIoALbRle4AVVkfBup6g9thwCzRX1VRQmdMeqLVETEIkW2ZNx
91H8oqzqAfXCGJEQ6XBQEgNQ2A7tq1C1a1tvaattOOrVFOqVSLCQhqU6QPx+DTsOU0GavLYUV20Qv4
92rEIymYNQuB48Wkg8QTA0NIQeYKB6NGTgH90jIcJEMikAi1dRRo9NLV583ek33jjpFAGIPw8++IAj
93e9SIRGm5wliraVosnTWLmmemUugBkTiPSS3AtgV8VQA9A8LxdfULYXBoEKv2wMhIn2BHGFR0DZ6d
94glQ6hUDT6A/RWVSSmfx5DjxRV1vzVkdHBzDAWLNmDezc+aQVqqz5dSY52Z63nLn9A33lI9myLXNL
95xv0Fq3gWutMN0BToxcso+AN+cKmOXI5A9P12mKDzYNXcZXDq1F+h+IboFgzb1VAhDULeJpxwC19G
96g/uMgOXVfXW1tbWCYM6mtdi8+YfiM4m/Y1UrHzkergyXz/3czImCnRjuHiW3qxpPqGFPy6SpHJC9
97IR+Sm+2N8i/dcMOMZdGeshcrS/S58+c3zU2Z8oVD50cbVfP8M4pGkymoUxLxsUzOVhtmQ+5432Rg
98oj6QOLFj28/caQk+EjMXraUV1eW+8dH06StQZnlnNbQefGTD92pWfu3I6TOT8oY7brv4hWUt3xiw
992OrlDVVdRslsd2Fd469Q8sUB3c8uOW49SdHX1rbcePhoz3B7feuqlt5oZtBTv+ioSdXc7q3fHQaM
100fwtg6Vd/dEvn8Qssnzg/0Ns56jRcO6Nw4d1Af+/RH0/cdv+O/fRK7KnmBXPWGsQeDPhK9oWC6hdd
101R3pdUcg88Tx7U7Ej1y1qMjreGwjt/cnaF2YtvCXQe7bzxLkj+/sunT0Ry00OwHRI8DERLqeNmqGV
102JZJVC6Yu7UxMOfLFlV9pWQcYp57/013rb1u9ua29b0Ch4bsl4tKLY5P1sgxNJzsHDj136KzS3NTk
1039mTNusPvXJLrbnjUe/b16FDfsZ/3xC8d4/HoCQ4Anwzg91vWPL7+3pvvDM806sTY4IVyMxfrojO3
104BVubbyJMhnVVM3y+l187/nChIJ2ZpSs9hMD4qC6t6x6+0gkAoRC33/Sb8RdmXj9nzvWraivhP47g
105AyHxKb1mfWkRYHCjMb30nafeeWzerU9963w3L3/02c4f7D0y0NXTx3f3D/JTb7bzxpeODu55+PGT
106yy5F+ZmeD/iSrh5efeJd/hGZP5GBux+6cysY3w7H+16IVy65V6trnn3P9JqVjQ3JuSsdHhWW6hIL
107NuhyUpJgEF/ofSVBeLBuVtVjd3y55SHXhQ8UBht0DR4r98Fs+IRg/zrxlz2/2A7p5yYBY93Gu+4f
108H5xojLwOxfjd/WufOHhQ/IcD7eYVC5YyCjFMfkVV4NpMFvpTachoZeDaNryLnliOczsUCv1XBWD8
109YjF5MWJ9kcT757qenR7vf4bDoqWwHCvUUfPNsQQMWSZAZTlsw7nxYQQTcuDrjgQuPn7z/D7YivNt
110nPPfEDzwqcU75/j6SD/f8uG5vXs5dL7Hjb+d4gp8mnF8nAOabjcac+OBAxyuNiT4HyNwGZYgu0RW
111IDt/Icz4zAC0tXE4183rQ6XwU9uBXgLQ5Teg7GIv1+EqgsF/GY4DtCQALZMp2ITttmqoHzpWr756
112o/0d59+Lh3Y1HHcAAAAASUVORK5CYII=
113
114--nextPart1939768.sIoLGH0PD8--
115
diff --git a/framework/domain/mimetreeparser/tests/data/openpgp-inline-charset-encrypted.mbox b/framework/domain/mimetreeparser/tests/data/openpgp-inline-charset-encrypted.mbox
new file mode 100644
index 00000000..8bd06910
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/data/openpgp-inline-charset-encrypted.mbox
@@ -0,0 +1,40 @@
1From test@example.com Thu, 17 Oct 2013 02:13:03 +0200
2Return-Path: <test@example.com>
3Delivered-To: you@you.com
4Received: from localhost (localhost [127.0.0.1])
5 by test@example.com (Postfix) with ESMTP id B30D8120030
6 for <you@you.com>; Thu, 17 Oct 2013 02:13:05 +0200 (CEST)
7From: test <test@example.com>
8To: you@you.com
9Subject: charset
10Date: Thu, 17 Oct 2013 02:13:03 +0200
11Message-ID: <4081645.yGjUJ4o4Se@example.local>
12User-Agent: KMail/4.12 pre (Linux/3.11-4.towo-siduction-amd64; KDE/4.11.2; x86_64; git-f7f14e3; 2013-10-15)
13MIME-Version: 1.0
14Content-Transfer-Encoding: 7Bit
15Content-Type: text/plain; charset="ISO-8859-15"
16
17-----BEGIN PGP MESSAGE-----
18Version: GnuPG v2.0.22 (GNU/Linux)
19
20hIwDGJlthTT7oq0BBACbaRZudMigMTetPZNRgkfEXv4QQowR1jborw0dcgKKqMQ1
216o67NkpxvmXKGJTfTVCLBX3nk6FKYo6NwlPCyU7X9X0DDk8hvaBdR9wGfrdm5YWX
22GKOzcqJY1EypiMsspXeZvjzEW7O8I956c3vBb/2pM3xqYEK1kh8+d9bVH+cjf4UB
23DAMMzkNap8zaOwEH/1rPShyYL8meJN+/GGgS8+Nf1BW5pSHdAPCg0dnX4QCLEx7u
24GkBU6N4JGYayaCBofibOLacQPhYZdnR5Xb/Pvrx03GrzyzyDp0WyeI9nGNfkani7
25sCRWbzlMPsEvGEvJVnMLNRSk4xhPIWumL4APkw+Mgi6mf+Br8z0RhfnGwyMA53Mr
26pG9VQKlq3v7/aaN40pMjAsxiytcHS515jXrb3Ko4pWbTlAr/eytOEfkLRJgSOpQT
27BY7lWs+UQJqiG8Yn65vS9LMDNJgX9EOGx77Z4u9wvv4ZieOxzgbHGg5kYCoae7ba
28hxZeNjYKscH+E6epbOxM/wlTdr4UTiiW9dMsH0zSwMUB891gToeXq+LDGEPTKVSX
29tsJm4HS/kISJBwrCI4EUqWZML6xQ427NkZGmF2z/sD3kmL66GjspIKnb4zHmXacp
3084n2KrI9s7p6AnKnQjsxvB/4/lpXPCIY5GH7KjySEJiMsHECzeN1dJSL6keykBsx
31DtmYDA+dhZ6UWbwzx/78+mjNREhyp/UiSAmLzlJh89OH/xelAPvKcIosYwz4cY9N
32wjralTmL+Y0aHKeZJOeqPLaXADcPFiZrCNPCH65Ey5GEtDpjLpEbjVbykPV9+YkK
337JKW6bwMraOl5zmAoR77PWMo3IoYb9q4GuqDr1V2ZGlb7eMH1gj1nfgfVintKC1X
343jFfy7aK6LIQDVKEwbi0SxVXTKStuliVUy5oX4woDOxmTEotJf1QlKZpn5oF20UP
35tumYrp0SPoP8Bo4EVRVaLupduI5cYce1q/kFj9Iho/wk56MoG9PxMMfsH7oKg3AA
36CqQ6/kM4oJNdN5xIf1EH5HeaNFkDy1jlLznnhwVAZKPo/9ffpg==
37=bPqu
38-----END PGP MESSAGE-----
39
40
diff --git a/framework/domain/mimetreeparser/tests/data/plaintext.mbox b/framework/domain/mimetreeparser/tests/data/plaintext.mbox
new file mode 100644
index 00000000..d185b1c1
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/data/plaintext.mbox
@@ -0,0 +1,13 @@
1Return-Path: <konqi@example.org>
2Date: Wed, 8 Jun 2016 20:34:44 -0700
3From: Konqi <konqi@example.org>
4To: konqi@kde.org
5Subject: A random subject with alternative contenttype
6MIME-Version: 1.0
7Content-Type: text/plain; charset=utf-8
8Content-Transfer-Encoding: quoted-printable
9
10If you can see this text it means that your email client couldn't display o=
11ur newsletter properly.
12Please visit this link to view the newsletter on our website: http://www.go=
13g.com/newsletter/
diff --git a/framework/domain/mimetreeparser/tests/data/smime-encrypted.mbox b/framework/domain/mimetreeparser/tests/data/smime-encrypted.mbox
new file mode 100644
index 00000000..6b6d6a0d
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/data/smime-encrypted.mbox
@@ -0,0 +1,22 @@
1From test@example.com Sat, 13 Apr 2013 01:54:30 +0200
2From: test <test@example.com>
3To: you@you.com
4Subject: test
5Date: Sat, 13 Apr 2013 01:54:30 +0200
6Message-ID: <1576646.QQxzHWx8dA@tabin>
7X-KMail-Identity: 505942601
8User-Agent: KMail/4.10.2 (Linux/3.9.0-rc4-experimental-amd64; KDE/4.10.60; x86_64; git-fc9b82c; 2013-04-11)
9MIME-Version: 1.0
10Content-Type: application/pkcs7-mime; name="smime.p7m"; smime-type="enveloped-data"
11Content-Transfer-Encoding: base64
12Content-Disposition: attachment; filename="smime.p7m"
13
14MIAGCSqGSIb3DQEHA6CAMIACAQAxgfwwgfkCAQAwYjBVMQswCQYDVQQGEwJVUzENMAsGA1UECgwE
15S0RBQjEWMBQGA1UEAwwNdW5pdHRlc3QgY2VydDEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxl
16LmNvbQIJANNFIDoYY4XJMA0GCSqGSIb3DQEBAQUABIGAJwmmaOeidXUHSQGOf2OBIsPYafVqdORe
17y54pEXbXiAfSVUWgI4a9CsiWwcDX8vlaX9ZLLr+L2VmOfr6Yc5214yxzausZVvnUFjy6LUXotuEX
18tSar4EW7XI9DjaZc1l985naMsTx9JUa5GyQ9J6PGqhosAKpKMGgKkFAHaOwE1/IwgAYJKoZIhvcN
19AQcBMBQGCCqGSIb3DQMHBAieDfmz3WGbN6CABHgEpsLrNn0PAZTDUfNomDypvSCl5bQH+9cKm80m
20upMV2r8RBiXS7OaP4SpCxq18afDTTPatvboHIoEX92taTbq8soiAgEs6raSGtEYZNvFL0IYqm7MA
21o5HCOmjiEcInyPf14lL3HnPk10FaP3hh58qTHUh4LPYtL7UECOZELYnUfUVhAAAAAAAAAAAAAA==
22
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/CMakeLists.txt b/framework/domain/mimetreeparser/tests/gnupg_home/CMakeLists.txt
new file mode 100644
index 00000000..9c64a008
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/CMakeLists.txt
@@ -0,0 +1,10 @@
1configure_file( gpg-agent.conf.in
2 "${CMAKE_CURRENT_BINARY_DIR}/gpg-agent.conf" @ONLY )
3
4configure_file( gpgsm.conf.in
5 "${CMAKE_CURRENT_BINARY_DIR}/gpgsm.conf" @ONLY )
6
7file( COPY
8 ${CMAKE_CURRENT_SOURCE_DIR}
9 DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/../"
10)
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/DIR.txt b/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/DIR.txt
new file mode 100644
index 00000000..1a45a6b3
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/DIR.txt
@@ -0,0 +1,3 @@
1v:1:
2c:4E31CEB57DDD4A7B9991AB05507B1ED4293FF952:CN=Test-ZS 7,O=Intevation GmbH,C=DE:ldap%3A//ca.intevation.org/cn=Test-ZS 7, o=Intevation GmbH, c=DE?certificateRevocationList:20100615T181523:20100707T181523:72FEF3FD88455A1D4C6796A6499D4422::::
3c:7F2A402CBB016A9146D613568C89D3596A4111AA:CN=Wurzel ZS 3,O=Intevation GmbH,C=DE:ldap%3A//ca.intevation.org/cn=Wurzel ZS 3, o=Intevation GmbH, c=DE?certificateRevocationList:20100625T102134:20100814T102134:44E60EEC02EF2FBF7A5C77E9BD565667::::
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/crl-4E31CEB57DDD4A7B9991AB05507B1ED4293FF952.db b/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/crl-4E31CEB57DDD4A7B9991AB05507B1ED4293FF952.db
new file mode 100644
index 00000000..0b7e2dd4
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/crl-4E31CEB57DDD4A7B9991AB05507B1ED4293FF952.db
Binary files differ
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/crl-7F2A402CBB016A9146D613568C89D3596A4111AA.db b/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/crl-7F2A402CBB016A9146D613568C89D3596A4111AA.db
new file mode 100644
index 00000000..47474a26
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr-cache.d/crl-7F2A402CBB016A9146D613568C89D3596A4111AA.db
Binary files differ
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr.conf b/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr.conf
new file mode 100644
index 00000000..a17a0354
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/dirmngr.conf
@@ -0,0 +1,8 @@
1
2###+++--- GPGConf ---+++###
3debug-level basic
4log-file socket:///home/leo/kde/src/kdepim/messagecomposer/tests/gnupg_home/log-socket
5###+++--- GPGConf ---+++### Tue 29 Jun 2010 10:23:13 AM EDT
6# GPGConf edited this configuration file.
7# It will disable options before this marked block, but it will
8# never change anything below these lines.
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/gpg-agent.conf.in b/framework/domain/mimetreeparser/tests/gnupg_home/gpg-agent.conf.in
new file mode 100644
index 00000000..ece69255
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/gpg-agent.conf.in
@@ -0,0 +1,10 @@
1pinentry-program @CMAKE_CURRENT_BINARY_DIR@/pinentry-fake.sh
2###+++--- GPGConf ---+++###
3allow-mark-trusted
4debug-level basic
5faked-system-time 20130110T154812
6log-file @CMAKE_CURRENT_BINARY_DIR@/gpg-agent.log
7###+++--- GPGConf ---+++### Tue 29 Jun 2010 10:23:13 AM EDT
8# GPGConf edited this configuration file.
9# It will disable options before this marked block, but it will
10# never change anything below these lines.
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/gpg.conf b/framework/domain/mimetreeparser/tests/gnupg_home/gpg.conf
new file mode 100644
index 00000000..f1760823
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/gpg.conf
@@ -0,0 +1,244 @@
1# Options for GnuPG
2# Copyright 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
3#
4# This file is free software; as a special exception the author gives
5# unlimited permission to copy and/or distribute it, with or without
6# modifications, as long as this notice is preserved.
7#
8# This file is distributed in the hope that it will be useful, but
9# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
10# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11#
12# Unless you specify which option file to use (with the command line
13# option "--options filename"), GnuPG uses the file ~/.gnupg/gpg.conf
14# by default.
15#
16# An options file can contain any long options which are available in
17# GnuPG. If the first non white space character of a line is a '#',
18# this line is ignored. Empty lines are also ignored.
19#
20# See the man page for a list of options.
21
22# Uncomment the following option to get rid of the copyright notice
23
24#no-greeting
25
26# If you have more than 1 secret key in your keyring, you may want to
27# uncomment the following option and set your preferred keyid.
28
29#default-key 621CC013
30
31# If you do not pass a recipient to gpg, it will ask for one. Using
32# this option you can encrypt to a default key. Key validation will
33# not be done in this case. The second form uses the default key as
34# default recipient.
35
36#default-recipient some-user-id
37#default-recipient-self
38
39# Use --encrypt-to to add the specified key as a recipient to all
40# messages. This is useful, for example, when sending mail through a
41# mail client that does not automatically encrypt mail to your key.
42# In the example, this option allows you to read your local copy of
43# encrypted mail that you've sent to others.
44
45#encrypt-to some-key-id
46
47# By default GnuPG creates version 3 signatures for data files. This
48# is not strictly OpenPGP compliant but PGP 6 and most versions of PGP
49# 7 require them. To disable this behavior, you may use this option
50# or --openpgp.
51
52#no-force-v3-sigs
53
54# Because some mailers change lines starting with "From " to ">From "
55# it is good to handle such lines in a special way when creating
56# cleartext signatures; all other PGP versions do it this way too.
57
58#no-escape-from-lines
59
60# If you do not use the Latin-1 (ISO-8859-1) charset, you should tell
61# GnuPG which is the native character set. Please check the man page
62# for supported character sets. This character set is only used for
63# metadata and not for the actual message which does not undergo any
64# translation. Note that future version of GnuPG will change to UTF-8
65# as default character set. In most cases this option is not required
66# as GnuPG is able to figure out the correct charset at runtime.
67
68#charset utf-8
69
70# Group names may be defined like this:
71# group mynames = paige 0x12345678 joe patti
72#
73# Any time "mynames" is a recipient (-r or --recipient), it will be
74# expanded to the names "paige", "joe", and "patti", and the key ID
75# "0x12345678". Note there is only one level of expansion - you
76# cannot make an group that points to another group. Note also that
77# if there are spaces in the recipient name, this will appear as two
78# recipients. In these cases it is better to use the key ID.
79
80#group mynames = paige 0x12345678 joe patti
81
82# Lock the file only once for the lifetime of a process. If you do
83# not define this, the lock will be obtained and released every time
84# it is needed, which is usually preferable.
85
86#lock-once
87
88# GnuPG can send and receive keys to and from a keyserver. These
89# servers can be HKP, email, or LDAP (if GnuPG is built with LDAP
90# support).
91#
92# Example HKP keyserver:
93# hkp://keys.gnupg.net
94# hkp://subkeys.pgp.net
95#
96# Example email keyserver:
97# mailto:pgp-public-keys@keys.pgp.net
98#
99# Example LDAP keyservers:
100# ldap://keyserver.pgp.com
101#
102# Regular URL syntax applies, and you can set an alternate port
103# through the usual method:
104# hkp://keyserver.example.net:22742
105#
106# Most users just set the name and type of their preferred keyserver.
107# Note that most servers (with the notable exception of
108# ldap://keyserver.pgp.com) synchronize changes with each other. Note
109# also that a single server name may actually point to multiple
110# servers via DNS round-robin. hkp://keys.gnupg.net is an example of
111# such a "server", which spreads the load over a number of physical
112# servers. To see the IP address of the server actually used, you may use
113# the "--keyserver-options debug".
114
115keyserver hkp://keys.gnupg.net
116#keyserver mailto:pgp-public-keys@keys.nl.pgp.net
117#keyserver ldap://keyserver.pgp.com
118
119# Common options for keyserver functions:
120#
121# include-disabled : when searching, include keys marked as "disabled"
122# on the keyserver (not all keyservers support this).
123#
124# no-include-revoked : when searching, do not include keys marked as
125# "revoked" on the keyserver.
126#
127# verbose : show more information as the keys are fetched.
128# Can be used more than once to increase the amount
129# of information shown.
130#
131# use-temp-files : use temporary files instead of a pipe to talk to the
132# keyserver. Some platforms (Win32 for one) always
133# have this on.
134#
135# keep-temp-files : do not delete temporary files after using them
136# (really only useful for debugging)
137#
138# http-proxy="proxy" : set the proxy to use for HTTP and HKP keyservers.
139# This overrides the "http_proxy" environment variable,
140# if any.
141#
142# auto-key-retrieve : automatically fetch keys as needed from the keyserver
143# when verifying signatures or when importing keys that
144# have been revoked by a revocation key that is not
145# present on the keyring.
146#
147# no-include-attributes : do not include attribute IDs (aka "photo IDs")
148# when sending keys to the keyserver.
149
150#keyserver-options auto-key-retrieve
151
152# Display photo user IDs in key listings
153
154# list-options show-photos
155
156# Display photo user IDs when a signature from a key with a photo is
157# verified
158
159# verify-options show-photos
160
161# Use this program to display photo user IDs
162#
163# %i is expanded to a temporary file that contains the photo.
164# %I is the same as %i, but the file isn't deleted afterwards by GnuPG.
165# %k is expanded to the key ID of the key.
166# %K is expanded to the long OpenPGP key ID of the key.
167# %t is expanded to the extension of the image (e.g. "jpg").
168# %T is expanded to the MIME type of the image (e.g. "image/jpeg").
169# %f is expanded to the fingerprint of the key.
170# %% is %, of course.
171#
172# If %i or %I are not present, then the photo is supplied to the
173# viewer on standard input. If your platform supports it, standard
174# input is the best way to do this as it avoids the time and effort in
175# generating and then cleaning up a secure temp file.
176#
177# If no photo-viewer is provided, GnuPG will look for xloadimage, eog,
178# or display (ImageMagick). On Mac OS X and Windows, the default is
179# to use your regular JPEG image viewer.
180#
181# Some other viewers:
182# photo-viewer "qiv %i"
183# photo-viewer "ee %i"
184#
185# This one saves a copy of the photo ID in your home directory:
186# photo-viewer "cat > ~/photoid-for-key-%k.%t"
187#
188# Use your MIME handler to view photos:
189# photo-viewer "metamail -q -d -b -c %T -s 'KeyID 0x%k' -f GnuPG"
190
191# Passphrase agent
192#
193# We support the old experimental passphrase agent protocol as well as
194# the new Assuan based one (currently available in the "newpg" package
195# at ftp.gnupg.org/gcrypt/alpha/aegypten/). To make use of the agent,
196# you have to run an agent as daemon and use the option
197#
198# use-agent
199#
200# which tries to use the agent but will fallback to the regular mode
201# if there is a problem connecting to the agent. The normal way to
202# locate the agent is by looking at the environment variable
203# GPG_AGENT_INFO which should have been set during gpg-agent startup.
204# In certain situations the use of this variable is not possible, thus
205# the option
206#
207# --gpg-agent-info=<path>:<pid>:1
208#
209# may be used to override it.
210
211# Automatic key location
212#
213# GnuPG can automatically locate and retrieve keys as needed using the
214# auto-key-locate option. This happens when encrypting to an email
215# address (in the "user@example.com" form), and there are no
216# user@example.com keys on the local keyring. This option takes the
217# following arguments, in the order they are to be tried:
218#
219# cert = locate a key using DNS CERT, as specified in RFC-4398.
220# GnuPG can handle both the PGP (key) and IPGP (URL + fingerprint)
221# CERT methods.
222#
223# pka = locate a key using DNS PKA.
224#
225# ldap = locate a key using the PGP Universal method of checking
226# "ldap://keys.(thedomain)". For example, encrypting to
227# user@example.com will check ldap://keys.example.com.
228#
229# keyserver = locate a key using whatever keyserver is defined using
230# the keyserver option.
231#
232# You may also list arbitrary keyservers here by URL.
233#
234# Try CERT, then PKA, then LDAP, then hkp://subkeys.net:
235#auto-key-locate cert pka ldap hkp://subkeys.pgp.net
236
237###+++--- GPGConf ---+++###
238utf8-strings
239#debug-level basic
240#log-file socket:///home/leo/kde/src/kdepim/messagecomposer/tests/gnupg_home/log-socket
241###+++--- GPGConf ---+++### Tue 29 Jun 2010 10:23:13 AM EDT
242# GPGConf edited this configuration file.
243# It will disable options before this marked block, but it will
244# never change anything below these lines.
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/gpgsm.conf.in b/framework/domain/mimetreeparser/tests/gnupg_home/gpgsm.conf.in
new file mode 100644
index 00000000..92b6119d
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/gpgsm.conf.in
@@ -0,0 +1,10 @@
1
2###+++--- GPGConf ---+++###
3disable-crl-checks
4debug-level basic
5faked-system-time 20130110T154812
6log-file @CMAKE_CURRENT_BINARY_DIR@/gpgsm.log
7###+++--- GPGConf ---+++### Tue 29 Jun 2010 10:23:13 AM EDT
8# GPGConf edited this configuration file.
9# It will disable options before this marked block, but it will
10# never change anything below these lines.
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/pinentry-fake.sh b/framework/domain/mimetreeparser/tests/gnupg_home/pinentry-fake.sh
new file mode 100755
index 00000000..7135a942
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/pinentry-fake.sh
@@ -0,0 +1,9 @@
1#!/bin/sh
2
3echo "OK Your orders please"
4while :
5do
6 read cmd
7 echo "OK"
8 [ "$cmd" = "BYE" ] && break
9done
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/private-keys-v1.d/1AA8BA52430E51AE249AF0DA97D59F869E4101A8.key b/framework/domain/mimetreeparser/tests/gnupg_home/private-keys-v1.d/1AA8BA52430E51AE249AF0DA97D59F869E4101A8.key
new file mode 100644
index 00000000..39ac307b
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/private-keys-v1.d/1AA8BA52430E51AE249AF0DA97D59F869E4101A8.key
Binary files differ
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/pubring.gpg b/framework/domain/mimetreeparser/tests/gnupg_home/pubring.gpg
new file mode 100644
index 00000000..2e00fa24
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/pubring.gpg
Binary files differ
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/pubring.kbx b/framework/domain/mimetreeparser/tests/gnupg_home/pubring.kbx
new file mode 100644
index 00000000..0230f313
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/pubring.kbx
Binary files differ
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/scdaemon.conf b/framework/domain/mimetreeparser/tests/gnupg_home/scdaemon.conf
new file mode 100644
index 00000000..a17a0354
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/scdaemon.conf
@@ -0,0 +1,8 @@
1
2###+++--- GPGConf ---+++###
3debug-level basic
4log-file socket:///home/leo/kde/src/kdepim/messagecomposer/tests/gnupg_home/log-socket
5###+++--- GPGConf ---+++### Tue 29 Jun 2010 10:23:13 AM EDT
6# GPGConf edited this configuration file.
7# It will disable options before this marked block, but it will
8# never change anything below these lines.
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/secring.gpg b/framework/domain/mimetreeparser/tests/gnupg_home/secring.gpg
new file mode 100644
index 00000000..cfd3387d
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/secring.gpg
Binary files differ
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/trustdb.gpg b/framework/domain/mimetreeparser/tests/gnupg_home/trustdb.gpg
new file mode 100644
index 00000000..70089c15
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/trustdb.gpg
Binary files differ
diff --git a/framework/domain/mimetreeparser/tests/gnupg_home/trustlist.txt b/framework/domain/mimetreeparser/tests/gnupg_home/trustlist.txt
new file mode 100644
index 00000000..bbb0442d
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/gnupg_home/trustlist.txt
@@ -0,0 +1,11 @@
15E:7C:B2:F4:9F:70:05:43:42:32:5D:75:74:70:00:09:B9:D8:08:61 S
2
3
4
5# CN=unittest cert
6# O=KDAB
7# C=US
8# EMail=test@example.com
924:D2:FC:A2:2E:B3:B8:0A:1E:37:71:D1:4C:C6:58:E3:21:2B:49:DC S
10
11
diff --git a/framework/domain/mimetreeparser/tests/interfacetest.cpp b/framework/domain/mimetreeparser/tests/interfacetest.cpp
new file mode 100644
index 00000000..ac77b025
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/interfacetest.cpp
@@ -0,0 +1,204 @@
1/*
2 Copyright (c) 2016 Sandro Knauß <knauss@kolabsystems.com>
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 "interface.h"
21#include "interface_p.h"
22
23#include <QTest>
24
25QByteArray readMailFromFile(const QString &mailFile)
26{
27 QFile file(QLatin1String(MAIL_DATA_DIR) + QLatin1Char('/') + mailFile);
28 file.open(QIODevice::ReadOnly);
29 Q_ASSERT(file.isOpen());
30 return file.readAll();
31}
32
33QByteArray join(QVector<QByteArray> vec, QByteArray sep)
34{
35 QByteArray ret;
36 bool bInit = true;
37 foreach(const auto &entry, vec) {
38 if (!bInit) {
39 ret += sep;
40 }
41 bInit = false;
42 ret += entry;
43 }
44 return ret;
45}
46
47class InterfaceTest : public QObject
48{
49 Q_OBJECT
50private:
51 void printTree(const Part::Ptr &start, QString pre)
52 {
53 foreach (const auto &part, start->subParts()) {
54 qWarning() << QStringLiteral("%1* %2(%3)")
55 .arg(pre)
56 .arg(QString::fromLatin1(part->type()))
57 .arg(QString::fromLatin1(join(part->availableContents(),", ")));
58 printTree(part,pre + QStringLiteral(" "));
59 }
60 }
61
62private slots:
63
64 void testTextMail()
65 {
66 Parser parser(readMailFromFile("plaintext.mbox"));
67 printTree(parser.d->mTree,QString());
68 auto contentPartList = parser.collectContentParts();
69 QCOMPARE(contentPartList.size(), 1);
70 auto contentPart = contentPartList[0];
71 QVERIFY((bool)contentPart);
72 QCOMPARE(contentPart->availableContents(), QVector<QByteArray>() << "plaintext");
73 auto contentList = contentPart->content("plaintext");
74 QCOMPARE(contentList.size(), 1);
75 QCOMPARE(contentList[0]->content(), QStringLiteral("If you can see this text it means that your email client couldn't display our newsletter properly.\nPlease visit this link to view the newsletter on our website: http://www.gog.com/newsletter/").toLocal8Bit());
76 QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit());
77 QCOMPARE(contentList[0]->encryptions().size(), 0);
78 QCOMPARE(contentList[0]->signatures().size(), 0);
79
80 contentList = contentPart->content("html");
81 QCOMPARE(contentList.size(), 0);
82 auto contentAttachmentList = parser.collectAttachmentParts();
83 QCOMPARE(contentAttachmentList.size(), 0);
84 }
85
86 void testTextAlternative()
87 {
88 Parser parser(readMailFromFile("alternative.mbox"));
89 printTree(parser.d->mTree,QString());
90 auto contentPartList = parser.collectContentParts();
91 QCOMPARE(contentPartList.size(), 1);
92 auto contentPart = contentPartList[0];
93 QVERIFY((bool)contentPart);
94 QCOMPARE(contentPart->availableContents(), QVector<QByteArray>() << "html" << "plaintext");
95 auto contentList = contentPart->content("plaintext");
96 QCOMPARE(contentList.size(), 1);
97 QCOMPARE(contentList[0]->content(), QStringLiteral("If you can see this text it means that your email client couldn't display our newsletter properly.\nPlease visit this link to view the newsletter on our website: http://www.gog.com/newsletter/\n").toLocal8Bit());
98 QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit());
99 QCOMPARE(contentList[0]->encryptions().size(), 0);
100 QCOMPARE(contentList[0]->signatures().size(), 0);
101
102 contentList = contentPart->content("html");
103 QCOMPARE(contentList.size(), 1);
104 QCOMPARE(contentList[0]->content(), QStringLiteral("<html><body><p><span>HTML</span> text</p></body></html>\n\n").toLocal8Bit());
105 QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit());
106 QCOMPARE(contentList[0]->encryptions().size(), 0);
107 QCOMPARE(contentList[0]->signatures().size(), 0);
108 auto contentAttachmentList = parser.collectAttachmentParts();
109 QCOMPARE(contentAttachmentList.size(), 0);
110 }
111
112 void testTextHtml()
113 {
114 Parser parser(readMailFromFile("html.mbox"));
115 printTree(parser.d->mTree,QString());
116 auto contentPartList = parser.collectContentParts();
117 QCOMPARE(contentPartList.size(), 1);
118 auto contentPart = contentPartList[0];
119 QVERIFY((bool)contentPart);
120 QCOMPARE(contentPart->availableContents(), QVector<QByteArray>() << "html");
121
122 auto contentList = contentPart->content("plaintext");
123 QCOMPARE(contentList.size(), 0);
124
125 contentList = contentPart->content("html");
126 QCOMPARE(contentList.size(), 1);
127 QCOMPARE(contentList[0]->content(), QStringLiteral("<html><body><p><span>HTML</span> text</p></body></html>").toLocal8Bit());
128 QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit());
129 QCOMPARE(contentList[0]->encryptions().size(), 0);
130 QCOMPARE(contentList[0]->signatures().size(), 0);
131 auto contentAttachmentList = parser.collectAttachmentParts();
132 QCOMPARE(contentAttachmentList.size(), 0);
133 }
134
135 void testSMimeEncrypted()
136 {
137 Parser parser(readMailFromFile("smime-encrypted.mbox"));
138 printTree(parser.d->mTree,QString());
139 auto contentPartList = parser.collectContentParts();
140 QCOMPARE(contentPartList.size(), 1);
141 auto contentPart = contentPartList[0];
142 QVERIFY((bool)contentPart);
143 QCOMPARE(contentPart->availableContents(), QVector<QByteArray>() << "plaintext");
144 auto contentList = contentPart->content("plaintext");
145 QCOMPARE(contentList.size(), 1);
146 QCOMPARE(contentList[0]->content(), QStringLiteral("The quick brown fox jumped over the lazy dog.").toLocal8Bit());
147 QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit());
148 QCOMPARE(contentList[0]->encryptions().size(), 1);
149 QCOMPARE(contentList[0]->signatures().size(), 0);
150 auto contentAttachmentList = parser.collectAttachmentParts();
151 QCOMPARE(contentAttachmentList.size(), 0);
152 }
153
154 void testOpenPGPEncryptedAttachment()
155 {
156 Parser parser(readMailFromFile("openpgp-encrypted-attachment-and-non-encrypted-attachment.mbox"));
157 printTree(parser.d->mTree,QString());
158 auto contentPartList = parser.collectContentParts();
159 QCOMPARE(contentPartList.size(), 1);
160 auto contentPart = contentPartList[0];
161 QVERIFY((bool)contentPart);
162 QCOMPARE(contentPart->availableContents(), QVector<QByteArray>() << "plaintext");
163 auto contentList = contentPart->content("plaintext");
164 QCOMPARE(contentList.size(), 1);
165 QCOMPARE(contentList[0]->content(), QStringLiteral("test text").toLocal8Bit());
166 QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit());
167 QCOMPARE(contentList[0]->encryptions().size(), 1);
168 QCOMPARE(contentList[0]->signatures().size(), 1);
169 auto contentAttachmentList = parser.collectAttachmentParts();
170 QCOMPARE(contentAttachmentList.size(), 2);
171 QCOMPARE(contentAttachmentList[0]->availableContents(), QVector<QByteArray>() << "text/plain");
172 QCOMPARE(contentAttachmentList[0]->content().size(), 1);
173 QCOMPARE(contentAttachmentList[0]->encryptions().size(), 1);
174 QCOMPARE(contentAttachmentList[0]->signatures().size(), 1);
175 QCOMPARE(contentAttachmentList[1]->availableContents(), QVector<QByteArray>() << "image/png");
176 QCOMPARE(contentAttachmentList[1]->content().size(), 1);
177 QCOMPARE(contentAttachmentList[1]->encryptions().size(), 0);
178 QCOMPARE(contentAttachmentList[1]->signatures().size(), 0);
179 }
180
181 void testOpenPPGInline()
182 {
183 Parser parser(readMailFromFile("openpgp-inline-charset-encrypted.mbox"));
184 printTree(parser.d->mTree,QString());
185 auto contentPartList = parser.collectContentParts();
186 QCOMPARE(contentPartList.size(), 1);
187 auto contentPart = contentPartList[0];
188 QVERIFY((bool)contentPart);
189 QCOMPARE(contentPart->availableContents(), QVector<QByteArray>() << "plaintext");
190 QCOMPARE(contentPart->encryptions().size(), 0);
191 QCOMPARE(contentPart->signatures().size(), 0);
192 auto contentList = contentPart->content("plaintext");
193 QCOMPARE(contentList.size(), 1);
194 QCOMPARE(contentList[0]->content(), QStringLiteral("asdasd asd asd asdf sadf sdaf sadf äöü").toLocal8Bit());
195 QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit());
196 QCOMPARE(contentList[0]->encryptions().size(), 1);
197 QCOMPARE(contentList[0]->signatures().size(), 1);
198 auto contentAttachmentList = parser.collectAttachmentParts();
199 QCOMPARE(contentAttachmentList.size(), 0);
200 }
201};
202
203QTEST_GUILESS_MAIN(InterfaceTest)
204#include "interfacetest.moc" \ No newline at end of file
diff --git a/framework/domain/mimetreeparser/tests/kdepim_add_gpg_crypto_test.cmake b/framework/domain/mimetreeparser/tests/kdepim_add_gpg_crypto_test.cmake
new file mode 100644
index 00000000..17078202
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/kdepim_add_gpg_crypto_test.cmake
@@ -0,0 +1,60 @@
1# Copyright (c) 2013 Sandro Knauß <mail@sandroknauss.de>
2#
3# Redistribution and use is allowed according to the terms of the BSD license.
4# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
5
6set( GNUPGHOME ${CMAKE_BINARY_DIR}/framework/domain/mimetreeparser/tests/gnupg_home )
7add_definitions( -DGNUPGHOME="\\"${GNUPGHOME}\\"" )
8
9macro (ADD_GPG_CRYPTO_TEST _target _testname)
10 if (UNIX)
11 if (APPLE)
12 set(_library_path_variable "DYLD_LIBRARY_PATH")
13 elseif (CYGWIN)
14 set(_library_path_variable "PATH")
15 else (APPLE)
16 set(_library_path_variable "LD_LIBRARY_PATH")
17 endif (APPLE)
18
19 if (APPLE)
20 # DYLD_LIBRARY_PATH does not work like LD_LIBRARY_PATH
21 # OSX already has the RPATH in libraries and executables, putting runtime directories in
22 # DYLD_LIBRARY_PATH actually breaks things
23 set(_ld_library_path "${LIBRARY_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/")
24 else (APPLE)
25 set(_ld_library_path "${LIBRARY_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/:${LIB_INSTALL_DIR}:${QT_LIBRARY_DIR}")
26 endif (APPLE)
27 set(_executable "$<TARGET_FILE:${_target}>")
28
29 # use add_custom_target() to have the sh-wrapper generated during build time instead of cmake time
30 add_custom_command(TARGET ${_target} POST_BUILD
31 COMMAND ${CMAKE_COMMAND}
32 -D_filename=${_executable}.shell -D_library_path_variable=${_library_path_variable}
33 -D_ld_library_path="${_ld_library_path}" -D_executable=$<TARGET_FILE:${_target}>
34 -D_gnupghome="${GNUPGHOME}"
35 -P ${CMAKE_SOURCE_DIR}/framework/domain/mimetreeparser/tests/kdepim_generate_crypto_test_wrapper.cmake
36 )
37
38 set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${_executable}.shell" )
39 add_test(NAME ${_testname} COMMAND ${_executable}.shell)
40
41 else (UNIX)
42 # under windows, set the property WRAPPER_SCRIPT just to the name of the executable
43 # maybe later this will change to a generated batch file (for setting the PATH so that the Qt libs are found)
44 set(_ld_library_path "${LIBRARY_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}\;${LIB_INSTALL_DIR}\;${QT_LIBRARY_DIR}")
45 set(_executable "$<TARGET_FILE:${_target}>")
46
47 # use add_custom_target() to have the batch-file-wrapper generated during build time instead of cmake time
48 add_custom_command(TARGET ${_target} POST_BUILD
49 COMMAND ${CMAKE_COMMAND}
50 -D_filename="${_executable}.bat"
51 -D_ld_library_path="${_ld_library_path}" -D_executable="${_executable}"
52 -D_gnupghome="${GNUPGHOME}"
53 -P ${CMAKE_SOURCE_DIR}/framework/domain/mimetreeparser/tests/kdepim_generate_crypto_test_wrapper.cmake
54 )
55
56 add_test(NAME ${_testname} COMMAND ${_executable}.bat)
57
58 endif (UNIX)
59endmacro (ADD_GPG_CRYPTO_TEST)
60
diff --git a/framework/domain/mimetreeparser/tests/kdepim_generate_crypto_test_wrapper.cmake b/framework/domain/mimetreeparser/tests/kdepim_generate_crypto_test_wrapper.cmake
new file mode 100644
index 00000000..e1412f37
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/kdepim_generate_crypto_test_wrapper.cmake
@@ -0,0 +1,45 @@
1# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>
2# Copyright (c) 2013, Sandro Knauß <mail@sandroknauss.de>
3#
4# Redistribution and use is allowed according to the terms of the BSD license.
5# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
6
7
8if (UNIX)
9
10file(WRITE "${_filename}"
11"#!/bin/sh
12# created by cmake, don't edit, changes will be lost
13
14# don't mess with a gpg-agent already running on the system
15unset GPG_AGENT_INFO
16
17${_library_path_variable}=${_ld_library_path}\${${_library_path_variable}:+:\$${_library_path_variable}} GNUPGHOME=${_gnupghome} gpg-agent --daemon \"${_executable}\" \"$@\"
18_result=$?
19_pid=`echo GETINFO pid | GNUPGHOME=${_gnupghome} gpg-connect-agent | grep 'D' | cut -d' ' -f2`
20if [ ! -z \"\$_pid\" ]; then
21 echo \"Waiting for gpg-agent to terminate (PID: $_pid)...\"
22 while kill -0 \"\$_pid\"; do
23 sleep 1
24 done
25fi
26exit \$_result
27")
28
29# make it executable
30# since this is only executed on UNIX, it is safe to call chmod
31exec_program(chmod ARGS ug+x \"${_filename}\" OUTPUT_VARIABLE _dummy )
32
33else (UNIX)
34
35file(TO_NATIVE_PATH "${_ld_library_path}" win_path)
36file(TO_NATIVE_PATH "${_gnupghome}" win_gnupghome)
37
38file(WRITE "${_filename}"
39"
40set PATH=${win_path};$ENV{PATH}
41set GNUPGHOME=${win_gnupghome};$ENV{GNUPGHOME}
42gpg-agent --daemon \"${_executable}\" %*
43")
44
45endif (UNIX)
diff --git a/framework/domain/mimetreeparser/thoughts.txt b/framework/domain/mimetreeparser/thoughts.txt
new file mode 100644
index 00000000..3340347a
--- /dev/null
+++ b/framework/domain/mimetreeparser/thoughts.txt
@@ -0,0 +1,148 @@
1Usecases:
2
3# plaintext msg + attachment
4* ContentPart => cp1
5* AttachmentPart => ap1
6
7(cp1) == collect<ContentPart>(select=NoEncapsulatedMessages)
8(ap1) == collect<AttachmentParts>(select=NoEncapsulatedMessages)
9
10(PlainText) == cp1.availableContent()
11
12# html msg + related attachment + normal attachment
13* ContentPart => cp1
14* AttachmentPart(mimetype="*/related", cid="12345678") => ap1
15* AttachmentPart => ap2
16
17(cp1) == collect<ContentPart>(select=NoEncapsulatedMessages)
18(ap1, ap2) == collect<AttachmentParts>(select=NoEncapsulatedMessages)
19(ap2) == collect<AttachmentParts>(select=NoEncapsulatedMessages, filter=filterelated)
20
21ap1 == getPart("cid:12345678")
22
23(Html) == cp1.availableContent()
24
25# alternative msg + attachment
26* ContentPart(html=[Content("HTML"),], plaintext=[Content("Text"),]) => cp1
27* AttachmentPart => ap1
28
29(cp1) == collect<ContentPart>(select=NoEncapsulatedMessages)
30(ap1) == collect<AttachmentParts>(select=NoEncapsulatedMessages)
31
32(Html, PlainText) == cp1.availableContent()
33[Content("HTML"),] == cp1.content(Html)
34[Content("Text"),] == cp1.content(Plaintext)
35
36# alternative msg with GPGInlin
37* ContentPart(
38 plaintext=[Content("Text"), Content("foo", encryption=(enc1))],
39 html=[Content("HTML"),]
40 ) => cp1
41
42(Html, PlainText) == cp1.availableContent()
43
44[Content("HTML"),] == cp1.content(Html)
45[Content("Text"),Content("foo", encryption=(enc1))] == cp1.content(Plaintext)
46
47
48# encrypted msg (not encrypted/error) with unencrypted attachment
49* EncryptionErrorPart => cp1
50* AttachmentPart => ap1
51
52(cp1) == collect<ContentPart>(select=NoEncapsulatedMessages)
53(ap1) == collect<AttachmentParts>(select=NoEncapsulatedMessages)
54
55#encrypted msg (decrypted with attachment) + unencrypted attachment
56* encrytion=(rec1,rec2) => enc1
57 * ContentPart(encrytion = (enc1,)) => cp1
58 * AttachmentPart(encryption = (enc1,)) => ap1
59* AttachmentPart => ap2
60
61(cp1) == collect<ContentPart>(select=NoEncapsulatedMessages)
62(ap1, ap2) == collect<AttachmentParts>(select=NoEncapsulatedMessages)
63
64#INLINE GPG encrypted msg + attachment
65* ContentPart => cp1 with
66 plaintext=[Content, Content(encrytion = (enc1(rec1,rec2),)), Content(signed = (sig1,)), Content]
67* AttachmentPart => ap1
68
69(cp1) == collect<ContentPart>(select=NoEncapsulatedMessages)
70(ap1) == collect<AttachmentParts>(select=NoEncapsulatedMessages)
71
72[Content, Content(encrytion = (enc1(rec1,rec2),)), Content(signed = (sig1,)), Content] == cp1.content(Plaintext)
73
74#forwared encrypted msg + attachments
75* ContentPart => cp1
76* EncapsulatedPart => ep1
77 * Encrytion=(rec1,rec2) => enc1
78 * Signature => sig1
79 * ContentPart(encrytion = (enc1,), signature = (sig1,)) => cp2
80 * Content(encrytion = (enc1,), signature = (sig1,))
81 * Content(encrytion = (enc1, enc2(rec3,rec4),), signature = (sig1,))
82 * AttachmentPart(encrytion = (enc1,), signature = (sig1,)) => ap1
83* AttachmentPart => ap2
84
85(cp1) = collect<ContentPart>(select=NoEncapsulatedMessages)
86(ap2) = collect<AttachmentParts>(select=NoEncapsulatedMessages)
87
88(cp2) = collect<ContentPart>(ep1, select=NoEncapsulatedMessages)
89(ap1) = collect<AttachmentParts>(ep1, select=NoEncapsulatedMessages)
90
91(cp1, cp2) == collect<ContentPart>()
92(ap1, ap2) == collect<AttachmentParts>()[Content, Content(encrytion = (enc1(rec1,rec2),)), Content(signed = (sig1,)), Content]
93
94
95# plaintext msg + attachment + cert
96* ContentPart => cp1
97* AttachmentPart => ap1
98* CertPart => cep1
99
100(cp1) == collect<ContentPart>(select=NoEncapsulatedMessages)
101(ap1, cep1) == collect<AttachmentPart>(select=NoEncapsulatedMessages)
102(ap1) == collect<AttachmentPart>(select=NoEncapsulatedMessages, filter=filterSubAttachmentParts)
103
104(cep1) == collect<CertPart>(select=NoEncapsulatedMessages)
105
106
107collect function:
108
109bool noEncapsulatedMessages(Part part)
110{
111 if (is<EncapsulatedPart>(part)) {
112 return false;
113 }
114 return true;
115}
116
117bool filterRelated(T part)
118{
119 if (part.mimetype == related && !part.cid.isEmpty()) {
120 return false; //filter out related parts
121 }
122 return true;
123}
124
125bool filterSubAttachmentParts(AttachmentPart part)
126{
127 if (isSubPart<AttachmentPart>(part)) {
128 return false; // filter out CertPart f.ex.
129 }
130 return true;
131}
132
133List<T> collect<T>(Part start, std::function<bool(const Part &)> select, std::function<bool(const std::shared_ptr<T> &)> filter) {
134 List<T> col;
135 if (!select(start)) {
136 return col;
137 }
138
139 if(isOrSubTypeIs<T>(start) && filter(start.staticCast<T>)){
140 col.append(p);
141 }
142 foreach(childs as child) {
143 if (select(child)) {
144 col.expand(collect(child,select,filter);
145 }
146 }
147 return col;
148} \ No newline at end of file