Messagelib

protectedheadersjob.cpp
1 /*
2  SPDX-FileCopyrightText: 2020 Sandro Knauß <[email protected]>
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/KMimeMessage>
14 
15 using namespace MessageComposer;
16 
17 class MessageComposer::ProtectedHeadersJobPrivate : public ContentJobBasePrivate
18 {
19 public:
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 
33 ProtectedHeadersJob::ProtectedHeadersJob(QObject *parent)
34  : ContentJobBase(*new ProtectedHeadersJobPrivate(this), parent)
35 {
36 }
37 
38 ProtectedHeadersJob::~ProtectedHeadersJob() = default;
39 
40 void ProtectedHeadersJob::setContent(KMime::Content *content)
41 {
43 
44  d->content = content;
45  if (content) {
46  d->content->assemble();
47  }
48 }
49 
50 void ProtectedHeadersJob::setSkeletonMessage(KMime::Message *skeletonMessage)
51 {
53 
54  d->skeletonMessage = skeletonMessage;
55 }
56 
57 void ProtectedHeadersJob::setObvoscate(bool obvoscate)
58 {
60 
61  d->obvoscate = obvoscate;
62 }
63 
64 void 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(QStringLiteral("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->addContent(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->addContent(d->content);
96  d->content = mixedPart;
97  });
98  appendSubjob(cjob);
99  }
100 
101  ContentJobBase::doStart();
102 }
103 
104 void 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->clear();
146  subject->from7BitString("...");
147  }
148  auto contentType = d->content->header<KMime::Headers::ContentType>();
149  contentType->setParameter(QStringLiteral("protected-headers"), QStringLiteral("v1"));
150 
151  d->resultContent = d->content;
152 
153  emitResult();
154 }
Content * content(const ContentIndex &index) const
Simple interface that both EncryptJob and SignEncryptJob implement so the composer can extract some e...
void setMimeType(const QByteArray &mimeType)
The SinglepartJob class.
Definition: singlepartjob.h:31
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void setParameter(const QString &key, const QString &value)
The ContentJobBase class.
Copies headers from skeleton message to content.
Q_D(Todo)
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.