summaryrefslogtreecommitdiffstats
path: root/framework/src/domain/mime/messageparser_new.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/domain/mime/messageparser_new.cpp')
-rw-r--r--framework/src/domain/mime/messageparser_new.cpp513
1 files changed, 513 insertions, 0 deletions
diff --git a/framework/src/domain/mime/messageparser_new.cpp b/framework/src/domain/mime/messageparser_new.cpp
new file mode 100644
index 00000000..7e7dbfa6
--- /dev/null
+++ b/framework/src/domain/mime/messageparser_new.cpp
@@ -0,0 +1,513 @@
1/*
2 Copyright (c) 2016 Sandro Knauß <knauss@kolabsys.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 "messageparser.h"
21#include "mimetreeparser/interface.h"
22#include "htmlutils.h"
23
24#include <QDebug>
25#include <QTextDocument>
26
27Q_DECLARE_METATYPE(Part *)
28Q_DECLARE_METATYPE(Content *)
29Q_DECLARE_METATYPE(Signature *)
30Q_DECLARE_METATYPE(Encryption *)
31
32class Entry;
33
34class NewModelPrivate
35{
36public:
37 NewModelPrivate(NewModel *q_ptr, const std::shared_ptr<Parser> &parser);
38 ~NewModelPrivate();
39
40 void createTree();
41
42 QSharedPointer<QVariant> getVar(const std::shared_ptr<Signature> &sig);
43 QSharedPointer<QVariant> getVar(const std::shared_ptr<Encryption> &enc);
44 QSharedPointer<QVariant> getVar(const std::shared_ptr<Part> &part);
45 QSharedPointer<QVariant> getVar(Part *part);
46 QSharedPointer<QVariant> getVar(const std::shared_ptr<Content> &content);
47 QSharedPointer<QVariant> getVar(Content *content);
48
49 int getPos(Signature *sig);
50 int getPos(Encryption *enc);
51 int getPos(Part *part);
52 int getPos(Content *content);
53
54 NewModel *q;
55 QVector<Part::Ptr> mParts;
56 std::unique_ptr<Entry> mRoot;
57
58 std::shared_ptr<Parser> mParser;
59private:
60 QMap<std::shared_ptr<Signature>, QSharedPointer<QVariant>> mSignatureMap;
61 QMap<std::shared_ptr<Encryption>, QSharedPointer<QVariant>> mEncryptionMap;
62 QMap<Part *, QSharedPointer<QVariant>> mPartMap;
63 QMap<Content *, QSharedPointer<QVariant>> mCMap;
64};
65
66class Entry
67{
68public:
69 Entry(NewModelPrivate *model)
70 : mParent(nullptr)
71 , mNewModelPrivate(model)
72 {
73 }
74
75 ~Entry()
76 {
77 foreach(auto child, mChildren) {
78 delete child;
79 }
80 mChildren.clear();
81 }
82
83 void addChild(Entry *entry)
84 {
85 mChildren.append(entry);
86 entry->mParent = this;
87 }
88
89 Entry *addSignatures(QVector<Signature::Ptr> signatures)
90 {
91 auto ret = this;
92 foreach(const auto &sig, signatures) {
93 auto entry = new Entry(mNewModelPrivate);
94 entry->mData = mNewModelPrivate->getVar(sig);
95 ret->addChild(entry);
96 ret = entry;
97 }
98 return ret;
99 }
100
101 Entry *addEncryptions(QVector<Encryption::Ptr> encryptions)
102 {
103 auto ret = this;
104 foreach(const auto &enc, encryptions) {
105 auto entry = new Entry(mNewModelPrivate);
106 entry->mData = mNewModelPrivate->getVar(enc);
107 ret->addChild(entry);
108 ret = entry;
109 }
110 return ret;
111 }
112
113 Entry *addPart(Part *part)
114 {
115 auto entry = new Entry(mNewModelPrivate);
116 entry->mData = mNewModelPrivate->getVar(part);
117 addChild(entry);
118
119 foreach(const auto &content, part->content()) {
120 auto _entry = entry;
121 _entry = _entry->addEncryptions(content->encryptions().mid(part->encryptions().size()));
122 _entry = _entry->addSignatures(content->signatures().mid(part->signatures().size()));
123 auto c = new Entry(mNewModelPrivate);
124 c->mData = mNewModelPrivate->getVar(content);
125 _entry->addChild(c);
126 }
127// foreach(const auto &content, part->availableContents()) {
128// foreach(const auto &contentPart, part->content(content)) {
129// auto _entry = entry;
130// _entry = _entry->addEncryptions(contentPart->encryptions().mid(part->encryptions().size()));
131// _entry = _entry->addSignatures(contentPart->signatures().mid(part->signatures().size()));
132// auto c = new Entry(mNewModelPrivate);
133// c->mData = mNewModelPrivate->getVar(contentPart);
134// _entry->addChild(c);
135// }
136// }
137 foreach(const auto &sp, part->subParts()) {
138 auto _entry = entry;
139 _entry = _entry->addEncryptions(sp->encryptions().mid(part->encryptions().size()));
140 _entry = _entry->addSignatures(sp->signatures().mid(part->signatures().size()));
141 _entry->addPart(sp.get());
142 }
143 return entry;
144 }
145
146 int pos()
147 {
148 if(!mParent) {
149 return -1;
150 }
151 int i=0;
152 foreach(const auto &child, mParent->mChildren) {
153 if (child == this) {
154 return i;
155 }
156 i++;
157 }
158 return -1;
159 }
160
161 QSharedPointer<QVariant> mData;
162
163 Entry *mParent;
164 QVector<Entry *> mChildren;
165 NewModelPrivate *mNewModelPrivate;
166};
167
168
169NewModelPrivate::NewModelPrivate(NewModel *q_ptr, const std::shared_ptr<Parser> &parser)
170 : q(q_ptr)
171 , mRoot(std::unique_ptr<Entry>(new Entry(this)))
172 , mParser(parser)
173{
174 mParts = mParser->collectContentParts();
175 createTree();
176}
177
178NewModelPrivate::~NewModelPrivate()
179{
180}
181
182void NewModelPrivate::createTree()
183{
184 auto root = mRoot.get();
185 auto parent = root;
186 Part *pPart = nullptr;
187 QVector<Signature::Ptr> signatures;
188 QVector<Encryption::Ptr> encryptions;
189 foreach(const auto part, mParts) {
190 auto _parent = parent;
191 if (pPart != part->parent()) {
192 auto _parent = root;
193 _parent = _parent->addEncryptions(part->parent()->encryptions());
194 _parent = _parent->addSignatures(part->parent()->signatures());
195 signatures = part->parent()->signatures();
196 encryptions = part->parent()->encryptions();
197 parent = _parent;
198 pPart = part->parent();
199 }
200 _parent = _parent->addEncryptions(part->encryptions().mid(encryptions.size()));
201 _parent = _parent->addSignatures(part->signatures().mid(signatures.size()));
202 _parent->addPart(part.get());
203 }
204}
205
206QSharedPointer<QVariant> NewModelPrivate::getVar(const std::shared_ptr<Signature> &sig)
207{
208 if (!mSignatureMap.contains(sig)) {
209 auto var = new QVariant();
210 var->setValue(sig.get());
211 mSignatureMap.insert(sig, QSharedPointer<QVariant>(var));
212 }
213 return mSignatureMap.value(sig);
214}
215
216QSharedPointer<QVariant> NewModelPrivate::getVar(const std::shared_ptr<Encryption> &enc)
217{
218 if (!mEncryptionMap.contains(enc)) {
219 auto var = new QVariant();
220 var->setValue(enc.get());
221 mEncryptionMap.insert(enc, QSharedPointer<QVariant>(var));
222 }
223 return mEncryptionMap.value(enc);
224}
225
226QSharedPointer<QVariant> NewModelPrivate::getVar(const std::shared_ptr<Part> &part)
227{
228 return getVar(part.get());
229}
230
231QSharedPointer<QVariant> NewModelPrivate::getVar(Part *part)
232{
233 if (!mPartMap.contains(part)) {
234 auto var = new QVariant();
235 var->setValue(part);
236 mPartMap.insert(part, QSharedPointer<QVariant>(var));
237 }
238 return mPartMap.value(part);
239}
240
241QSharedPointer<QVariant> NewModelPrivate::getVar(const std::shared_ptr<Content> &content)
242{
243 return getVar(content.get());
244}
245
246QSharedPointer<QVariant> NewModelPrivate::getVar(Content *content)
247{
248 if (!mCMap.contains(content)) {
249 auto var = new QVariant();
250 var->setValue(content);
251 mCMap.insert(content, QSharedPointer<QVariant>(var));
252 }
253 return mCMap.value(content);
254}
255
256int NewModelPrivate::getPos(Signature *signature)
257{
258 const auto first = mParts.first();
259 int i = 0;
260 foreach(const auto &sig, first->signatures()) {
261 if (sig.get() == signature) {
262 break;
263 }
264 i++;
265 }
266 return i;
267}
268
269int NewModelPrivate::getPos(Encryption *encryption)
270{
271 const auto first = mParts.first();
272 int i = 0;
273 foreach(const auto &enc, first->encryptions()) {
274 if (enc.get() == encryption) {
275 break;
276 }
277 i++;
278 }
279 return i;
280}
281
282int NewModelPrivate::getPos(Part *part)
283{
284 int i = 0;
285 foreach(const auto &p, mParts) {
286 if (p.get() == part) {
287 break;
288 }
289 i++;
290 }
291 return i;
292}
293
294int NewModelPrivate::getPos(Content *content)
295{
296 int i = 0;
297 foreach(const auto &c, content->parent()->content()) {
298 if (c.get() == content) {
299 break;
300 }
301 i++;
302 }
303 return i;
304}
305
306NewModel::NewModel(std::shared_ptr<Parser> parser)
307 : d(std::unique_ptr<NewModelPrivate>(new NewModelPrivate(this, parser)))
308{
309}
310
311NewModel::~NewModel()
312{
313}
314
315QHash<int, QByteArray> NewModel::roleNames() const
316{
317 QHash<int, QByteArray> roles;
318 roles[TypeRole] = "type";
319 roles[ContentRole] = "content";
320 roles[IsComplexHtmlContentRole] = "complexHtmlContent";
321 roles[IsEmbededRole] = "embeded";
322 roles[SecurityLevelRole] = "securityLevel";
323 roles[EncryptionErrorType] = "errorType";
324 roles[EncryptionErrorString] = "errorString";
325 return roles;
326}
327
328QModelIndex NewModel::index(int row, int column, const QModelIndex &parent) const
329{
330 if (row < 0 || column != 0) {
331 return QModelIndex();
332 }
333 Entry *entry = d->mRoot.get();
334 if (parent.isValid()) {
335 entry = static_cast<Entry *>(parent.internalPointer());
336 }
337
338 if (row < entry->mChildren.size()) {
339 return createIndex(row, column, entry->mChildren.at(row));
340 }
341 return QModelIndex();
342}
343
344QVariant NewModel::data(const QModelIndex &index, int role) const
345{
346 if (!index.isValid()) {
347 switch (role) {
348 case Qt::DisplayRole:
349 return QString("root");
350 case IsEmbededRole:
351 return false;
352 }
353 return QVariant();
354 }
355
356 if (index.internalPointer()) {
357 const auto entry = static_cast<Entry *>(index.internalPointer());
358 const auto _data = entry->mData;
359 if (entry == d->mRoot.get()|| !_data) {
360 switch (role) {
361 case Qt::DisplayRole:
362 return QString("root");
363 case IsEmbededRole:
364 return false;
365 }
366 return QVariant();
367 }
368 if (_data->userType() == qMetaTypeId<Signature *>()) {
369 const auto signature = _data->value<Signature *>();
370 int i = d->getPos(signature);
371 switch(role) {
372 case Qt::DisplayRole:
373 return QStringLiteral("Signature%1").arg(i);
374 case TypeRole:
375 return QStringLiteral("Signature");
376 case SecurityLevelRole:
377 return QStringLiteral("RED");
378 case IsEmbededRole:
379 return data(index.parent(), IsEmbededRole);
380 }
381 } else if (_data->userType() == qMetaTypeId<Encryption *>()) {
382 const auto encryption = _data->value<Encryption *>();
383 int i = d->getPos(encryption);
384 switch(role) {
385 case Qt::DisplayRole:
386 return QStringLiteral("Encryption%1").arg(i);
387 case TypeRole:
388 return QStringLiteral("Encryption");
389 case SecurityLevelRole:
390 return QStringLiteral("GREEN");
391 case IsEmbededRole:
392 return data(index.parent(), IsEmbededRole);
393 case EncryptionErrorType:
394 {
395 switch(encryption->errorType()) {
396 case Encryption::NoError:
397 return QString();
398 case Encryption::PassphraseError:
399 return QStringLiteral("PassphraseError");
400 case Encryption::KeyMissing:
401 return QStringLiteral("KeyMissing");
402 default:
403 return QStringLiteral("UnknownError");
404 }
405 }
406 case EncryptionErrorString:
407 return encryption->errorString();
408 }
409 } else if (_data->userType() == qMetaTypeId<Part *>()) {
410 const auto part = _data->value<Part *>();
411 switch (role) {
412 case Qt::DisplayRole:
413 case TypeRole:
414 return QString::fromLatin1(part->type());
415 case IsEmbededRole:
416 return data(index.parent(), IsEmbededRole);
417 }
418 } else if (_data->userType() == qMetaTypeId<Content *>()) {
419 const auto content = _data->value<Content *>();
420 int i = d->getPos(content);
421 switch(role) {
422 case Qt::DisplayRole:
423 return QStringLiteral("Content%1").arg(i);
424 case TypeRole:
425 return QString::fromLatin1(content->type());
426 case IsEmbededRole:
427 return data(index.parent(), IsEmbededRole);
428 case IsComplexHtmlContentRole: {
429 const auto contentType = data(index, TypeRole).toString();
430 if (contentType == "HtmlContent") {
431 const auto text = content->encodedContent();
432 if (text.contains("<!DOCTYPE html PUBLIC")) {
433 return true;
434 }
435 //Media queries are too advanced
436 if (text.contains("@media")) {
437 return true;
438 }
439 if (text.contains("<style")) {
440 return true;
441 }
442 return false;
443 } else {
444 return false;
445 }
446 break;
447 }
448 case ContentRole: {
449 auto text = content->encodedContent();
450 const auto contentType = data(index, TypeRole).toString();
451 if (contentType == "HtmlContent") {
452 const auto rx = QRegExp("(src)\\s*=\\s*(\"|')(cid:[^\"']+)\\2");
453 int pos = 0;
454 while ((pos = rx.indexIn(text, pos)) != -1) {
455 const auto link = QUrl(rx.cap(3).toUtf8());
456 pos += rx.matchedLength();
457 const auto repl = d->mParser->getPart(link);
458 if (!repl) {
459 continue;
460 }
461 const auto content = repl->content();
462 if(content.size() < 1) {
463 continue;
464 }
465 const auto mailMime = content.first()->mailMime();
466 const auto mimetype = mailMime->mimetype().name();
467 if (mimetype.startsWith("image/")) {
468 const auto data = content.first()->content();
469 text.replace(rx.cap(0), QString("src=\"data:%1;base64,%2\"").arg(mimetype, QString::fromLatin1(data.toBase64())));
470 }
471 }
472 } else { //We assume plain
473 //We alwas do richtext (so we get highlighted links and stuff).
474 return HtmlUtils::linkify(Qt::convertFromPlainText(text));
475 }
476 return text;
477 }
478 }
479 }
480 }
481 return QVariant();
482}
483
484QModelIndex NewModel::parent(const QModelIndex &index) const
485{
486 if (!index.internalPointer()) {
487 return QModelIndex();
488 }
489 const auto entry = static_cast<Entry *>(index.internalPointer());
490 if (entry->mParent && entry->mParent != d->mRoot.get()) {
491 return createIndex(entry->pos(), 0, entry->mParent);
492 }
493 return QModelIndex();
494}
495
496int NewModel::rowCount(const QModelIndex &parent) const
497{
498 if (!parent.isValid()) {
499 return d->mRoot->mChildren.size();
500 } else {
501 if (!parent.internalPointer()) {
502 return 0;
503 }
504 const auto entry = static_cast<Entry *>(parent.internalPointer());
505 return entry->mChildren.size();
506 }
507 return 0;
508}
509
510int NewModel::columnCount(const QModelIndex &parent) const
511{
512 return 1;
513}