summaryrefslogtreecommitdiffstats
path: root/framework
diff options
context:
space:
mode:
Diffstat (limited to 'framework')
-rw-r--r--framework/domain/CMakeLists.txt2
-rw-r--r--framework/domain/mimetreeparser/CMakeLists.txt12
-rw-r--r--framework/domain/mimetreeparser/interface.cpp538
-rw-r--r--framework/domain/mimetreeparser/interface.h335
-rw-r--r--framework/domain/mimetreeparser/interface_p.h50
-rw-r--r--framework/domain/mimetreeparser/objecttreesource.cpp151
-rw-r--r--framework/domain/mimetreeparser/objecttreesource.h57
-rw-r--r--framework/domain/mimetreeparser/stringhtmlwriter.cpp150
-rw-r--r--framework/domain/mimetreeparser/stringhtmlwriter.h71
-rw-r--r--framework/domain/mimetreeparser/tests/CMakeLists.txt10
-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/interfacetest.cpp157
-rw-r--r--framework/domain/mimetreeparser/thoughts.txt148
18 files changed, 1914 insertions, 0 deletions
diff --git a/framework/domain/CMakeLists.txt b/framework/domain/CMakeLists.txt
index ea293655..92a81352 100644
--- a/framework/domain/CMakeLists.txt
+++ b/framework/domain/CMakeLists.txt
@@ -26,3 +26,5 @@ add_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/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..a76a6cde
--- /dev/null
+++ b/framework/domain/mimetreeparser/interface.cpp
@@ -0,0 +1,538 @@
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) {
51 return false;
52 }
53 return (d->mNode->topLevel()->textContent() == d->mNode);
54}
55
56MailMime::Disposition MailMime::disposition() const
57{
58 if (!d->mNode) {
59 return Invalid;
60 }
61 const auto cd = d->mNode->contentDisposition(false);
62 if (!cd) {
63 return Invalid;
64 }
65 switch (cd->disposition()){
66 case KMime::Headers::CDinline:
67 return Inline;
68 case KMime::Headers::CDattachment:
69 return Attachment;
70 default:
71 return Invalid;
72 }
73}
74
75QString MailMime::filename() const
76{
77 if (!d->mNode) {
78 return QString();
79 }
80 const auto cd = d->mNode->contentDisposition(false);
81 if (!cd) {
82 return QString();
83 }
84 return cd->filename();
85}
86
87QMimeType MailMime::mimetype() const
88{
89 if (!d->mNode) {
90 return QMimeType();
91 }
92
93 const auto ct = d->mNode->contentType(false);
94 if (!ct) {
95 return QMimeType();
96 }
97
98 QMimeDatabase mimeDb;
99 return mimeDb.mimeTypeForName(ct->mimeType());
100}
101
102class PartPrivate
103{
104public:
105 PartPrivate(Part *part);
106 void appendSubPart(Part::Ptr subpart);
107
108 QVector<Part::Ptr> subParts();
109
110 Part *parent() const;
111
112 const MailMime::Ptr &mailMime() const;
113private:
114 Part *q;
115 Part *mParent;
116 QVector<Part::Ptr> mSubParts;
117 MailMime::Ptr mMailMime;
118};
119
120PartPrivate::PartPrivate(Part* part)
121 : q(part)
122 , mParent(Q_NULLPTR)
123{
124
125}
126
127void PartPrivate::appendSubPart(Part::Ptr subpart)
128{
129 subpart->d->mParent = q;
130 mSubParts.append(subpart);
131}
132
133Part *PartPrivate::parent() const
134{
135 return mParent;
136}
137
138QVector< Part::Ptr > PartPrivate::subParts()
139{
140 return mSubParts;
141}
142
143const MailMime::Ptr& PartPrivate::mailMime() const
144{
145 return mMailMime;
146}
147
148Part::Part()
149 : d(std::unique_ptr<PartPrivate>(new PartPrivate(this)))
150{
151
152}
153
154bool Part::hasSubParts() const
155{
156 return !subParts().isEmpty();
157}
158
159QVector<Part::Ptr> Part::subParts() const
160{
161 return d->subParts();
162}
163
164QByteArray Part::type() const
165{
166 return "Part";
167}
168
169QVector<QByteArray> Part::availableContents() const
170{
171 return QVector<QByteArray>();
172}
173
174QVector<Content::Ptr> Part::content() const
175{
176 return content(availableContents().first());
177}
178
179QVector<Content::Ptr> Part::content(const QByteArray& ct) const
180{
181 return QVector<Content::Ptr>();
182}
183
184QVector<Encryption> Part::encryptions() const
185{
186 auto parent = d->parent();
187 if (parent) {
188 return parent->encryptions();
189 } else {
190 return QVector<Encryption>();
191 }
192}
193
194QVector<Signature> Part::signatures() const
195{
196 auto parent = d->parent();
197 if (parent) {
198 return parent->signatures();
199 } else {
200 return QVector<Signature>();
201 }
202}
203
204MailMime::Ptr Part::mailMime() const
205{
206 return d->mailMime();
207}
208
209class ContentPrivate
210{
211public:
212 QByteArray mContent;
213 QByteArray mCodec;
214 Part *mParent;
215 Content *q;
216 MailMime::Ptr mMailMime;
217};
218
219Content::Content(const QByteArray& content, Part *parent)
220 : d(std::unique_ptr<ContentPrivate>(new ContentPrivate))
221{
222 d->q = this;
223 d->mContent = content;
224 d->mCodec = "utf-8";
225 d->mParent = parent;
226}
227
228Content::~Content()
229{
230}
231
232QVector<Encryption> Content::encryptions() const
233{
234 if (d->mParent) {
235 return d->mParent->encryptions();
236 }
237 return QVector<Encryption>();
238}
239
240QVector<Signature> Content::signatures() const
241{
242 if (d->mParent) {
243 return d->mParent->signatures();
244 }
245 return QVector<Signature>();
246}
247
248QByteArray Content::content() const
249{
250 return d->mContent;
251}
252
253QByteArray Content::charset() const
254{
255 return d->mCodec;
256}
257
258QByteArray Content::type() const
259{
260 return "Content";
261}
262
263MailMime::Ptr Content::mailMime() const
264{
265 return d->mMailMime;
266}
267
268HtmlContent::HtmlContent(const QByteArray& content, Part* parent)
269 : Content(content, parent)
270{
271
272}
273
274QByteArray HtmlContent::type() const
275{
276 return "HtmlContent";
277}
278
279PlainTextContent::PlainTextContent(const QByteArray& content, Part* parent)
280 : Content(content, parent)
281{
282
283}
284
285QByteArray PlainTextContent::type() const
286{
287 return "PlainTextContent";
288}
289
290class AlternativePartPrivate
291{
292public:
293 void fillFrom(MimeTreeParser::AlternativeMessagePart::Ptr part);
294
295 QVector<Content::Ptr> content(const QByteArray &ct) const;
296
297 AlternativePart *q;
298
299 QVector<QByteArray> types() const;
300
301private:
302 QMap<QByteArray, QVector<Content::Ptr>> mContent;
303 QVector<QByteArray> mTypes;
304};
305
306void AlternativePartPrivate::fillFrom(MimeTreeParser::AlternativeMessagePart::Ptr part)
307{
308 mTypes = QVector<QByteArray>() << "html" << "plaintext";
309
310 Content::Ptr content = std::make_shared<HtmlContent>(part->htmlContent().toLocal8Bit(), q);
311 mContent["html"].append(content);
312 content = std::make_shared<PlainTextContent>(part->plaintextContent().toLocal8Bit(), q);
313 mContent["plaintext"].append(content);
314}
315
316QVector<QByteArray> AlternativePartPrivate::types() const
317{
318 return mTypes;
319}
320
321QVector<Content::Ptr> AlternativePartPrivate::content(const QByteArray& ct) const
322{
323 return mContent[ct];
324}
325
326AlternativePart::AlternativePart()
327 : d(std::unique_ptr<AlternativePartPrivate>(new AlternativePartPrivate))
328{
329 d->q = this;
330}
331
332AlternativePart::~AlternativePart()
333{
334
335}
336
337QByteArray AlternativePart::type() const
338{
339 return "AlternativePart";
340}
341
342QVector<QByteArray> AlternativePart::availableContents() const
343{
344 return d->types();
345}
346
347QVector<Content::Ptr> AlternativePart::content(const QByteArray& ct) const
348{
349 return d->content(ct);
350}
351
352class SinglePartPrivate
353{
354public:
355 void fillFrom(MimeTreeParser::TextMessagePart::Ptr part);
356 void fillFrom(MimeTreeParser::HtmlMessagePart::Ptr part);
357 void fillFrom(MimeTreeParser::AttachmentMessagePart::Ptr part);
358 SinglePart *q;
359
360 QVector<Content::Ptr> mContent;
361 QByteArray mType;
362};
363
364void SinglePartPrivate::fillFrom(MimeTreeParser::TextMessagePart::Ptr part)
365{
366 mType = "plaintext";
367 mContent.clear();
368 foreach (const auto &mp, part->subParts()) {
369 mContent.append(std::make_shared<PlainTextContent>(mp->text().toLocal8Bit(), q));
370 }
371}
372
373void SinglePartPrivate::fillFrom(MimeTreeParser::HtmlMessagePart::Ptr part)
374{
375 mType = "html";
376 mContent.clear();
377 mContent.append(std::make_shared<HtmlContent>(part->text().toLocal8Bit(), q));
378}
379
380void SinglePartPrivate::fillFrom(MimeTreeParser::AttachmentMessagePart::Ptr part)
381{
382
383}
384
385SinglePart::SinglePart()
386 : d(std::unique_ptr<SinglePartPrivate>(new SinglePartPrivate))
387{
388 d->q = this;
389}
390
391SinglePart::~SinglePart()
392{
393
394}
395
396QVector<QByteArray> SinglePart::availableContents() const
397{
398 return QVector<QByteArray>() << d->mType;
399}
400
401QVector< Content::Ptr > SinglePart::content(const QByteArray &ct) const
402{
403 if (ct == d->mType) {
404 return d->mContent;
405 }
406 return QVector<Content::Ptr>();
407}
408
409QByteArray SinglePart::type() const
410{
411 return "SinglePart";
412}
413
414ParserPrivate::ParserPrivate(Parser* parser)
415 : q(parser)
416 , mNodeHelper(std::make_shared<MimeTreeParser::NodeHelper>())
417{
418
419}
420
421void ParserPrivate::setMessage(const QByteArray& mimeMessage)
422{
423 const auto mailData = KMime::CRLFtoLF(mimeMessage);
424 KMime::Message::Ptr msg(new KMime::Message);
425 msg->setContent(mailData);
426 msg->parse();
427
428 // render the mail
429 StringHtmlWriter htmlWriter;
430 ObjectTreeSource source(&htmlWriter);
431 MimeTreeParser::ObjectTreeParser otp(&source, mNodeHelper.get());
432
433 otp.parseObjectTree(msg.data());
434 mPartTree = otp.parsedPart().dynamicCast<MimeTreeParser::MessagePart>();
435
436 mEmbeddedPartMap = htmlWriter.embeddedParts();
437 mHtml = htmlWriter.html();
438
439 mTree = std::make_shared<Part>();
440 createTree(mPartTree, mTree);
441}
442
443
444void ParserPrivate::createTree(const MimeTreeParser::MessagePart::Ptr &start, const Part::Ptr &tree)
445{
446 foreach (const auto &mp, start->subParts()) {
447 const auto m = mp.dynamicCast<MimeTreeParser::MessagePart>();
448 const auto text = mp.dynamicCast<MimeTreeParser::TextMessagePart>();
449 const auto alternative = mp.dynamicCast<MimeTreeParser::AlternativeMessagePart>();
450 const auto html = mp.dynamicCast<MimeTreeParser::HtmlMessagePart>();
451 const auto attachment = mp.dynamicCast<MimeTreeParser::AttachmentMessagePart>();
452 if (attachment) {
453 auto part = std::make_shared<SinglePart>();
454 part->d->fillFrom(attachment);
455 mTree->d->appendSubPart(part);
456 } else if (text) {
457 auto part = std::make_shared<SinglePart>();
458 part->d->fillFrom(text);
459 mTree->d->appendSubPart(part);
460 } else if (alternative) {
461 auto part = std::make_shared<AlternativePart>();
462 part->d->fillFrom(alternative);
463 mTree->d->appendSubPart(part);
464 } else if (html) {
465 auto part = std::make_shared<SinglePart>();
466 part->d->fillFrom(html);
467 mTree->d->appendSubPart(part);
468 } else {
469 createTree(m, tree);
470 }
471 }
472}
473
474Parser::Parser(const QByteArray& mimeMessage)
475 :d(std::unique_ptr<ParserPrivate>(new ParserPrivate(this)))
476{
477 d->setMessage(mimeMessage);
478}
479
480Parser::~Parser()
481{
482}
483
484QVector<Part::Ptr> Parser::collectContentParts() const
485{
486 return collect(d->mTree, [](const Part::Ptr &p){return p->type() != "EncapsulatedPart";},
487 [](const Content::Ptr &content){
488 const auto mime = content->mailMime();
489
490 if (!mime) {
491 return true;
492 }
493
494 if (mime->isFirstTextPart()) {
495 return true;
496 }
497 const auto cd = mime->disposition();
498 if (cd && cd == MailMime::Inline) {
499 // explict "inline" disposition:
500 return true;
501 }
502 if (cd && cd == MailMime::Attachment) {
503 // explicit "attachment" disposition:
504 return false;
505 }
506
507 const auto ct = mime->mimetype();
508 if (ct.name().trimmed().toLower() == "text" && ct.name().trimmed().isEmpty() &&
509 (!mime || mime->filename().trimmed().isEmpty())) {
510 // text/* w/o filename parameter:
511 return true;
512 }
513 return false;
514 });
515}
516
517QVector<Part::Ptr> Parser::collect(const Part::Ptr &start, std::function<bool(const Part::Ptr &)> select, std::function<bool(const Content::Ptr &)> filter) const
518{
519 QVector<Part::Ptr> ret;
520 foreach (const auto &part, start->subParts()) {
521 QVector<QByteArray> contents;
522 foreach(const auto &ct, part->availableContents()) {
523 foreach(const auto &content, part->content(ct)) {
524 if (filter(content)) {
525 contents.append(ct);
526 break;
527 }
528 }
529 }
530 if (!contents.isEmpty()) {
531 ret.append(part);
532 }
533 if (select(part)){
534 ret += collect(part, select, filter);
535 }
536 }
537 return ret;
538} \ 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..c71b86d6
--- /dev/null
+++ b/framework/domain/mimetreeparser/interface.h
@@ -0,0 +1,335 @@
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 Encryption;
58
59class Parser;
60class ParserPrivate;
61
62/*
63 * A MessagePart that is based on a KMime::Content
64 */
65class MailMime
66{
67public:
68 typedef std::shared_ptr<MailMime> Ptr;
69 /**
70 * Various possible values for the "Content-Disposition" header.
71 */
72 enum Disposition {
73 Invalid, ///< Default, invalid value
74 Inline, ///< inline
75 Attachment ///< attachment
76 };
77
78 MailMime();
79
80 // interessting header parts of a KMime::Content
81 QMimeType mimetype() const;
82 Disposition disposition() const;
83 QUrl label() const;
84 QByteArray cid() const;
85 QByteArray charset() const;
86 QString filename() const;
87
88 // Unique identifier to ecactly this KMime::Content
89 QByteArray link() const;
90
91 QByteArray content() const;
92 //Use default charset
93 QString encodedContent() const;
94
95 // overwrite default charset with given charset
96 QString encodedContent(QByteArray charset) const;
97
98 bool isFirstTextPart() const;
99
100private:
101 std::unique_ptr<MailMimePrivate> d;
102};
103
104class Content
105{
106public:
107 typedef std::shared_ptr<Content> Ptr;
108 Content(const QByteArray &content, Part *parent);
109 virtual ~Content();
110
111 QByteArray content() const;
112
113 QByteArray charset() const;
114
115 //Use default charset
116 QString encodedContent() const;
117
118 // overwrite default charset with given charset
119 QString encodedContent(QByteArray charset) const;
120
121 virtual QVector<Signature> signatures() const;
122 virtual QVector<Encryption> encryptions() const;
123 MailMime::Ptr mailMime() const;
124 virtual QByteArray type() const;
125private:
126 std::unique_ptr<ContentPrivate> d;
127};
128
129class PlainTextContent : public Content
130{
131public:
132 PlainTextContent(const QByteArray &content, Part *parent);
133 QByteArray type() const Q_DECL_OVERRIDE;
134};
135
136class HtmlContent : public Content
137{
138public:
139 HtmlContent(const QByteArray &content, Part *parent);
140 QByteArray type() const Q_DECL_OVERRIDE;
141};
142
143/*
144 * importing a cert GpgMe::ImportResult
145 * checking a cert (if it is a valid cert)
146 */
147
148class CertContent : public Content
149{
150public:
151 typedef std::shared_ptr<CertContent> Ptr;
152 CertContent(const QByteArray &content, Part *parent);
153
154 QByteArray type() const Q_DECL_OVERRIDE;
155 enum CertType {
156 Pgp,
157 SMime
158 };
159
160 enum CertSubType {
161 Public,
162 Private
163 };
164
165 CertType certType() const;
166 CertSubType certSubType() const;
167 int keyLength() const;
168
169private:
170 std::unique_ptr<CertContentPrivate> d;
171};
172
173class Part
174{
175public:
176 typedef std::shared_ptr<Part> Ptr;
177 Part();
178 virtual QByteArray type() const;
179
180 virtual QVector<QByteArray> availableContents() const;
181 virtual QVector<Content::Ptr> content(const QByteArray& ct) const;
182 QVector<Content::Ptr> content() const;
183
184 bool hasSubParts() const;
185 QVector<Part::Ptr> subParts() const;
186 Part *parent() const;
187
188 virtual QVector<Signature> signatures() const;
189 virtual QVector<Encryption> encryptions() const;
190 virtual MailMime::Ptr mailMime() const;
191private:
192 std::unique_ptr<PartPrivate> d;
193 friend class ParserPrivate;
194 friend class PartPrivate;
195};
196
197class AlternativePart : public Part
198{
199public:
200 typedef std::shared_ptr<AlternativePart> Ptr;
201
202 AlternativePart();
203 virtual ~AlternativePart();
204
205 QVector<QByteArray> availableContents() const Q_DECL_OVERRIDE;
206 QVector<Content::Ptr> content(const QByteArray& ct) const Q_DECL_OVERRIDE;
207
208 QByteArray type() const Q_DECL_OVERRIDE;
209
210private:
211 std::unique_ptr<AlternativePartPrivate> d;
212
213 friend class ParserPrivate;
214};
215
216class SinglePart : public Part
217{
218 public:
219 typedef std::shared_ptr<SinglePart> Ptr;
220
221 SinglePart();
222 virtual ~SinglePart();
223
224 QVector<Content::Ptr> content(const QByteArray& ct) const Q_DECL_OVERRIDE;
225 QVector<QByteArray> availableContents() const Q_DECL_OVERRIDE;
226
227 QByteArray type() const Q_DECL_OVERRIDE;
228private:
229 std::unique_ptr<SinglePartPrivate> d;
230
231 friend class ParserPrivate;
232};
233
234
235class EncryptionPart : public Part
236{
237public:
238 typedef std::shared_ptr<EncryptionPart> Ptr;
239 QByteArray type() const Q_DECL_OVERRIDE;
240
241 EncryptionError error() const;
242private:
243 std::unique_ptr<EncryptionPartPrivate> d;
244};
245
246
247/*
248 * we want to request complete headers like:
249 * from/to...
250 */
251
252class EncapsulatedPart : public SinglePart
253{
254public:
255 typedef std::shared_ptr<EncapsulatedPart> Ptr;
256 QByteArray type() const Q_DECL_OVERRIDE;
257
258 //template <class T> QByteArray header<T>();
259private:
260 std::unique_ptr<EncapsulatedPartPrivate> d;
261};
262
263class EncryptionError
264{
265public:
266 int errorId() const;
267 QString errorString() const;
268};
269
270class Key
271{
272 QString keyid() const;
273 QString name() const;
274 QString email() const;
275 QString comment() const;
276 QVector<QString> emails() const;
277 enum KeyTrust {
278 Unknown, Undefined, Never, Marginal, Full, Ultimate
279 };
280 KeyTrust keyTrust() const;
281
282 bool isRevokation() const;
283 bool isInvalid() const;
284 bool isExpired() const;
285
286 std::vector<Key> subkeys();
287 Key parentkey() const;
288};
289
290class Signature
291{
292 Key key() const;
293 QDateTime creationDateTime() const;
294 QDateTime expirationTime() const;
295 bool neverExpires() const;
296
297 //template <> StatusObject<SignatureVerificationResult> verify() const;
298};
299
300/*
301 * Normally the Keys for encryption are subkeys
302 * for clients the parentkeys are "more interessting", because they store the name, email etc.
303 * but a client may also wants show to what subkey the mail is really encrypted, an if this subkey isRevoked or something else
304 */
305class Encryption
306{
307 std::vector<Key> recipients() const;
308};
309
310class Parser
311{
312public:
313 typedef std::shared_ptr<Parser> Ptr;
314 Parser(const QByteArray &mimeMessage);
315 ~Parser();
316
317 Part::Ptr getPart(QUrl url);
318
319 QVector<Part::Ptr> collect(const Part::Ptr &start, std::function<bool(const Part::Ptr &)> select, std::function<bool(const Content::Ptr &)> filter) const;
320 QVector<Part::Ptr> collectContentParts() const;
321 QVector<Part::Ptr> collectAttachmentParts() const;
322 //template <> QVector<ContentPart::Ptr> collect<ContentPart>() const;
323
324 //template <> static StatusObject<SignatureVerificationResult> verifySignature(const Signature signature) const;
325 //template <> static StatusObject<Part> decrypt(const EncryptedPart part) const;
326
327signals:
328 void partsChanged();
329
330private:
331 std::unique_ptr<ParserPrivate> d;
332
333 friend class InterfaceTest;
334};
335
diff --git a/framework/domain/mimetreeparser/interface_p.h b/framework/domain/mimetreeparser/interface_p.h
new file mode 100644
index 00000000..f83af6eb
--- /dev/null
+++ b/framework/domain/mimetreeparser/interface_p.h
@@ -0,0 +1,50 @@
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 MimeTreeParser
28{
29 class MessagePart;
30 class NodeHelper;
31 typedef QSharedPointer<MessagePart> MessagePartPtr;
32}
33
34class ParserPrivate
35{
36public:
37 ParserPrivate(Parser *parser);
38
39 void setMessage(const QByteArray &mimeMessage);
40 void createTree(const MimeTreeParser::MessagePartPtr& start, const Part::Ptr& tree);
41
42 Part::Ptr mTree;
43private:
44 Parser *q;
45
46 MimeTreeParser::MessagePartPtr mPartTree;
47 std::shared_ptr<MimeTreeParser::NodeHelper> mNodeHelper;
48 QString mHtml;
49 QMap<QByteArray, QUrl> mEmbeddedPartMap;
50}; \ 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..12cf88ab
--- /dev/null
+++ b/framework/domain/mimetreeparser/objecttreesource.cpp
@@ -0,0 +1,151 @@
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 , mHtmlMail(true)
35 {
36
37 }
38 MimeTreeParser::HtmlWriter *mWriter;
39 MimeTreeParser::BodyPartFormatterBaseFactory mBodyPartFormatterBaseFactory;
40 bool mAllowDecryption;
41 bool mHtmlLoadExternal;
42 bool mHtmlMail;
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::htmlMail() const
78{
79 return d->mHtmlMail;
80}
81
82void ObjectTreeSource::setHtmlMail(bool htmlMail)
83{
84 d->mHtmlMail = htmlMail;
85}
86
87bool ObjectTreeSource::decryptMessage() const
88{
89 return d->mAllowDecryption;
90}
91
92bool ObjectTreeSource::showSignatureDetails() const
93{
94 return true;
95}
96
97int ObjectTreeSource::levelQuote() const
98{
99 return 1;
100}
101
102const QTextCodec *ObjectTreeSource::overrideCodec()
103{
104 return Q_NULLPTR;
105}
106
107QString ObjectTreeSource::createMessageHeader(KMime::Message *message)
108{
109 return QString();
110}
111
112const MimeTreeParser::AttachmentStrategy *ObjectTreeSource::attachmentStrategy()
113{
114 return MimeTreeParser::AttachmentStrategy::smart();
115}
116
117QObject *ObjectTreeSource::sourceObject()
118{
119 return Q_NULLPTR;
120}
121
122void ObjectTreeSource::setHtmlMode(MimeTreeParser::Util::HtmlMode mode)
123{
124 Q_UNUSED(mode);
125}
126
127bool ObjectTreeSource::autoImportKeys() const
128{
129 return false;
130}
131
132bool ObjectTreeSource::showEmoticons() const
133{
134 return false;
135}
136
137bool ObjectTreeSource::showExpandQuotesMark() const
138{
139 return false;
140}
141
142const MimeTreeParser::BodyPartFormatterBaseFactory *ObjectTreeSource::bodyPartFormatterFactory()
143{
144 return &(d->mBodyPartFormatterBaseFactory);
145}
146
147MimeTreeParser::Interface::MessagePartRenderer::Ptr ObjectTreeSource::messagePartTheme(MimeTreeParser::Interface::MessagePart::Ptr msgPart)
148{
149 Q_UNUSED(msgPart);
150 return MimeTreeParser::Interface::MessagePartRenderer::Ptr();
151}
diff --git a/framework/domain/mimetreeparser/objecttreesource.h b/framework/domain/mimetreeparser/objecttreesource.h
new file mode 100644
index 00000000..bb0cd679
--- /dev/null
+++ b/framework/domain/mimetreeparser/objecttreesource.h
@@ -0,0 +1,57 @@
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 void setHtmlMail(bool htmlMail);
35 bool htmlMail() const Q_DECL_OVERRIDE;
36 bool decryptMessage() const Q_DECL_OVERRIDE;
37 bool htmlLoadExternal() const Q_DECL_OVERRIDE;
38 bool showSignatureDetails() const Q_DECL_OVERRIDE;
39 void setHtmlMode(MimeTreeParser::Util::HtmlMode mode) Q_DECL_OVERRIDE;
40 void setAllowDecryption(bool allowDecryption);
41 int levelQuote() const Q_DECL_OVERRIDE;
42 const QTextCodec *overrideCodec() Q_DECL_OVERRIDE;
43 QString createMessageHeader(KMime::Message *message) Q_DECL_OVERRIDE;
44 const MimeTreeParser::AttachmentStrategy *attachmentStrategy() Q_DECL_OVERRIDE;
45 MimeTreeParser::HtmlWriter *htmlWriter() Q_DECL_OVERRIDE;
46 QObject *sourceObject() Q_DECL_OVERRIDE;
47 bool autoImportKeys() const Q_DECL_OVERRIDE;
48 bool showEmoticons() const Q_DECL_OVERRIDE;
49 bool showExpandQuotesMark() const Q_DECL_OVERRIDE;
50 const MimeTreeParser::BodyPartFormatterBaseFactory *bodyPartFormatterFactory() Q_DECL_OVERRIDE;
51 MimeTreeParser::Interface::MessagePartRendererPtr messagePartTheme(MimeTreeParser::Interface::MessagePartPtr msgPart) Q_DECL_OVERRIDE;
52private:
53 ObjectSourcePrivate *const d;
54};
55
56#endif
57
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..d3549215
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/CMakeLists.txt
@@ -0,0 +1,10 @@
1add_definitions( -DMAIL_DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data" )
2include_directories(
3 ${CMAKE_CURRENT_BINARY_DIR}
4 ${CMAKE_CURRENT_SOURCE_DIR}/..
5 )
6
7add_executable(mimetreeparsertest interfacetest.cpp)
8add_test(mimetreeparsertest mimetreeparsertest)
9qt5_use_modules(mimetreeparsertest Core Test)
10target_link_libraries(mimetreeparsertest mimetreeparser) \ No newline at end of file
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
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
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/interfacetest.cpp b/framework/domain/mimetreeparser/tests/interfacetest.cpp
new file mode 100644
index 00000000..83de97f7
--- /dev/null
+++ b/framework/domain/mimetreeparser/tests/interfacetest.cpp
@@ -0,0 +1,157 @@
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
33
34class InterfaceTest : public QObject
35{
36 Q_OBJECT
37private:
38 void printTree(const Part::Ptr &start, QString pre)
39 {
40 foreach (const auto &part, start->subParts()) {
41 qWarning() << QStringLiteral("%1* %2").arg(pre).arg(QString::fromLatin1(part->type()));
42 printTree(part,pre + QStringLiteral(" "));
43 }
44 }
45
46private slots:
47
48 void testTextMail()
49 {
50 Parser parser(readMailFromFile("plaintext.mbox"));
51 auto contentPartList = parser.collectContentParts();
52 QCOMPARE(contentPartList.size(), 1);
53 auto contentPart = contentPartList[0];
54 QVERIFY((bool)contentPart);
55 QCOMPARE(contentPart->availableContents(), QVector<QByteArray>() << "plaintext");
56 auto contentList = contentPart->content("plaintext");
57 QCOMPARE(contentList.size(), 1);
58 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());
59 QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit());
60 QCOMPARE(contentList[0]->encryptions().size(), 0);
61 QCOMPARE(contentList[0]->signatures().size(), 0);
62
63 contentList = contentPart->content("html");
64 QCOMPARE(contentList.size(), 0);
65 }
66
67 void testTextAlternative()
68 {
69 Parser parser(readMailFromFile("alternative.mbox"));
70 auto contentPartList = parser.collectContentParts();
71 QCOMPARE(contentPartList.size(), 1);
72 auto contentPart = contentPartList[0];
73 QVERIFY((bool)contentPart);
74 QCOMPARE(contentPart->availableContents(), QVector<QByteArray>() << "html" << "plaintext");
75 auto contentList = contentPart->content("plaintext");
76 QCOMPARE(contentList.size(), 1);
77 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());
78 QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit());
79 QCOMPARE(contentList[0]->encryptions().size(), 0);
80 QCOMPARE(contentList[0]->signatures().size(), 0);
81
82 contentList = contentPart->content("html");
83 QCOMPARE(contentList.size(), 1);
84 QCOMPARE(contentList[0]->content(), QStringLiteral("<html><body><p><span>HTML</span> text</p></body></html>\n\n").toLocal8Bit());
85 QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit());
86 QCOMPARE(contentList[0]->encryptions().size(), 0);
87 QCOMPARE(contentList[0]->signatures().size(), 0);
88 }
89
90 void testTextHtml()
91 {
92 Parser parser(readMailFromFile("html.mbox"));
93 auto contentPartList = parser.collectContentParts();
94 QCOMPARE(contentPartList.size(), 1);
95 auto contentPart = contentPartList[0];
96 QVERIFY((bool)contentPart);
97 QCOMPARE(contentPart->availableContents(), QVector<QByteArray>() << "html");
98
99 auto contentList = contentPart->content("plaintext");
100 QCOMPARE(contentList.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>").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 }
109
110 void testSMimeEncrypted()
111 {
112 Parser parser(readMailFromFile("smime-encrypted.mbox"));
113 printTree(parser.d->mTree,QString());
114 auto contentPartList = parser.collectContentParts();
115 QCOMPARE(contentPartList.size(), 1);
116 auto contentPart = contentPartList[0];
117 QVERIFY((bool)contentPart);
118 QCOMPARE(contentPart->availableContents(), QVector<QByteArray>() << "plaintext");
119 auto contentList = contentPart->content("plaintext");
120 QCOMPARE(contentList.size(), 1);
121 QCOMPARE(contentList[0]->content(), QStringLiteral("The quick brown fox jumped over the lazy dog.").toLocal8Bit());
122 QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit());
123 }
124
125 void testOpenPGPEncryptedAttachment()
126 {
127 Parser parser(readMailFromFile("openpgp-encrypted-attachment-and-non-encrypted-attachment.mbox"));
128 printTree(parser.d->mTree,QString());
129 auto contentPartList = parser.collectContentParts();
130 QCOMPARE(contentPartList.size(), 1);
131 auto contentPart = contentPartList[0];
132 QVERIFY((bool)contentPart);
133 QCOMPARE(contentPart->availableContents(), QVector<QByteArray>() << "plaintext");
134 auto contentList = contentPart->content("plaintext");
135 QCOMPARE(contentList.size(), 1);
136 QCOMPARE(contentList[0]->content(), QStringLiteral("test text").toLocal8Bit());
137 QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit());
138 }
139
140 void testOpenPPGInline()
141 {
142 Parser parser(readMailFromFile("openpgp-inline-charset-encrypted.mbox"));
143 printTree(parser.d->mTree,QString());
144 auto contentPartList = parser.collectContentParts();
145 QCOMPARE(contentPartList.size(), 1);
146 auto contentPart = contentPartList[0];
147 QVERIFY((bool)contentPart);
148 QCOMPARE(contentPart->availableContents(), QVector<QByteArray>() << "plaintext");
149 auto contentList = contentPart->content("plaintext");
150 QCOMPARE(contentList.size(), 1);
151 QCOMPARE(contentList[0]->content(), QStringLiteral("asdasd asd asd asdf sadf sdaf sadf äöü").toLocal8Bit());
152 QCOMPARE(contentList[0]->charset(), QStringLiteral("utf-8").toLocal8Bit());
153 }
154};
155
156QTEST_GUILESS_MAIN(InterfaceTest)
157#include "interfacetest.moc" \ No newline at end of file
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