diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2017-05-29 16:17:04 +0200 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2017-06-04 12:57:04 +0200 |
commit | e452707fdfbd61be1e5633b516b653b7337e7865 (patch) | |
tree | 1e1d4b48ebf8d381f292436f2ba04b8763edc5de /framework/src/domain/mime/mimetreeparser/nodehelper.cpp | |
parent | 5a1033bdace740799a6e03389bee30e5a4de5d44 (diff) | |
download | kube-e452707fdfbd61be1e5633b516b653b7337e7865.tar.gz kube-e452707fdfbd61be1e5633b516b653b7337e7865.zip |
Reduced the messagetreeparser to aproximately what we actually require
While in a much more managable state it's still not pretty.
However, further refactoring can now gradually happen as we need to do
further work on it.
Things that should happen eventually:
* Simplify the logic that creates the messageparts (we don't need the whole formatter plugin complexity)
* Get rid of the nodehelper (let the parts hold the necessary data)
* Get rid of partmetadata (let the part handleit)
Diffstat (limited to 'framework/src/domain/mime/mimetreeparser/nodehelper.cpp')
-rw-r--r-- | framework/src/domain/mime/mimetreeparser/nodehelper.cpp | 544 |
1 files changed, 544 insertions, 0 deletions
diff --git a/framework/src/domain/mime/mimetreeparser/nodehelper.cpp b/framework/src/domain/mime/mimetreeparser/nodehelper.cpp new file mode 100644 index 00000000..3005ea0f --- /dev/null +++ b/framework/src/domain/mime/mimetreeparser/nodehelper.cpp | |||
@@ -0,0 +1,544 @@ | |||
1 | /* | ||
2 | Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net | ||
3 | Copyright (c) 2009 Andras Mantia <andras@kdab.net> | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License along | ||
16 | with this program; if not, write to the Free Software Foundation, Inc., | ||
17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
18 | */ | ||
19 | |||
20 | #include "nodehelper.h" | ||
21 | #include "mimetreeparser_debug.h" | ||
22 | #include "partmetadata.h" | ||
23 | #include "bodypart.h" | ||
24 | #include "attachmenttemporaryfilesdirs.h" | ||
25 | |||
26 | #include <KMime/Content> | ||
27 | #include <KMime/Message> | ||
28 | #include <KMime/Headers> | ||
29 | |||
30 | #include <QTemporaryFile> | ||
31 | #include <KLocalizedString> | ||
32 | #include <kcharsets.h> | ||
33 | |||
34 | #include <QUrl> | ||
35 | #include <QDir> | ||
36 | #include <QTextCodec> | ||
37 | |||
38 | #include <string> | ||
39 | #include <sstream> | ||
40 | #include <algorithm> | ||
41 | #include <KCharsets> | ||
42 | #include <QMimeDatabase> | ||
43 | #include <QMimeType> | ||
44 | #include <QFileDevice> | ||
45 | |||
46 | namespace MimeTreeParser | ||
47 | { | ||
48 | |||
49 | NodeHelper::NodeHelper() : | ||
50 | mAttachmentFilesDir(new AttachmentTemporaryFilesDirs()) | ||
51 | { | ||
52 | //TODO(Andras) add methods to modify these prefixes | ||
53 | |||
54 | mLocalCodec = QTextCodec::codecForLocale(); | ||
55 | |||
56 | // In the case of Japan. Japanese locale name is "eucjp" but | ||
57 | // The Japanese mail systems normally used "iso-2022-jp" of locale name. | ||
58 | // We want to change locale name from eucjp to iso-2022-jp at KMail only. | ||
59 | |||
60 | // (Introduction to i18n, 6.6 Limit of Locale technology): | ||
61 | // EUC-JP is the de-facto standard for UNIX systems, ISO 2022-JP | ||
62 | // is the standard for Internet, and Shift-JIS is the encoding | ||
63 | // for Windows and Macintosh. | ||
64 | if (mLocalCodec) { | ||
65 | const QByteArray codecNameLower = mLocalCodec->name().toLower(); | ||
66 | if (codecNameLower == "eucjp" | ||
67 | #if defined Q_OS_WIN || defined Q_OS_MACX | ||
68 | || codecNameLower == "shift-jis" // OK? | ||
69 | #endif | ||
70 | ) { | ||
71 | mLocalCodec = QTextCodec::codecForName("jis7"); | ||
72 | // QTextCodec *cdc = QTextCodec::codecForName("jis7"); | ||
73 | // QTextCodec::setCodecForLocale(cdc); | ||
74 | // KLocale::global()->setEncoding(cdc->mibEnum()); | ||
75 | } | ||
76 | } | ||
77 | } | ||
78 | |||
79 | NodeHelper::~NodeHelper() | ||
80 | { | ||
81 | if (mAttachmentFilesDir) { | ||
82 | mAttachmentFilesDir->forceCleanTempFiles(); | ||
83 | delete mAttachmentFilesDir; | ||
84 | mAttachmentFilesDir = nullptr; | ||
85 | } | ||
86 | clear(); | ||
87 | } | ||
88 | |||
89 | void NodeHelper::setNodeProcessed(KMime::Content *node, bool recurse) | ||
90 | { | ||
91 | if (!node) { | ||
92 | return; | ||
93 | } | ||
94 | mProcessedNodes.append(node); | ||
95 | qCDebug(MIMETREEPARSER_LOG) << "Node processed: " << node->index().toString() << node->contentType()->as7BitString(); | ||
96 | //<< " decodedContent" << node->decodedContent(); | ||
97 | if (recurse) { | ||
98 | const auto contents = node->contents(); | ||
99 | for (KMime::Content *c : contents) { | ||
100 | setNodeProcessed(c, true); | ||
101 | } | ||
102 | } | ||
103 | } | ||
104 | |||
105 | void NodeHelper::setNodeUnprocessed(KMime::Content *node, bool recurse) | ||
106 | { | ||
107 | if (!node) { | ||
108 | return; | ||
109 | } | ||
110 | mProcessedNodes.removeAll(node); | ||
111 | |||
112 | //avoid double addition of extra nodes, eg. encrypted attachments | ||
113 | const QMap<KMime::Content *, QList<KMime::Content *> >::iterator it = mExtraContents.find(node); | ||
114 | if (it != mExtraContents.end()) { | ||
115 | Q_FOREACH (KMime::Content *c, it.value()) { | ||
116 | KMime::Content *p = c->parent(); | ||
117 | if (p) { | ||
118 | p->removeContent(c); | ||
119 | } | ||
120 | } | ||
121 | qDeleteAll(it.value()); | ||
122 | qCDebug(MIMETREEPARSER_LOG) << "mExtraContents deleted for" << it.key(); | ||
123 | mExtraContents.erase(it); | ||
124 | } | ||
125 | |||
126 | qCDebug(MIMETREEPARSER_LOG) << "Node UNprocessed: " << node; | ||
127 | if (recurse) { | ||
128 | const auto contents = node->contents(); | ||
129 | for (KMime::Content *c : contents) { | ||
130 | setNodeUnprocessed(c, true); | ||
131 | } | ||
132 | } | ||
133 | } | ||
134 | |||
135 | bool NodeHelper::nodeProcessed(KMime::Content *node) const | ||
136 | { | ||
137 | if (!node) { | ||
138 | return true; | ||
139 | } | ||
140 | return mProcessedNodes.contains(node); | ||
141 | } | ||
142 | |||
143 | void NodeHelper::clear() | ||
144 | { | ||
145 | mProcessedNodes.clear(); | ||
146 | mOverrideCodecs.clear(); | ||
147 | QMap<KMime::Content *, QList<KMime::Content *> >::ConstIterator end(mExtraContents.constEnd()); | ||
148 | |||
149 | for (QMap<KMime::Content *, QList<KMime::Content *> >::ConstIterator it = mExtraContents.constBegin(); it != end; ++it) { | ||
150 | Q_FOREACH (KMime::Content *c, it.value()) { | ||
151 | KMime::Content *p = c->parent(); | ||
152 | if (p) { | ||
153 | p->removeContent(c); | ||
154 | } | ||
155 | } | ||
156 | qDeleteAll(it.value()); | ||
157 | qCDebug(MIMETREEPARSER_LOG) << "mExtraContents deleted for" << it.key(); | ||
158 | } | ||
159 | mExtraContents.clear(); | ||
160 | } | ||
161 | |||
162 | |||
163 | PartMetaData NodeHelper::partMetaData(KMime::Content *node) | ||
164 | { | ||
165 | return mPartMetaDatas.value(node, PartMetaData()); | ||
166 | } | ||
167 | |||
168 | void NodeHelper::setPartMetaData(KMime::Content *node, const PartMetaData &metaData) | ||
169 | { | ||
170 | mPartMetaDatas.insert(node, metaData); | ||
171 | } | ||
172 | |||
173 | void NodeHelper::forceCleanTempFiles() | ||
174 | { | ||
175 | mAttachmentFilesDir->forceCleanTempFiles(); | ||
176 | delete mAttachmentFilesDir; | ||
177 | mAttachmentFilesDir = nullptr; | ||
178 | } | ||
179 | |||
180 | void NodeHelper::removeTempFiles() | ||
181 | { | ||
182 | //Don't delete it it will delete in class | ||
183 | mAttachmentFilesDir->removeTempFiles(); | ||
184 | mAttachmentFilesDir = new AttachmentTemporaryFilesDirs(); | ||
185 | } | ||
186 | |||
187 | void NodeHelper::addTempFile(const QString &file) | ||
188 | { | ||
189 | mAttachmentFilesDir->addTempFile(file); | ||
190 | } | ||
191 | |||
192 | bool NodeHelper::isInEncapsulatedMessage(KMime::Content *node) | ||
193 | { | ||
194 | const KMime::Content *const topLevel = node->topLevel(); | ||
195 | const KMime::Content *cur = node; | ||
196 | while (cur && cur != topLevel) { | ||
197 | const bool parentIsMessage = cur->parent() && cur->parent()->contentType(false) && | ||
198 | cur->parent()->contentType()->mimeType().toLower() == "message/rfc822"; | ||
199 | if (parentIsMessage && cur->parent() != topLevel) { | ||
200 | return true; | ||
201 | } | ||
202 | cur = cur->parent(); | ||
203 | } | ||
204 | return false; | ||
205 | } | ||
206 | |||
207 | QByteArray NodeHelper::charset(KMime::Content *node) | ||
208 | { | ||
209 | if (node->contentType(false)) { | ||
210 | return node->contentType(false)->charset(); | ||
211 | } else { | ||
212 | return node->defaultCharset(); | ||
213 | } | ||
214 | } | ||
215 | |||
216 | void NodeHelper::magicSetType(KMime::Content *node, bool aAutoDecode) | ||
217 | { | ||
218 | const QByteArray body = (aAutoDecode) ? node->decodedContent() : node->body(); | ||
219 | QMimeDatabase db; | ||
220 | QMimeType mime = db.mimeTypeForData(body); | ||
221 | |||
222 | QString mimetype = mime.name(); | ||
223 | node->contentType()->setMimeType(mimetype.toLatin1()); | ||
224 | } | ||
225 | |||
226 | void NodeHelper::setOverrideCodec(KMime::Content *node, const QTextCodec *codec) | ||
227 | { | ||
228 | if (!node) { | ||
229 | return; | ||
230 | } | ||
231 | |||
232 | mOverrideCodecs[node] = codec; | ||
233 | } | ||
234 | |||
235 | const QTextCodec *NodeHelper::codec(KMime::Content *node) | ||
236 | { | ||
237 | if (! node) { | ||
238 | return mLocalCodec; | ||
239 | } | ||
240 | |||
241 | const QTextCodec *c = mOverrideCodecs.value(node, nullptr); | ||
242 | if (!c) { | ||
243 | // no override-codec set for this message, try the CT charset parameter: | ||
244 | QByteArray charset = node->contentType()->charset(); | ||
245 | |||
246 | // utf-8 is a superset of us-ascii, so we don't loose anything, if we it insead | ||
247 | // utf-8 is nowadays that widely, that it is a good guess to use it to fix issus with broken clients. | ||
248 | if (charset.toLower() == "us-ascii") { | ||
249 | charset = "utf-8"; | ||
250 | } | ||
251 | c = codecForName(charset); | ||
252 | } | ||
253 | if (!c) { | ||
254 | // no charset means us-ascii (RFC 2045), so using local encoding should | ||
255 | // be okay | ||
256 | c = mLocalCodec; | ||
257 | } | ||
258 | return c; | ||
259 | } | ||
260 | |||
261 | const QTextCodec *NodeHelper::codecForName(const QByteArray &_str) | ||
262 | { | ||
263 | if (_str.isEmpty()) { | ||
264 | return nullptr; | ||
265 | } | ||
266 | QByteArray codec = _str.toLower(); | ||
267 | return KCharsets::charsets()->codecForName(QLatin1String(codec)); | ||
268 | } | ||
269 | |||
270 | QString NodeHelper::fileName(const KMime::Content *node) | ||
271 | { | ||
272 | QString name = const_cast<KMime::Content *>(node)->contentDisposition()->filename(); | ||
273 | if (name.isEmpty()) { | ||
274 | name = const_cast<KMime::Content *>(node)->contentType()->name(); | ||
275 | } | ||
276 | |||
277 | name = name.trimmed(); | ||
278 | return name; | ||
279 | } | ||
280 | |||
281 | /*! | ||
282 | Creates a persistent index string that bridges the gap between the | ||
283 | permanent nodes and the temporary ones. | ||
284 | |||
285 | Used internally for robust indexing. | ||
286 | */ | ||
287 | QString NodeHelper::persistentIndex(const KMime::Content *node) const | ||
288 | { | ||
289 | if (!node) { | ||
290 | return QString(); | ||
291 | } | ||
292 | |||
293 | QString indexStr = node->index().toString(); | ||
294 | if (indexStr.isEmpty()) { | ||
295 | QMapIterator<KMime::Message::Content *, QList<KMime::Content *> > it(mExtraContents); | ||
296 | while (it.hasNext()) { | ||
297 | it.next(); | ||
298 | const auto &extraNodes = it.value(); | ||
299 | for (int i = 0; i < extraNodes.size(); i++) { | ||
300 | if (extraNodes[i] == node) { | ||
301 | indexStr = QString::fromLatin1("e%1").arg(i); | ||
302 | const QString parentIndex = persistentIndex(it.key()); | ||
303 | if (!parentIndex.isEmpty()) { | ||
304 | indexStr = QString::fromLatin1("%1:%2").arg(parentIndex, indexStr); | ||
305 | } | ||
306 | qWarning() << "Persistentindex: " << indexStr; | ||
307 | return indexStr; | ||
308 | } | ||
309 | } | ||
310 | } | ||
311 | } else { | ||
312 | const KMime::Content *const topLevel = node->topLevel(); | ||
313 | //if the node is an extra node, prepend the index of the extra node to the url | ||
314 | QMapIterator<KMime::Message::Content *, QList<KMime::Content *> > it(mExtraContents); | ||
315 | while (it.hasNext()) { | ||
316 | it.next(); | ||
317 | const QList<KMime::Content *> &extraNodes = extraContents(it.key()); | ||
318 | for (int i = 0; i < extraNodes.size(); ++i) { | ||
319 | KMime::Content *const extraNode = extraNodes[i]; | ||
320 | if (topLevel == extraNode) { | ||
321 | indexStr.prepend(QStringLiteral("e%1:").arg(i)); | ||
322 | const QString parentIndex = persistentIndex(it.key()); | ||
323 | if (!parentIndex.isEmpty()) { | ||
324 | indexStr = QStringLiteral("%1:%2").arg(parentIndex, indexStr); | ||
325 | } | ||
326 | qWarning() << "Persistentindex: " << indexStr; | ||
327 | return indexStr; | ||
328 | } | ||
329 | } | ||
330 | } | ||
331 | } | ||
332 | |||
333 | qWarning() << "Persistentindex: " << indexStr; | ||
334 | return indexStr; | ||
335 | } | ||
336 | |||
337 | KMime::Content *NodeHelper::contentFromIndex(KMime::Content *node, const QString &persistentIndex) const | ||
338 | { | ||
339 | KMime::Content *c = node->topLevel(); | ||
340 | if (c) { | ||
341 | const QStringList pathParts = persistentIndex.split(QLatin1Char(':'), QString::SkipEmptyParts); | ||
342 | const int pathPartsSize(pathParts.size()); | ||
343 | for (int i = 0; i < pathPartsSize; ++i) { | ||
344 | const QString &path = pathParts[i]; | ||
345 | if (path.startsWith(QLatin1Char('e'))) { | ||
346 | const QList<KMime::Content *> &extraParts = mExtraContents.value(c); | ||
347 | const int idx = path.midRef(1, -1).toInt(); | ||
348 | c = (idx < extraParts.size()) ? extraParts[idx] : nullptr; | ||
349 | } else { | ||
350 | c = c->content(KMime::ContentIndex(path)); | ||
351 | } | ||
352 | if (!c) { | ||
353 | break; | ||
354 | } | ||
355 | } | ||
356 | } | ||
357 | return c; | ||
358 | } | ||
359 | |||
360 | QString NodeHelper::asHREF(const KMime::Content *node, const QString &place) const | ||
361 | { | ||
362 | return QStringLiteral("attachment:%1?place=%2").arg(persistentIndex(node), place); | ||
363 | } | ||
364 | |||
365 | KMime::Content *NodeHelper::fromHREF(const KMime::Message::Ptr &mMessage, const QUrl &url) const | ||
366 | { | ||
367 | if (url.isEmpty()) { | ||
368 | return mMessage.data(); | ||
369 | } | ||
370 | |||
371 | if (!url.isLocalFile()) { | ||
372 | return contentFromIndex(mMessage.data(), url.adjusted(QUrl::StripTrailingSlash).path()); | ||
373 | } else { | ||
374 | const QString path = url.toLocalFile(); | ||
375 | // extract from /<path>/qttestn28554.index.2.3:0:2/unnamed -> "2.3:0:2" | ||
376 | // start of the index is something that is not a number followed by a dot: \D. | ||
377 | // index is only made of numbers,"." and ":": ([0-9.:]+) | ||
378 | // index is the last part of the folder name: / | ||
379 | const QRegExp rIndex(QStringLiteral("\\D\\.([e0-9.:]+)/")); | ||
380 | |||
381 | //search the occurence at most at the end | ||
382 | if (rIndex.lastIndexIn(path) != -1) { | ||
383 | return contentFromIndex(mMessage.data(), rIndex.cap(1)); | ||
384 | } | ||
385 | return mMessage.data(); | ||
386 | } | ||
387 | } | ||
388 | |||
389 | QString NodeHelper::fixEncoding(const QString &encoding) | ||
390 | { | ||
391 | QString returnEncoding = encoding; | ||
392 | // According to http://www.iana.org/assignments/character-sets, uppercase is | ||
393 | // preferred in MIME headers | ||
394 | const QString returnEncodingToUpper = returnEncoding.toUpper(); | ||
395 | if (returnEncodingToUpper.contains(QStringLiteral("ISO "))) { | ||
396 | returnEncoding = returnEncodingToUpper; | ||
397 | returnEncoding.replace(QLatin1String("ISO "), QStringLiteral("ISO-")); | ||
398 | } | ||
399 | return returnEncoding; | ||
400 | } | ||
401 | |||
402 | //----------------------------------------------------------------------------- | ||
403 | QString NodeHelper::encodingForName(const QString &descriptiveName) | ||
404 | { | ||
405 | QString encoding = KCharsets::charsets()->encodingForName(descriptiveName); | ||
406 | return NodeHelper::fixEncoding(encoding); | ||
407 | } | ||
408 | |||
409 | QStringList NodeHelper::supportedEncodings(bool usAscii) | ||
410 | { | ||
411 | QStringList encodingNames = KCharsets::charsets()->availableEncodingNames(); | ||
412 | QStringList encodings; | ||
413 | QMap<QString, bool> mimeNames; | ||
414 | QStringList::ConstIterator constEnd(encodingNames.constEnd()); | ||
415 | for (QStringList::ConstIterator it = encodingNames.constBegin(); | ||
416 | it != constEnd; ++it) { | ||
417 | QTextCodec *codec = KCharsets::charsets()->codecForName(*it); | ||
418 | QString mimeName = (codec) ? QString::fromLatin1(codec->name()).toLower() : (*it); | ||
419 | if (!mimeNames.contains(mimeName)) { | ||
420 | encodings.append(KCharsets::charsets()->descriptionForEncoding(*it)); | ||
421 | mimeNames.insert(mimeName, true); | ||
422 | } | ||
423 | } | ||
424 | encodings.sort(); | ||
425 | if (usAscii) { | ||
426 | encodings.prepend(KCharsets::charsets()->descriptionForEncoding(QStringLiteral("us-ascii"))); | ||
427 | } | ||
428 | return encodings; | ||
429 | } | ||
430 | |||
431 | QString NodeHelper::fromAsString(KMime::Content *node) const | ||
432 | { | ||
433 | if (auto topLevel = dynamic_cast<KMime::Message *>(node->topLevel())) { | ||
434 | return topLevel->from()->asUnicodeString(); | ||
435 | } else { | ||
436 | auto realNode = std::find_if(mExtraContents.cbegin(), mExtraContents.cend(), | ||
437 | [node](const QList<KMime::Content *> &nodes) { | ||
438 | return nodes.contains(node); | ||
439 | }); | ||
440 | if (realNode != mExtraContents.cend()) { | ||
441 | return fromAsString(realNode.key()); | ||
442 | } | ||
443 | } | ||
444 | |||
445 | return QString(); | ||
446 | } | ||
447 | |||
448 | void NodeHelper::attachExtraContent(KMime::Content *topLevelNode, KMime::Content *content) | ||
449 | { | ||
450 | qCDebug(MIMETREEPARSER_LOG) << "mExtraContents added for" << topLevelNode << " extra content: " << content; | ||
451 | mExtraContents[topLevelNode].append(content); | ||
452 | } | ||
453 | |||
454 | QList< KMime::Content * > NodeHelper::extraContents(KMime::Content *topLevelnode) const | ||
455 | { | ||
456 | return mExtraContents.value(topLevelnode); | ||
457 | } | ||
458 | |||
459 | void NodeHelper::mergeExtraNodes(KMime::Content *node) | ||
460 | { | ||
461 | if (!node) { | ||
462 | return; | ||
463 | } | ||
464 | |||
465 | const QList<KMime::Content * > extraNodes = extraContents(node); | ||
466 | for (KMime::Content *extra : extraNodes) { | ||
467 | if (node->bodyIsMessage()) { | ||
468 | qCWarning(MIMETREEPARSER_LOG) << "Asked to attach extra content to a kmime::message, this does not make sense. Attaching to:" << node << | ||
469 | node->encodedContent() << "\n====== with =======\n" << extra << extra->encodedContent(); | ||
470 | continue; | ||
471 | } | ||
472 | KMime::Content *c = new KMime::Content(node); | ||
473 | c->setContent(extra->encodedContent()); | ||
474 | c->parse(); | ||
475 | node->addContent(c); | ||
476 | } | ||
477 | |||
478 | Q_FOREACH (KMime::Content *child, node->contents()) { | ||
479 | mergeExtraNodes(child); | ||
480 | } | ||
481 | } | ||
482 | |||
483 | void NodeHelper::cleanFromExtraNodes(KMime::Content *node) | ||
484 | { | ||
485 | if (!node) { | ||
486 | return; | ||
487 | } | ||
488 | const QList<KMime::Content * > extraNodes = extraContents(node); | ||
489 | for (KMime::Content *extra : extraNodes) { | ||
490 | QByteArray s = extra->encodedContent(); | ||
491 | const auto children = node->contents(); | ||
492 | for (KMime::Content *c : children) { | ||
493 | if (c->encodedContent() == s) { | ||
494 | node->removeContent(c); | ||
495 | } | ||
496 | } | ||
497 | } | ||
498 | Q_FOREACH (KMime::Content *child, node->contents()) { | ||
499 | cleanFromExtraNodes(child); | ||
500 | } | ||
501 | } | ||
502 | |||
503 | KMime::Message *NodeHelper::messageWithExtraContent(KMime::Content *topLevelNode) | ||
504 | { | ||
505 | /*The merge is done in several steps: | ||
506 | 1) merge the extra nodes into topLevelNode | ||
507 | 2) copy the modified (merged) node tree into a new node tree | ||
508 | 3) restore the original node tree in topLevelNode by removing the extra nodes from it | ||
509 | |||
510 | The reason is that extra nodes are assigned by pointer value to the nodes in the original tree. | ||
511 | */ | ||
512 | if (!topLevelNode) { | ||
513 | return nullptr; | ||
514 | } | ||
515 | |||
516 | mergeExtraNodes(topLevelNode); | ||
517 | |||
518 | KMime::Message *m = new KMime::Message; | ||
519 | m->setContent(topLevelNode->encodedContent()); | ||
520 | m->parse(); | ||
521 | |||
522 | cleanFromExtraNodes(topLevelNode); | ||
523 | // qCDebug(MIMETREEPARSER_LOG) << "MESSAGE WITH EXTRA: " << m->encodedContent(); | ||
524 | // qCDebug(MIMETREEPARSER_LOG) << "MESSAGE WITHOUT EXTRA: " << topLevelNode->encodedContent(); | ||
525 | |||
526 | return m; | ||
527 | } | ||
528 | |||
529 | QVector<KMime::Content *> NodeHelper::attachmentsOfExtraContents() const | ||
530 | { | ||
531 | QVector<KMime::Content *> result; | ||
532 | for (auto it = mExtraContents.begin(); it != mExtraContents.end(); ++it) { | ||
533 | foreach (auto content, it.value()) { | ||
534 | if (KMime::isAttachment(content)) { | ||
535 | result.push_back(content); | ||
536 | } else { | ||
537 | result += content->attachments(); | ||
538 | } | ||
539 | } | ||
540 | } | ||
541 | return result; | ||
542 | } | ||
543 | |||
544 | } | ||