Messagelib

mailman.cpp
1 /*
2  SPDX-FileCopyrightText: 2016 Sandro Knauß <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "mailman.h"
8 
9 #include "utils.h"
10 
11 #include "messagepart.h"
12 #include "objecttreeparser.h"
13 
14 #include <KMime/Content>
15 
16 #include "mimetreeparser_debug.h"
17 
18 using namespace MimeTreeParser;
19 
20 const MailmanBodyPartFormatter *MailmanBodyPartFormatter::self;
21 
22 const Interface::BodyPartFormatter *MailmanBodyPartFormatter::create()
23 {
24  if (!self) {
25  self = new MailmanBodyPartFormatter();
26  }
27  return self;
28 }
29 
30 bool MailmanBodyPartFormatter::isMailmanMessage(KMime::Content *curNode) const
31 {
32  if (!curNode || curNode->head().isEmpty()) {
33  return false;
34  }
35  if (curNode->hasHeader("X-Mailman-Version")) {
36  return true;
37  }
38  if (KMime::Headers::Base *header = curNode->headerByType("X-Mailer")) {
39  if (header->asUnicodeString().contains(QLatin1String("MAILMAN"), Qt::CaseInsensitive)) {
40  return true;
41  }
42  }
43  return false;
44 }
45 
46 MessagePart::Ptr MailmanBodyPartFormatter::process(Interface::BodyPart &part) const
47 {
48  KMime::Content *curNode = part.content();
49 
50  if (!isMailmanMessage(curNode)) {
51  return {};
52  }
53 
54  // Latin1 or utf8 ?
55  const QString str = QString::fromLatin1(curNode->decodedContent());
56 
57  // ###
58  const QLatin1String delim1("--__--__--\n\nMessage:");
59  const QLatin1String delim2("--__--__--\r\n\r\nMessage:");
60  const QLatin1String delimZ2("--__--__--\n\n_____________");
61  const QLatin1String delimZ1("--__--__--\r\n\r\n_____________");
62  QString partStr;
63  QString digestHeaderStr;
64  int thisDelim = str.indexOf(delim1, Qt::CaseInsensitive);
65  if (thisDelim == -1) {
66  thisDelim = str.indexOf(delim2, Qt::CaseInsensitive);
67  }
68  if (thisDelim == -1) {
69  return {};
70  }
71 
72  int nextDelim = str.indexOf(delim1, thisDelim + 1, Qt::CaseInsensitive);
73  if (-1 == nextDelim) {
74  nextDelim = str.indexOf(delim2, thisDelim + 1, Qt::CaseInsensitive);
75  }
76  if (-1 == nextDelim) {
77  nextDelim = str.indexOf(delimZ1, thisDelim + 1, Qt::CaseInsensitive);
78  }
79  if (-1 == nextDelim) {
80  nextDelim = str.indexOf(delimZ2, thisDelim + 1, Qt::CaseInsensitive);
81  }
82  if (nextDelim < 0) {
83  return {};
84  }
85 
86  // if ( curNode->mRoot )
87  // curNode = curNode->mRoot;
88 
89  // at least one message found: build a mime tree
90  digestHeaderStr = QStringLiteral("Content-Type: text/plain\nContent-Description: digest header\n\n");
91  digestHeaderStr += QStringView(str).mid(0, thisDelim);
92 
94  mpl->appendSubPart(createAndParseTempNode(part, part.topLevelContent(), digestHeaderStr.toLatin1().constData(), "Digest Header"));
95  // mReader->queueHtml("<br><hr><br>");
96  // temporarily change current node's Content-Type
97  // to get our embedded RfC822 messages properly inserted
98  curNode->contentType()->setMimeType("multipart/digest");
99  while (-1 < nextDelim) {
100  int thisEoL = str.indexOf(QLatin1String("\nMessage:"), thisDelim, Qt::CaseInsensitive);
101  if (-1 < thisEoL) {
102  thisDelim = thisEoL + 1;
103  } else {
104  thisEoL = str.indexOf(QLatin1String("\n_____________"), thisDelim, Qt::CaseInsensitive);
105  if (-1 < thisEoL) {
106  thisDelim = thisEoL + 1;
107  }
108  }
109  thisEoL = str.indexOf(QLatin1Char('\n'), thisDelim);
110  if (-1 < thisEoL) {
111  thisDelim = thisEoL + 1;
112  } else {
113  thisDelim = thisDelim + 1;
114  }
115  // while( thisDelim < cstr.size() && '\n' == cstr[thisDelim] )
116  // ++thisDelim;
117 
118  partStr = QStringLiteral("Content-Type: message/rfc822\nContent-Description: embedded message\n\n");
119  partStr += QStringView(str).mid(thisDelim, nextDelim - thisDelim);
120  QString subject = QStringLiteral("embedded message");
121  QString subSearch = QStringLiteral("\nSubject:");
122  int subPos = partStr.indexOf(subSearch, 0, Qt::CaseInsensitive);
123  if (-1 < subPos) {
124  subject = partStr.mid(subPos + subSearch.length());
125  thisEoL = subject.indexOf(QLatin1Char('\n'));
126  if (-1 < thisEoL) {
127  subject.truncate(thisEoL);
128  }
129  }
130  qCDebug(MIMETREEPARSER_LOG) << " embedded message found: \"" << subject;
131  mpl->appendSubPart(createAndParseTempNode(part, part.topLevelContent(), partStr.toLatin1().constData(), subject.toLatin1().constData()));
132  // mReader->queueHtml("<br><hr><br>");
133  thisDelim = nextDelim + 1;
134  nextDelim = str.indexOf(delim1, thisDelim, Qt::CaseInsensitive);
135  if (-1 == nextDelim) {
136  nextDelim = str.indexOf(delim2, thisDelim, Qt::CaseInsensitive);
137  }
138  if (-1 == nextDelim) {
139  nextDelim = str.indexOf(delimZ1, thisDelim, Qt::CaseInsensitive);
140  }
141  if (-1 == nextDelim) {
142  nextDelim = str.indexOf(delimZ2, thisDelim, Qt::CaseInsensitive);
143  }
144  }
145  // reset current node's Content-Type
146  curNode->contentType()->setMimeType("text/plain");
147  int thisEoL = str.indexOf(QLatin1String("_____________"), thisDelim);
148  if (-1 < thisEoL) {
149  thisDelim = thisEoL;
150  thisEoL = str.indexOf(QLatin1Char('\n'), thisDelim);
151  if (-1 < thisEoL) {
152  thisDelim = thisEoL + 1;
153  }
154  } else {
155  thisDelim = thisDelim + 1;
156  }
157  partStr = QStringLiteral("Content-Type: text/plain\nContent-Description: digest footer\n\n");
158  partStr += QStringView(str).mid(thisDelim);
159  mpl->appendSubPart(createAndParseTempNode(part, part.topLevelContent(), partStr.toLatin1().constData(), "Digest Footer"));
160  return mpl;
161 }
void truncate(int position)
virtual MimeTreeParser::ObjectTreeParser * objectTreeParser() const =0
For making it easier to refactor, add objectTreeParser.
CaseInsensitive
virtual KMime::Content * topLevelContent() const =0
Returns the top-level content.
QStringView mid(qsizetype start) const const
QByteArray toLatin1() const const
void setMimeType(const QByteArray &mimeType)
int length() const const
virtual KMime::Content * content() const =0
Returns the KMime::Content node represented here.
interface of message body parts.
Definition: bodypart.h:44
QByteArray head() const
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
Headers::Base * headerByType(const char *type) const
QByteArray decodedContent()
bool isEmpty() const const
const char * constData() const const
QString fromLatin1(const char *str, int size)
bool hasHeader(const char *type) const
Headers::ContentType * contentType(bool create=true)
QString mid(int position, int n) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Mar 26 2023 04:08:11 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.