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{
42 Q_D(ProtectedHeadersJob);
43
44 d->content = content;
45 if (content) {
46 d->content->assemble();
47 }
48}
49
50void ProtectedHeadersJob::setSkeletonMessage(KMime::Message *skeletonMessage)
51{
52 Q_D(ProtectedHeadersJob);
53
54 d->skeletonMessage = skeletonMessage;
55}
56
57void ProtectedHeadersJob::setObvoscate(bool obvoscate)
58{
59 Q_D(ProtectedHeadersJob);
60
61 d->obvoscate = obvoscate;
62}
63
64void ProtectedHeadersJob::doStart()
65{
66 Q_D(ProtectedHeadersJob);
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{
106 Q_D(ProtectedHeadersJob);
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)
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.
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-2025 The KDE developers.
Generated on Fri Jan 24 2025 11:47:39 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.