Messagelib

mailman.cpp
1/*
2 SPDX-FileCopyrightText: 2016 Sandro Knauß <sknauss@kde.org>
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
18using namespace MimeTreeParser;
19
20const MailmanBodyPartFormatter *MailmanBodyPartFormatter::self;
21
22const Interface::BodyPartFormatter *MailmanBodyPartFormatter::create()
23{
24 if (!self) {
25 self = new MailmanBodyPartFormatter();
26 }
27 return self;
28}
29
30bool 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(QLatin1StringView("MAILMAN"), Qt::CaseInsensitive)) {
40 return true;
41 }
42 }
43 return false;
44}
45
46MessagePart::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 QLatin1StringView delim1("--__--__--\n\nMessage:");
59 const QLatin1StringView delim2("--__--__--\r\n\r\nMessage:");
60 const QLatin1StringView delimZ2("--__--__--\n\n_____________");
61 const QLatin1StringView 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(QLatin1StringView("\nMessage:"), thisDelim, Qt::CaseInsensitive);
101 if (-1 < thisEoL) {
102 thisDelim = thisEoL + 1;
103 } else {
104 thisEoL = str.indexOf(QLatin1StringView("\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(QLatin1StringView("_____________"), 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}
Headers::ContentType * contentType(bool create=true)
QByteArray head() const
QByteArray decodedContent()
Headers::Base * headerByType(const char *type) const
bool hasHeader(const char *type) const
void setMimeType(const QByteArray &mimeType)
interface of message body parts.
Definition bodypart.h:45
virtual KMime::Content * topLevelContent() const =0
Returns the top-level content.
virtual MimeTreeParser::ObjectTreeParser * objectTreeParser() const =0
For making it easier to refactor, add objectTreeParser.
virtual KMime::Content * content() const =0
Returns the KMime::Content node represented here.
const char * constData() const const
bool isEmpty() const const
QString fromLatin1(QByteArrayView str)
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
qsizetype length() const const
QString mid(qsizetype position, qsizetype n) const const
QByteArray toLatin1() const const
void truncate(qsizetype position)
QStringView mid(qsizetype start, qsizetype length) const const
CaseInsensitive
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:12:43 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.