summaryrefslogtreecommitdiffstats
path: root/framework/domain/mimetreeparser/interface.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'framework/domain/mimetreeparser/interface.cpp')
-rw-r--r--framework/domain/mimetreeparser/interface.cpp1089
1 files changed, 1089 insertions, 0 deletions
diff --git a/framework/domain/mimetreeparser/interface.cpp b/framework/domain/mimetreeparser/interface.cpp
new file mode 100644
index 00000000..0bcbfec4
--- /dev/null
+++ b/framework/domain/mimetreeparser/interface.cpp
@@ -0,0 +1,1089 @@
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 <Libkleo/KeyListJob>
27#include <gpgme++/key.h>
28#include <gpgme++/keylistresult.h>
29
30#include <KMime/Content>
31#include <MimeTreeParser/ObjectTreeParser>
32#include <MimeTreeParser/MessagePart>
33#include <MimeTreeParser/NodeHelper>
34
35#include <QMimeDatabase>
36#include <QMimeType>
37#include <QTextCodec>
38#include <QDebug>
39
40class MailMimePrivate
41{
42public:
43 MailMimePrivate(MailMime *p);
44
45 MailMime *q;
46 KMime::Content *mNode;
47 std::shared_ptr<MailMime> parent;
48};
49
50MailMimePrivate::MailMimePrivate(MailMime* p)
51 : q(p)
52 , mNode(nullptr)
53 , parent(nullptr)
54{
55}
56
57
58MailMime::MailMime()
59 : d(std::unique_ptr<MailMimePrivate>(new MailMimePrivate(this)))
60{
61}
62
63QByteArray MailMime::cid() const
64{
65 if (!d->mNode || !d->mNode->contentID()) {
66 return QByteArray();
67 }
68 return d->mNode->contentID()->identifier();
69}
70
71QByteArray MailMime::charset() const
72{
73 if(!d->mNode || !d->mNode->contentType(false)) {
74 return QByteArray();
75 }
76 if (d->mNode->contentType(false)) {
77 return d->mNode->contentType(false)->charset();
78 }
79 return d->mNode->defaultCharset();
80}
81
82bool MailMime::isFirstTextPart() const
83{
84 if (!d->mNode || !d->mNode->topLevel()) {
85 return false;
86 }
87 return (d->mNode->topLevel()->textContent() == d->mNode);
88}
89
90bool MailMime::isFirstPart() const
91{
92 if (!d->mNode || !d->mNode->parent()) {
93 return false;
94 }
95 return (d->mNode->parent()->contents().first() == d->mNode);
96}
97
98bool MailMime::isTopLevelPart() const
99{
100 if (!d->mNode) {
101 return false;
102 }
103 return (d->mNode->topLevel() == d->mNode);
104}
105
106MailMime::Disposition MailMime::disposition() const
107{
108 if (!d->mNode) {
109 return Invalid;
110 }
111 const auto cd = d->mNode->contentDisposition(false);
112 if (!cd) {
113 return Invalid;
114 }
115 switch (cd->disposition()){
116 case KMime::Headers::CDinline:
117 return Inline;
118 case KMime::Headers::CDattachment:
119 return Attachment;
120 default:
121 return Invalid;
122 }
123}
124
125QString MailMime::filename() const
126{
127 if (!d->mNode) {
128 return QString();
129 }
130 const auto cd = d->mNode->contentDisposition(false);
131 if (!cd) {
132 return QString();
133 }
134 return cd->filename();
135}
136
137QMimeType MailMime::mimetype() const
138{
139 if (!d->mNode) {
140 return QMimeType();
141 }
142
143 const auto ct = d->mNode->contentType(false);
144 if (!ct) {
145 return QMimeType();
146 }
147
148 QMimeDatabase mimeDb;
149 return mimeDb.mimeTypeForName(ct->mimeType());
150}
151
152MailMime::Ptr MailMime::parent() const
153{
154 if (!d->parent) {
155 d->parent = std::shared_ptr<MailMime>(new MailMime());
156 d->parent->d->mNode = d->mNode->parent();
157 }
158 return d->parent;
159}
160
161QByteArray MailMime::decodedContent() const
162{
163 if (!d->mNode) {
164 return QByteArray();
165 }
166 return d->mNode->decodedContent();
167}
168
169class KeyPrivate
170{
171public:
172 Key *q;
173 GpgME::Key mKey;
174};
175
176Key::Key()
177 :d(std::unique_ptr<KeyPrivate>(new KeyPrivate))
178{
179 d->q = this;
180}
181
182
183Key::Key(KeyPrivate *d_ptr)
184 :d(std::unique_ptr<KeyPrivate>(d_ptr))
185{
186 d->q = this;
187}
188
189Key::~Key()
190{
191
192}
193
194QString Key::keyid() const
195{
196 return d->mKey.keyID();
197}
198
199QString Key::name() const
200{
201 //FIXME: is this the correct way to get the primary UID?
202 return d->mKey.userID(0).name();
203}
204
205QString Key::email() const
206{
207 return d->mKey.userID(0).email();
208}
209
210QString Key::comment() const
211{
212 return d->mKey.userID(0).comment();
213}
214
215class SignaturePrivate
216{
217public:
218 Signature *q;
219 GpgME::Signature mSignature;
220 Key::Ptr mKey;
221};
222
223Signature::Signature()
224 :d(std::unique_ptr<SignaturePrivate>(new SignaturePrivate))
225{
226 d->q = this;
227}
228
229
230Signature::Signature(SignaturePrivate *d_ptr)
231 :d(std::unique_ptr<SignaturePrivate>(d_ptr))
232{
233 d->q = this;
234
235}
236
237Signature::~Signature()
238{
239
240}
241
242QDateTime Signature::creationDateTime() const
243{
244 QDateTime dt;
245 dt.setTime_t(d->mSignature.creationTime());
246 return dt;
247}
248
249QDateTime Signature::expirationDateTime() const
250{
251 QDateTime dt;
252 dt.setTime_t(d->mSignature.expirationTime());
253 return dt;
254}
255
256bool Signature::neverExpires() const
257{
258 return d->mSignature.neverExpires();
259}
260
261Key::Ptr Signature::key() const
262{
263 return d->mKey;
264}
265
266class EncryptionPrivate
267{
268public:
269 Encryption *q;
270 std::vector<Key::Ptr> mRecipients;
271};
272
273Encryption::Encryption(EncryptionPrivate *d_ptr)
274 :d(std::unique_ptr<EncryptionPrivate>(d_ptr))
275{
276 d->q = this;
277}
278
279Encryption::Encryption()
280 :d(std::unique_ptr<EncryptionPrivate>(new EncryptionPrivate))
281{
282 d->q = this;
283}
284
285Encryption::~Encryption()
286{
287
288}
289
290std::vector<Key::Ptr> Encryption::recipients() const
291{
292 return d->mRecipients;
293}
294
295class PartPrivate
296{
297public:
298 PartPrivate(Part *part);
299 void appendSubPart(Part::Ptr subpart);
300
301 QVector<Part::Ptr> subParts();
302
303 Part *parent() const;
304
305 const MailMime::Ptr &mailMime() const;
306 void createMailMime(const MimeTreeParser::MimeMessagePart::Ptr &part);
307 void createMailMime(const MimeTreeParser::TextMessagePart::Ptr &part);
308 void createMailMime(const MimeTreeParser::AlternativeMessagePart::Ptr &part);
309 void createMailMime(const MimeTreeParser::HtmlMessagePart::Ptr &part);
310
311 static Encryption::Ptr createEncryption(const MimeTreeParser::EncryptedMessagePart::Ptr& part);
312 void appendEncryption(const MimeTreeParser::EncryptedMessagePart::Ptr &part);
313 static QVector<Signature::Ptr> createSignature(const MimeTreeParser::SignedMessagePart::Ptr& part);
314 void appendSignature(const MimeTreeParser::SignedMessagePart::Ptr &part);
315
316 void setSignatures(const QVector<Signature::Ptr> &sigs);
317 void setEncryptions(const QVector<Encryption::Ptr> &encs);
318
319 const QVector<Encryption::Ptr> &encryptions() const;
320 const QVector<Signature::Ptr> &signatures() const;
321private:
322 Part *q;
323 Part *mParent;
324 QVector<Part::Ptr> mSubParts;
325 QVector<Encryption::Ptr> mEncryptions;
326 QVector<Signature::Ptr> mSignatures;
327 MailMime::Ptr mMailMime;
328};
329
330PartPrivate::PartPrivate(Part* part)
331 : q(part)
332 , mParent(Q_NULLPTR)
333{
334
335}
336
337void PartPrivate::createMailMime(const MimeTreeParser::HtmlMessagePart::Ptr& part)
338{
339 mMailMime = MailMime::Ptr(new MailMime);
340 mMailMime->d->mNode = part->mNode;
341}
342
343void PartPrivate::createMailMime(const MimeTreeParser::AlternativeMessagePart::Ptr& part)
344{
345 mMailMime = MailMime::Ptr(new MailMime);
346 mMailMime->d->mNode = part->mNode;
347}
348
349void PartPrivate::createMailMime(const MimeTreeParser::TextMessagePart::Ptr& part)
350{
351 mMailMime = MailMime::Ptr(new MailMime);
352 mMailMime->d->mNode = part->mNode;
353}
354
355void PartPrivate::createMailMime(const MimeTreeParser::MimeMessagePart::Ptr& part)
356{
357 mMailMime = MailMime::Ptr(new MailMime);
358 mMailMime->d->mNode = part->mNode;
359}
360
361void PartPrivate::appendSubPart(Part::Ptr subpart)
362{
363 subpart->d->mParent = q;
364 mSubParts.append(subpart);
365}
366
367Encryption::Ptr PartPrivate::createEncryption(const MimeTreeParser::EncryptedMessagePart::Ptr& part)
368{
369 Kleo::KeyListJob *job = part->mCryptoProto->keyListJob(false); // local, no sigs
370 if (!job) {
371 qWarning() << "The Crypto backend does not support listing keys. ";
372 return Encryption::Ptr();
373 }
374
375 auto encpriv = new EncryptionPrivate();
376 foreach(const auto &recipient, part->mDecryptRecipients) {
377 std::vector<GpgME::Key> found_keys;
378 const auto &keyid = recipient.keyID();
379 GpgME::KeyListResult res = job->exec(QStringList(QLatin1String(keyid)), false, found_keys);
380 if (res.error()) {
381 qWarning() << "Error while searching key for Fingerprint: " << keyid;
382 continue;
383 }
384 if (found_keys.size() > 1) {
385 // Should not Happen
386 qWarning() << "Oops: Found more then one Key for Fingerprint: " << keyid;
387 }
388 if (found_keys.size() != 1) {
389 // Should not Happen at this point
390 qWarning() << "Oops: Found no Key for Fingerprint: " << keyid;
391 } else {
392 auto key = found_keys[0];
393 auto keypriv = new KeyPrivate;
394 keypriv->mKey = key;
395 encpriv->mRecipients.push_back(Key::Ptr(new Key(keypriv)));
396 }
397 }
398 return Encryption::Ptr(new Encryption(encpriv));
399}
400
401void PartPrivate::appendEncryption(const MimeTreeParser::EncryptedMessagePart::Ptr& part)
402{
403 mEncryptions.append(createEncryption(part));
404}
405
406void PartPrivate::setEncryptions(const QVector< Encryption::Ptr >& encs)
407{
408 mEncryptions = encs;
409}
410
411QVector<Signature::Ptr> PartPrivate::createSignature(const MimeTreeParser::SignedMessagePart::Ptr& part)
412{
413 QVector<Signature::Ptr> sigs;
414 Kleo::KeyListJob *job = part->mCryptoProto->keyListJob(false); // local, no sigs
415 if (!job) {
416 qWarning() << "The Crypto backend does not support listing keys. ";
417 return sigs;
418 }
419
420 foreach(const auto &sig, part->mSignatures) {
421 auto sigpriv = new SignaturePrivate();
422 sigpriv->mSignature = sig;
423 auto signature = std::make_shared<Signature>(sigpriv);
424 sigs.append(signature);
425
426 std::vector<GpgME::Key> found_keys;
427 const auto &keyid = sig.fingerprint();
428 GpgME::KeyListResult res = job->exec(QStringList(QLatin1String(keyid)), false, found_keys);
429 if (res.error()) {
430 qWarning() << "Error while searching key for Fingerprint: " << keyid;
431 continue;
432 }
433 if (found_keys.size() > 1) {
434 // Should not Happen
435 qWarning() << "Oops: Found more then one Key for Fingerprint: " << keyid;
436 continue;
437 }
438 if (found_keys.size() != 1) {
439 // Should not Happen at this point
440 qWarning() << "Oops: Found no Key for Fingerprint: " << keyid;
441 continue;
442 } else {
443 auto key = found_keys[0];
444 auto keypriv = new KeyPrivate;
445 keypriv->mKey = key;
446 sigpriv->mKey = Key::Ptr(new Key(keypriv));
447 }
448 }
449 return sigs;
450}
451
452void PartPrivate::appendSignature(const MimeTreeParser::SignedMessagePart::Ptr& part)
453{
454 mSignatures.append(createSignature(part));
455}
456
457
458void PartPrivate::setSignatures(const QVector< Signature::Ptr >& sigs)
459{
460 mSignatures = sigs;
461}
462
463Part *PartPrivate::parent() const
464{
465 return mParent;
466}
467
468QVector< Part::Ptr > PartPrivate::subParts()
469{
470 return mSubParts;
471}
472
473const MailMime::Ptr& PartPrivate::mailMime() const
474{
475 return mMailMime;
476}
477
478const QVector< Encryption::Ptr >& PartPrivate::encryptions() const
479{
480 return mEncryptions;
481}
482
483const QVector< Signature::Ptr >& PartPrivate::signatures() const
484{
485 return mSignatures;
486}
487
488Part::Part()
489 : d(std::unique_ptr<PartPrivate>(new PartPrivate(this)))
490{
491
492}
493
494bool Part::hasSubParts() const
495{
496 return !subParts().isEmpty();
497}
498
499QVector<Part::Ptr> Part::subParts() const
500{
501 return d->subParts();
502}
503
504QByteArray Part::type() const
505{
506 return "Part";
507}
508
509QVector<QByteArray> Part::availableContents() const
510{
511 return QVector<QByteArray>();
512}
513
514QVector<Content::Ptr> Part::content() const
515{
516 return content(availableContents().first());
517}
518
519QVector<Content::Ptr> Part::content(const QByteArray& ct) const
520{
521 return QVector<Content::Ptr>();
522}
523
524QVector<Encryption::Ptr> Part::encryptions() const
525{
526 auto ret = d->encryptions();
527 auto parent = d->parent();
528 if (parent) {
529 ret.append(parent->encryptions());
530 }
531 return ret;
532}
533
534QVector<Signature::Ptr> Part::signatures() const
535{
536 auto ret = d->signatures();
537 auto parent = d->parent();
538 if (parent) {
539 ret.append(parent->signatures());
540 }
541 return ret;
542}
543
544MailMime::Ptr Part::mailMime() const
545{
546 return d->mailMime();
547}
548
549Part *Part::parent() const
550{
551 return d->parent();
552}
553
554class ContentPrivate
555{
556public:
557 QByteArray mContent;
558 QByteArray mCodec;
559 Part *mParent;
560 Content *q;
561 MailMime::Ptr mMailMime;
562 QVector<Encryption::Ptr> mEncryptions;
563 QVector<Signature::Ptr> mSignatures;
564 void appendSignature(const MimeTreeParser::SignedMessagePart::Ptr &sig);
565 void appendEncryption(const MimeTreeParser::EncryptedMessagePart::Ptr &enc);
566};
567
568void ContentPrivate::appendEncryption(const MimeTreeParser::EncryptedMessagePart::Ptr& enc)
569{
570 mEncryptions.append(PartPrivate::createEncryption(enc));
571}
572
573void ContentPrivate::appendSignature(const MimeTreeParser::SignedMessagePart::Ptr& sig)
574{
575 mSignatures.append(PartPrivate::createSignature(sig));
576}
577
578
579Content::Content(const QByteArray& content, Part *parent)
580 : d(std::unique_ptr<ContentPrivate>(new ContentPrivate))
581{
582 d->q = this;
583 d->mContent = content;
584 d->mCodec = "utf-8";
585 d->mParent = parent;
586}
587
588Content::Content(ContentPrivate* d_ptr)
589 : d(std::unique_ptr<ContentPrivate>(d_ptr))
590{
591 d->q = this;
592}
593
594Content::~Content()
595{
596}
597
598QVector<Encryption::Ptr> Content::encryptions() const
599{
600 auto ret = d->mEncryptions;
601 if (d->mParent) {
602 ret.append(d->mParent->encryptions());
603 }
604 return ret;
605}
606
607QVector<Signature::Ptr> Content::signatures() const
608{
609 auto ret = d->mSignatures;
610 if (d->mParent) {
611 ret.append(d->mParent->signatures());
612 }
613 return ret;
614}
615
616QByteArray Content::content() const
617{
618 return d->mContent;
619}
620
621QByteArray Content::charset() const
622{
623 return d->mCodec;
624}
625
626QString Content::encodedContent() const
627{
628 return encodedContent(charset());
629}
630
631QString Content::encodedContent(const QByteArray &charset) const
632{
633 QTextCodec *codec = QTextCodec::codecForName(charset);
634 return codec->toUnicode(content());
635}
636
637QByteArray Content::type() const
638{
639 return "Content";
640}
641
642MailMime::Ptr Content::mailMime() const
643{
644 if (d->mMailMime) {
645 return d->mMailMime;
646 } else {
647 return d->mParent->mailMime();
648 }
649}
650
651Part *Content::parent() const
652{
653 return d->mParent;
654}
655
656HtmlContent::HtmlContent(const QByteArray& content, Part* parent)
657 : Content(content, parent)
658{
659
660}
661
662QByteArray HtmlContent::type() const
663{
664 return "HtmlContent";
665}
666
667PlainTextContent::PlainTextContent(const QByteArray& content, Part* parent)
668 : Content(content, parent)
669{
670
671}
672
673PlainTextContent::PlainTextContent(ContentPrivate* d_ptr)
674 : Content(d_ptr)
675{
676
677}
678
679HtmlContent::HtmlContent(ContentPrivate* d_ptr)
680 : Content(d_ptr)
681{
682
683}
684
685
686QByteArray PlainTextContent::type() const
687{
688 return "PlainTextContent";
689}
690
691class AlternativePartPrivate
692{
693public:
694 void fillFrom(MimeTreeParser::AlternativeMessagePart::Ptr part);
695
696 QVector<Content::Ptr> content(const QByteArray &ct) const;
697
698 AlternativePart *q;
699
700 QVector<QByteArray> types() const;
701
702private:
703 QMap<QByteArray, QVector<Content::Ptr>> mContent;
704 QVector<QByteArray> mTypes;
705};
706
707void AlternativePartPrivate::fillFrom(MimeTreeParser::AlternativeMessagePart::Ptr part)
708{
709 mTypes = QVector<QByteArray>() << "html" << "plaintext";
710
711 Content::Ptr content = std::make_shared<HtmlContent>(part->htmlContent().toLocal8Bit(), q);
712 mContent["html"].append(content);
713 content = std::make_shared<PlainTextContent>(part->plaintextContent().toLocal8Bit(), q);
714 mContent["plaintext"].append(content);
715 q->reachParentD()->createMailMime(part);
716}
717
718QVector<QByteArray> AlternativePartPrivate::types() const
719{
720 return mTypes;
721}
722
723QVector<Content::Ptr> AlternativePartPrivate::content(const QByteArray& ct) const
724{
725 return mContent[ct];
726}
727
728AlternativePart::AlternativePart()
729 : d(std::unique_ptr<AlternativePartPrivate>(new AlternativePartPrivate))
730{
731 d->q = this;
732}
733
734AlternativePart::~AlternativePart()
735{
736
737}
738
739QByteArray AlternativePart::type() const
740{
741 return "AlternativePart";
742}
743
744QVector<QByteArray> AlternativePart::availableContents() const
745{
746 return d->types();
747}
748
749QVector<Content::Ptr> AlternativePart::content(const QByteArray& ct) const
750{
751 return d->content(ct);
752}
753
754PartPrivate* AlternativePart::reachParentD() const
755{
756 return Part::d.get();
757}
758
759class SinglePartPrivate
760{
761public:
762 void fillFrom(MimeTreeParser::TextMessagePart::Ptr part);
763 void fillFrom(MimeTreeParser::HtmlMessagePart::Ptr part);
764 void fillFrom(MimeTreeParser::AttachmentMessagePart::Ptr part);
765 SinglePart *q;
766
767 QVector<Content::Ptr> mContent;
768 QByteArray mType;
769};
770
771void SinglePartPrivate::fillFrom(MimeTreeParser::TextMessagePart::Ptr part)
772{
773 mType = "plaintext";
774 mContent.clear();
775 foreach (const auto &mp, part->subParts()) {
776 auto d_ptr = new ContentPrivate;
777 d_ptr->mContent = mp->text().toLocal8Bit();
778 d_ptr->mParent = q;
779 const auto enc = mp.dynamicCast<MimeTreeParser::EncryptedMessagePart>();
780 auto sig = mp.dynamicCast<MimeTreeParser::SignedMessagePart>();
781 if (enc) {
782 d_ptr->appendEncryption(enc);
783 const auto s = enc->subParts();
784 if (s.size() == 1) {
785 sig = s[0].dynamicCast<MimeTreeParser::SignedMessagePart>();
786 }
787 }
788 if (sig) {
789 d_ptr->appendSignature(sig);
790 }
791 mContent.append(std::make_shared<PlainTextContent>(d_ptr));
792 q->reachParentD()->createMailMime(part);
793 d_ptr->mCodec = q->mailMime()->charset();
794 }
795}
796
797void SinglePartPrivate::fillFrom(MimeTreeParser::HtmlMessagePart::Ptr part)
798{
799 mType = "html";
800 mContent.clear();
801 mContent.append(std::make_shared<HtmlContent>(part->text().toLocal8Bit(), q));
802 q->reachParentD()->createMailMime(part);
803}
804
805void SinglePartPrivate::fillFrom(MimeTreeParser::AttachmentMessagePart::Ptr part)
806{
807 q->reachParentD()->createMailMime(part.staticCast<MimeTreeParser::TextMessagePart>());
808 mType = q->mailMime()->mimetype().name().toUtf8();
809 mContent.clear();
810 mContent.append(std::make_shared<Content>(q->mailMime()->decodedContent(), q));
811}
812
813SinglePart::SinglePart()
814 : d(std::unique_ptr<SinglePartPrivate>(new SinglePartPrivate))
815{
816 d->q = this;
817}
818
819SinglePart::~SinglePart()
820{
821
822}
823
824QVector<QByteArray> SinglePart::availableContents() const
825{
826 return QVector<QByteArray>() << d->mType;
827}
828
829QVector< Content::Ptr > SinglePart::content(const QByteArray &ct) const
830{
831 if (ct == d->mType) {
832 return d->mContent;
833 }
834 return QVector<Content::Ptr>();
835}
836
837QByteArray SinglePart::type() const
838{
839 return "SinglePart";
840}
841
842PartPrivate* SinglePart::reachParentD() const
843{
844 return Part::d.get();
845}
846
847ParserPrivate::ParserPrivate(Parser* parser)
848 : q(parser)
849 , mNodeHelper(std::make_shared<MimeTreeParser::NodeHelper>())
850{
851
852}
853
854void ParserPrivate::setMessage(const QByteArray& mimeMessage)
855{
856 const auto mailData = KMime::CRLFtoLF(mimeMessage);
857 mMsg = KMime::Message::Ptr(new KMime::Message);
858 mMsg->setContent(mailData);
859 mMsg->parse();
860
861 // render the mail
862 StringHtmlWriter htmlWriter;
863 ObjectTreeSource source(&htmlWriter);
864 MimeTreeParser::ObjectTreeParser otp(&source, mNodeHelper.get());
865
866 otp.parseObjectTree(mMsg.data());
867 mPartTree = otp.parsedPart().dynamicCast<MimeTreeParser::MessagePart>();
868
869 mEmbeddedPartMap = htmlWriter.embeddedParts();
870 mHtml = htmlWriter.html();
871
872 mTree = std::make_shared<Part>();
873 createTree(mPartTree, mTree);
874}
875
876
877void ParserPrivate::createTree(const MimeTreeParser::MessagePart::Ptr &start, const Part::Ptr &tree)
878{
879 foreach (const auto &mp, start->subParts()) {
880 const auto m = mp.dynamicCast<MimeTreeParser::MessagePart>();
881 const auto text = mp.dynamicCast<MimeTreeParser::TextMessagePart>();
882 const auto alternative = mp.dynamicCast<MimeTreeParser::AlternativeMessagePart>();
883 const auto html = mp.dynamicCast<MimeTreeParser::HtmlMessagePart>();
884 const auto attachment = mp.dynamicCast<MimeTreeParser::AttachmentMessagePart>();
885 if (attachment) {
886 auto part = std::make_shared<SinglePart>();
887 part->d->fillFrom(attachment);
888 tree->d->appendSubPart(part);
889 } else if (text) {
890 auto part = std::make_shared<SinglePart>();
891 part->d->fillFrom(text);
892 tree->d->appendSubPart(part);
893 } else if (alternative) {
894 auto part = std::make_shared<AlternativePart>();
895 part->d->fillFrom(alternative);
896 tree->d->appendSubPart(part);
897 } else if (html) {
898 auto part = std::make_shared<SinglePart>();
899 part->d->fillFrom(html);
900 tree->d->appendSubPart(part);
901 } else {
902 const auto enc = mp.dynamicCast<MimeTreeParser::EncryptedMessagePart>();
903 const auto sig = mp.dynamicCast<MimeTreeParser::SignedMessagePart>();
904 if (enc || sig) {
905 auto subTree = std::make_shared<Part>();
906 if (enc) {
907 subTree->d->appendEncryption(enc);
908 }
909 if (sig) {
910 subTree->d->appendSignature(sig);
911 }
912 createTree(m, subTree);
913 foreach(const auto &p, subTree->subParts()) {
914 tree->d->appendSubPart(p);
915 if (enc) {
916 p->d->setEncryptions(subTree->d->encryptions());
917 }
918 if (sig) {
919 p->d->setSignatures(subTree->d->signatures());
920 }
921 }
922 } else {
923 createTree(m, tree);
924 }
925 }
926 }
927}
928
929Parser::Parser(const QByteArray& mimeMessage)
930 :d(std::unique_ptr<ParserPrivate>(new ParserPrivate(this)))
931{
932 d->setMessage(mimeMessage);
933}
934
935Parser::~Parser()
936{
937}
938
939Part::Ptr Parser::getPart(const QUrl &url)
940{
941 if (url.scheme() == QStringLiteral("cid") && !url.path().isEmpty()) {
942 const auto cid = url.path();
943 return find(d->mTree, [&cid](const Part::Ptr &p){
944 const auto mime = p->mailMime();
945 return mime->cid() == cid;
946 });
947 }
948 return Part::Ptr();
949}
950
951QVector<Part::Ptr> Parser::collectContentParts() const
952{
953 return collect(d->mTree, [](const Part::Ptr &p){return p->type() != "EncapsulatedPart";},
954 [](const Content::Ptr &content){
955 const auto mime = content->mailMime();
956
957 if (!mime) {
958 return true;
959 }
960
961 if (mime->isFirstTextPart()) {
962 return true;
963 }
964
965 {
966 auto _mime = content->parent()->mailMime();
967 while (_mime) {
968 if (_mime && (_mime->isTopLevelPart() || _mime->isFirstTextPart())) {
969 return true;
970 }
971 if (_mime->isFirstPart()) {
972 _mime = _mime->parent();
973 } else {
974 break;
975 }
976 }
977 }
978 const auto cd = mime->disposition();
979 if (cd && cd == MailMime::Inline) {
980 // explict "inline" disposition:
981 return true;
982 }
983 if (cd && cd == MailMime::Attachment) {
984 // explicit "attachment" disposition:
985 return false;
986 }
987
988 const auto ct = mime->mimetype();
989 if (ct.name().trimmed().toLower() == "text" && ct.name().trimmed().isEmpty() &&
990 (!mime || mime->filename().trimmed().isEmpty())) {
991 // text/* w/o filename parameter:
992 return true;
993 }
994 return false;
995 });
996}
997
998
999QVector<Part::Ptr> Parser::collectAttachmentParts() const
1000{
1001 return collect(d->mTree, [](const Part::Ptr &p){return p->type() != "EncapsulatedPart";},
1002 [](const Content::Ptr &content){
1003 const auto mime = content->mailMime();
1004
1005 if (!mime) {
1006 return false;
1007 }
1008
1009 if (mime->isFirstTextPart()) {
1010 return false;
1011 }
1012
1013 {
1014 QMimeDatabase mimeDb;
1015 auto _mime = content->parent()->mailMime();
1016 const auto parent = _mime->parent();
1017 if (parent) {
1018 const auto mimetype = parent->mimetype();
1019 if (mimetype == mimeDb.mimeTypeForName("multipart/related")) {
1020 return false;
1021 }
1022 }
1023 while (_mime) {
1024 if (_mime && (_mime->isTopLevelPart() || _mime->isFirstTextPart())) {
1025 return false;
1026 }
1027 if (_mime->isFirstPart()) {
1028 _mime = _mime->parent();
1029 } else {
1030 break;
1031 }
1032 }
1033 }
1034 const auto cd = mime->disposition();
1035 if (cd && cd == MailMime::Inline) {
1036 // explict "inline" disposition:
1037 return false;
1038 }
1039 if (cd && cd == MailMime::Attachment) {
1040 // explicit "attachment" disposition:
1041 return true;
1042 }
1043
1044 const auto ct = mime->mimetype();
1045 if (ct.name().trimmed().toLower() == "text" && ct.name().trimmed().isEmpty() &&
1046 (!mime || mime->filename().trimmed().isEmpty())) {
1047 // text/* w/o filename parameter:
1048 return false;
1049 }
1050 return true;
1051 });
1052}
1053
1054QVector<Part::Ptr> Parser::collect(const Part::Ptr &start, std::function<bool(const Part::Ptr &)> select, std::function<bool(const Content::Ptr &)> filter) const
1055{
1056 QVector<Part::Ptr> ret;
1057 foreach (const auto &part, start->subParts()) {
1058 QVector<QByteArray> contents;
1059 foreach(const auto &ct, part->availableContents()) {
1060 foreach(const auto &content, part->content(ct)) {
1061 if (filter(content)) {
1062 contents.append(ct);
1063 break;
1064 }
1065 }
1066 }
1067 if (!contents.isEmpty()) {
1068 ret.append(part);
1069 }
1070 if (select(part)){
1071 ret += collect(part, select, filter);
1072 }
1073 }
1074 return ret;
1075}
1076
1077Part::Ptr Parser::find(const Part::Ptr &start, std::function<bool(const Part::Ptr &)> select) const
1078{
1079 foreach (const auto &part, start->subParts()) {
1080 if (select(part)) {
1081 return part;
1082 }
1083 const auto ret = find(part, select);
1084 if (ret) {
1085 return ret;
1086 }
1087 }
1088 return Part::Ptr();
1089}