Messagelib

objecttreeparser.cpp
1 /*
2  objecttreeparser.cpp
3 
4  This file is part of KMail, the KDE mail client.
5  SPDX-FileCopyrightText: 2003 Marc Mutz <[email protected]>
6  SPDX-FileCopyrightText: 2002-2004 Klarälvdalens Datakonsult AB, a KDAB Group company, [email protected]
7  SPDX-FileCopyrightText: 2009 Andras Mantia <[email protected]>
8  SPDX-FileCopyrightText: 2015 Sandro Knauß <[email protected]>
9 
10  SPDX-License-Identifier: GPL-2.0-or-later
11 */
12 
13 // MessageViewer includes
14 
15 #include "objecttreeparser.h"
16 
17 #include "bodypartformatterfactory.h"
18 #include "messagepart.h"
19 #include "nodehelper.h"
20 #include "partnodebodypart.h"
21 
22 #include "bodyformatter/utils.h"
23 #include "interfaces/bodypartformatter.h"
24 #include "utils/util.h"
25 
26 #include <KMime/Headers>
27 #include <KMime/Message>
28 
29 // KDE includes
30 
31 // Qt includes
32 #include <QByteArray>
33 #include <QTextCodec>
34 
35 using namespace MimeTreeParser;
36 
37 ObjectTreeParser::ObjectTreeParser(const ObjectTreeParser *topLevelParser)
38  : mSource(topLevelParser->mSource)
39  , mNodeHelper(topLevelParser->mNodeHelper)
40  , mTopLevelContent(topLevelParser->mTopLevelContent)
41  , mAllowAsync(topLevelParser->mAllowAsync)
42 {
43  init();
44 }
45 
46 ObjectTreeParser::ObjectTreeParser(Interface::ObjectTreeSource *source, MimeTreeParser::NodeHelper *nodeHelper)
47  : mSource(source)
48  , mNodeHelper(nodeHelper)
49  , mTopLevelContent(nullptr)
50  , mAllowAsync(false)
51 {
52  init();
53 }
54 
55 void ObjectTreeParser::init()
56 {
57  Q_ASSERT(mSource);
58 
59  if (!mNodeHelper) {
60  mNodeHelper = new NodeHelper();
61  mDeleteNodeHelper = true;
62  } else {
63  mDeleteNodeHelper = false;
64  }
65 }
66 
67 ObjectTreeParser::ObjectTreeParser(const ObjectTreeParser &other)
68  : mSource(other.mSource)
69  , mNodeHelper(other.nodeHelper())
70  , mTopLevelContent(other.mTopLevelContent)
71  , mHasPendingAsyncJobs(other.hasPendingAsyncJobs())
72  , mAllowAsync(other.allowAsync())
73  , mDeleteNodeHelper(false)
74 {
75 }
76 
77 ObjectTreeParser::~ObjectTreeParser()
78 {
79  if (mDeleteNodeHelper) {
80  delete mNodeHelper;
81  mNodeHelper = nullptr;
82  }
83 }
84 
85 void ObjectTreeParser::setAllowAsync(bool allow)
86 {
87  Q_ASSERT(!mHasPendingAsyncJobs);
88  mAllowAsync = allow;
89 }
90 
91 bool ObjectTreeParser::allowAsync() const
92 {
93  return mAllowAsync;
94 }
95 
96 bool ObjectTreeParser::hasPendingAsyncJobs() const
97 {
98  return mHasPendingAsyncJobs;
99 }
100 
101 QString ObjectTreeParser::plainTextContent() const
102 {
103  return mPlainTextContent;
104 }
105 
106 QString ObjectTreeParser::htmlContent() const
107 {
108  return mHtmlContent;
109 }
110 
111 //-----------------------------------------------------------------------------
112 
113 void ObjectTreeParser::parseObjectTree(KMime::Content *node, bool parseOnlySingleNode)
114 {
115  mTopLevelContent = node;
116  mParsedPart = parseObjectTreeInternal(node, parseOnlySingleNode);
117 
118  if (mParsedPart) {
119  mParsedPart->fix();
120  if (auto mp = toplevelTextNode(mParsedPart)) {
121  if (auto _mp = mp.dynamicCast<TextMessagePart>()) {
122  extractNodeInfos(_mp->content(), true);
123  } else if (auto _mp = mp.dynamicCast<AlternativeMessagePart>()) {
124  if (_mp->childParts().contains(Util::MultipartPlain)) {
125  extractNodeInfos(_mp->childParts()[Util::MultipartPlain]->content(), true);
126  }
127  }
128  setPlainTextContent(mp->text());
129  }
130  }
131 }
132 
133 MessagePartPtr ObjectTreeParser::parsedPart() const
134 {
135  return mParsedPart;
136 }
137 
138 MessagePartPtr ObjectTreeParser::processType(KMime::Content *node, ProcessResult &processResult, const QByteArray &mimeType)
139 {
140  const auto formatters = mSource->bodyPartFormatterFactory()->formattersForType(QString::fromUtf8(mimeType));
141  Q_ASSERT(!formatters.empty());
142  for (auto formatter : formatters) {
143  PartNodeBodyPart part(this, &processResult, mTopLevelContent, node, mNodeHelper);
144  mNodeHelper->setNodeDisplayedEmbedded(node, true);
145 
146  const MessagePart::Ptr result = formatter->process(part);
147  if (result.isNull()) {
148  continue;
149  }
150 
151  result->setAttachmentContent(node);
152  return result;
153  }
154 
155  Q_UNREACHABLE();
156  return {};
157 }
158 
159 MessagePart::Ptr ObjectTreeParser::parseObjectTreeInternal(KMime::Content *node, bool onlyOneMimePart)
160 {
161  if (!node) {
162  return {};
163  }
164 
165  // reset pending async jobs state (we'll rediscover pending jobs as we go)
166  mHasPendingAsyncJobs = false;
167 
168  mNodeHelper->clearOverrideHeaders();
169 
170  // reset "processed" flags for...
171  if (onlyOneMimePart) {
172  // ... this node and all descendants
173  mNodeHelper->setNodeUnprocessed(node, false);
174  if (!node->contents().isEmpty()) {
175  mNodeHelper->setNodeUnprocessed(node, true);
176  }
177  } else if (!node->parent()) {
178  // ...this node and all it's siblings and descendants
179  mNodeHelper->setNodeUnprocessed(node, true);
180  }
181 
182  const bool isRoot = node->isTopLevel();
183  auto parsedPart = MessagePart::Ptr(new MessagePartList(this));
184  parsedPart->setIsRoot(isRoot);
185  KMime::Content *parent = node->parent();
186  auto contents = parent ? parent->contents() : KMime::Content::List();
187  if (contents.isEmpty()) {
188  contents.append(node);
189  }
190  int i = contents.indexOf(node);
191  if (i < 0) {
192  return parsedPart;
193  } else {
194  for (; i < contents.size(); ++i) {
195  node = contents.at(i);
196  if (mNodeHelper->nodeProcessed(node)) {
197  continue;
198  }
199 
200  ProcessResult processResult(mNodeHelper);
201 
202  QByteArray mimeType("text/plain");
203  if (auto ct = node->contentType(false)) {
204  mimeType = ct->mimeType();
205  }
206  // unfortunately there's many emails where we can't trust the attachment mimetype
207  // so try to see if we can find something better
208  if (mimeType == "application/octet-stream") {
209  NodeHelper::magicSetType(node);
210  mimeType = node->contentType(false)->mimeType();
211  }
212 
213  const auto mp = processType(node, processResult, mimeType);
214  Q_ASSERT(mp);
215  parsedPart->appendSubPart(mp);
216  mNodeHelper->setNodeProcessed(node, false);
217 
218  // adjust signed/encrypted flags if inline PGP was found
219  processResult.adjustCryptoStatesOfNode(node);
220 
221  if (onlyOneMimePart) {
222  break;
223  }
224  }
225  }
226  return parsedPart;
227 }
228 
229 KMMsgSignatureState ProcessResult::inlineSignatureState() const
230 {
231  return mInlineSignatureState;
232 }
233 
234 void ProcessResult::setInlineSignatureState(KMMsgSignatureState state)
235 {
236  mInlineSignatureState = state;
237 }
238 
239 KMMsgEncryptionState ProcessResult::inlineEncryptionState() const
240 {
241  return mInlineEncryptionState;
242 }
243 
244 void ProcessResult::setInlineEncryptionState(KMMsgEncryptionState state)
245 {
246  mInlineEncryptionState = state;
247 }
248 
249 bool ProcessResult::neverDisplayInline() const
250 {
251  return mNeverDisplayInline;
252 }
253 
254 void ProcessResult::setNeverDisplayInline(bool display)
255 {
256  mNeverDisplayInline = display;
257 }
258 
259 void ProcessResult::adjustCryptoStatesOfNode(const KMime::Content *node) const
260 {
261  if ((inlineSignatureState() != KMMsgNotSigned) || (inlineEncryptionState() != KMMsgNotEncrypted)) {
262  mNodeHelper->setSignatureState(node, inlineSignatureState());
263  mNodeHelper->setEncryptionState(node, inlineEncryptionState());
264  }
265 }
266 
267 void ObjectTreeParser::extractNodeInfos(KMime::Content *curNode, bool isFirstTextPart)
268 {
269  if (isFirstTextPart) {
270  mPlainTextContent += curNode->decodedText();
271  mPlainTextContentCharset += NodeHelper::charset(curNode);
272  }
273 }
274 
275 void ObjectTreeParser::setPlainTextContent(const QString &plainTextContent)
276 {
277  mPlainTextContent = plainTextContent;
278 }
279 
280 const QTextCodec *ObjectTreeParser::codecFor(KMime::Content *node) const
281 {
282  Q_ASSERT(node);
283  if (mSource->overrideCodec()) {
284  return mSource->overrideCodec();
285  }
286  return mNodeHelper->codec(node);
287 }
288 
289 QByteArray ObjectTreeParser::plainTextContentCharset() const
290 {
291  return mPlainTextContentCharset;
292 }
293 
294 QByteArray ObjectTreeParser::htmlContentCharset() const
295 {
296  return mHtmlContentCharset;
297 }
298 
299 MimeTreeParser::NodeHelper *ObjectTreeParser::nodeHelper() const
300 {
301  return mNodeHelper;
302 }
The ProcessResult class.
QString fromUtf8(const char *str, int size)
bool isNull() const const
QByteArray mimeType() const
Content * parent() const
QCA_EXPORT void init()
QVector< KMime::Content * > List
QString decodedText(bool trimText=false, bool removeTrailingNewlines=false)
Parses messages and generates HTML display code out of them.
Interface for object tree sources.
KCALUTILS_EXPORT QString mimeType()
an implementation of the BodyPart interface using KMime::Content's
bool isTopLevel() const
Headers::ContentType * contentType(bool create=true)
QVector< Content * > contents() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Wed Mar 22 2023 04:07:15 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.