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

KDE's Doxygen guidelines are available online.