Messagelib

protectedheadersjob.cpp
1/*
2 SPDX-FileCopyrightText: 2020 Sandro Knauß <sknauss@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "job/protectedheadersjob.h"
8
9#include "contentjobbase_p.h"
10#include "job/singlepartjob.h"
11
12#include <KMime/Content>
13#include <KMime/Message>
14
15using namespace MessageComposer;
16
17class MessageComposer::ProtectedHeadersJobPrivate : public ContentJobBasePrivate
18{
19public:
20 ProtectedHeadersJobPrivate(ProtectedHeadersJob *qq)
21 : ContentJobBasePrivate(qq)
22 {
23 }
24
25 KMime::Content *content = nullptr;
26 KMime::Message *skeletonMessage = nullptr;
27
28 bool obvoscate = false;
29
30 Q_DECLARE_PUBLIC(ProtectedHeadersJob)
31};
32
33ProtectedHeadersJob::ProtectedHeadersJob(QObject *parent)
34 : ContentJobBase(*new ProtectedHeadersJobPrivate(this), parent)
35{
36}
37
38ProtectedHeadersJob::~ProtectedHeadersJob() = default;
39
40void ProtectedHeadersJob::setContent(KMime::Content *content)
41{
43
44 d->content = content;
45 if (content) {
46 d->content->assemble();
47 }
48}
49
50void ProtectedHeadersJob::setSkeletonMessage(KMime::Message *skeletonMessage)
51{
53
54 d->skeletonMessage = skeletonMessage;
55}
56
57void ProtectedHeadersJob::setObvoscate(bool obvoscate)
58{
60
61 d->obvoscate = obvoscate;
62}
63
64void ProtectedHeadersJob::doStart()
65{
67 Q_ASSERT(d->resultContent == nullptr); // Not processed before.
68 Q_ASSERT(d->skeletonMessage); // We need a skeletonMessage to proceed
69
70 auto subject = d->skeletonMessage->header<KMime::Headers::Subject>();
71 if (d->obvoscate && subject) {
72 // Create protected header lagacy mimepart with replaced headers
73 auto cjob = new SinglepartJob;
74 auto ct = cjob->contentType();
75 ct->setMimeType("text/plain");
76 ct->setCharset(subject->rfc2047Charset());
77 ct->setParameter(QByteArrayLiteral("protected-headers"), QStringLiteral("v1"));
78 cjob->contentDisposition()->setDisposition(KMime::Headers::contentDisposition::CDinline);
79 cjob->setData(subject->type() + QByteArray(": ") + subject->asUnicodeString().toUtf8());
80
81 QObject::connect(cjob, &SinglepartJob::finished, this, [d, cjob]() {
82 auto mixedPart = new KMime::Content();
83 const QByteArray boundary = KMime::multiPartBoundary();
84 mixedPart->contentType()->setMimeType("multipart/mixed");
85 mixedPart->contentType(false)->setBoundary(boundary);
86 mixedPart->appendContent(cjob->content());
87
88 // if setContent hasn't been called, we assume that a subjob was added
89 // and we want to use that
90 if (!d->content || !d->content->hasContent()) {
91 Q_ASSERT(d->subjobContents.size() == 1);
92 d->content = d->subjobContents.constFirst();
93 }
94
95 mixedPart->appendContent(d->content);
96 d->content = mixedPart;
97 });
98 appendSubjob(cjob);
99 }
100
102}
103
104void ProtectedHeadersJob::process()
105{
107
108 // if setContent hasn't been called, we assume that a subjob was added
109 // and we want to use that
110 if (!d->content || !d->content->hasContent()) {
111 Q_ASSERT(d->subjobContents.size() == 1);
112 d->content = d->subjobContents.constFirst();
113 }
114
115 auto subject = d->skeletonMessage->header<KMime::Headers::Subject>();
116 const auto headers = d->skeletonMessage->headers();
117 for (const auto &header : headers) {
118 const QByteArray headerType(header->type());
119 if (headerType.startsWith("X-KMail-")) {
120 continue;
121 }
122 if (headerType == "Bcc") {
123 continue;
124 }
125 if (headerType.startsWith("Content-")) {
126 continue;
127 }
128 // A workaround for #439958
129 // KMime strips sometimes the newlines from long headers, if those
130 // headers are in the signature block, this breaks the signature.
131 // The simplest workaround is not to sign those headers until this
132 // get fixed in KMime.
133 if (header->as7BitString().length() > 70) {
134 continue;
135 }
136 auto copyHeader = KMime::Headers::createHeader(headerType);
137 if (!copyHeader) {
138 copyHeader = new KMime::Headers::Generic(headerType.constData(), headerType.size());
139 }
140 copyHeader->from7BitString(header->as7BitString(false));
141 d->content->appendHeader(copyHeader);
142 }
143
144 if (d->obvoscate && subject) {
145 subject->from7BitString("...");
146 }
147 auto contentType = d->content->header<KMime::Headers::ContentType>();
148 contentType->setParameter(QByteArrayLiteral("protected-headers"), QStringLiteral("v1"));
149
150 d->resultContent = d->content;
151
152 emitResult();
153}
154
155#include "moc_protectedheadersjob.cpp"
void emitResult()
void finished(KJob *job)
void setMimeType(const QByteArray &mimeType)
void setParameter(const QByteArray &key, const QString &value)
The ContentJobBase class.
virtual void doStart()
Reimplement to do additional stuff before processing children, such as adding more subjobs.
bool appendSubjob(ContentJobBase *job)
This is meant to be used instead of KCompositeJob::addSubjob(), making it possible to add subjobs fro...
KMime::Content * content() const
Get the resulting KMime::Content that the ContentJobBase has generated.
Copies headers from skeleton message to content.
The SinglepartJob class.
Simple interface that both EncryptJob and SignEncryptJob implement so the composer can extract some e...
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:07:24 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.