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

KDE's Doxygen guidelines are available online.