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 #include "utils/util_p.h"
12 
13 #include "messagecomposer_debug.h"
14 
15 #include <KMime/Content>
16 #include <KMime/KMimeMessage>
17 
18 using namespace MessageComposer;
19 
20 class MessageComposer::ProtectedHeadersJobPrivate : public ContentJobBasePrivate
21 {
22 public:
23  ProtectedHeadersJobPrivate(ProtectedHeadersJob *qq)
24  : ContentJobBasePrivate(qq)
25  {
26  }
27 
28  KMime::Content *content = nullptr;
29  KMime::Message *skeletonMessage = nullptr;
30 
31  bool obvoscate = false;
32 
33  Q_DECLARE_PUBLIC(ProtectedHeadersJob)
34 };
35 
36 ProtectedHeadersJob::ProtectedHeadersJob(QObject *parent)
37  : ContentJobBase(*new ProtectedHeadersJobPrivate(this), parent)
38 {
39 }
40 
41 ProtectedHeadersJob::~ProtectedHeadersJob() = default;
42 
43 void ProtectedHeadersJob::setContent(KMime::Content *content)
44 {
46 
47  d->content = content;
48  if (content) {
49  d->content->assemble();
50  }
51 }
52 
53 void ProtectedHeadersJob::setSkeletonMessage(KMime::Message *skeletonMessage)
54 {
56 
57  d->skeletonMessage = skeletonMessage;
58 }
59 
60 void ProtectedHeadersJob::setObvoscate(bool obvoscate)
61 {
63 
64  d->obvoscate = obvoscate;
65 }
66 
67 void ProtectedHeadersJob::doStart()
68 {
70  Q_ASSERT(d->resultContent == nullptr); // Not processed before.
71  Q_ASSERT(d->skeletonMessage); // We need a skeletonMessage to proceed
72 
73  auto subject = d->skeletonMessage->header<KMime::Headers::Subject>();
74  if (d->obvoscate && subject) {
75  // Create protected header lagacy mimepart with replaced headers
76  auto cjob = new SinglepartJob;
77  auto ct = cjob->contentType();
78  ct->setMimeType("text/plain");
79  ct->setCharset(subject->rfc2047Charset());
80  ct->setParameter(QStringLiteral("protected-headers"), QStringLiteral("v1"));
81  cjob->contentDisposition()->setDisposition(KMime::Headers::contentDisposition::CDinline);
82  cjob->setData(subject->type() + QByteArray(": ") + subject->asUnicodeString().toUtf8());
83 
84  QObject::connect(cjob, &SinglepartJob::finished, this, [d, cjob]() {
85  auto mixedPart = new KMime::Content();
86  const QByteArray boundary = KMime::multiPartBoundary();
87  mixedPart->contentType()->setMimeType("multipart/mixed");
88  mixedPart->contentType(false)->setBoundary(boundary);
89  mixedPart->addContent(cjob->content());
90 
91  // if setContent hasn't been called, we assume that a subjob was added
92  // and we want to use that
93  if (!d->content || !d->content->hasContent()) {
94  Q_ASSERT(d->subjobContents.size() == 1);
95  d->content = d->subjobContents.constFirst();
96  }
97 
98  mixedPart->addContent(d->content);
99  d->content = mixedPart;
100  });
101  appendSubjob(cjob);
102  }
103 
104  ContentJobBase::doStart();
105 }
106 
107 void ProtectedHeadersJob::process()
108 {
110 
111  // if setContent hasn't been called, we assume that a subjob was added
112  // and we want to use that
113  if (!d->content || !d->content->hasContent()) {
114  Q_ASSERT(d->subjobContents.size() == 1);
115  d->content = d->subjobContents.constFirst();
116  }
117 
118  auto subject = d->skeletonMessage->header<KMime::Headers::Subject>();
119  const auto headers = d->skeletonMessage->headers();
120  for (const auto &header : headers) {
121  const QByteArray headerType(header->type());
122  if (headerType.startsWith("X-KMail-")) {
123  continue;
124  }
125  if (headerType == "Bcc") {
126  continue;
127  }
128  if (headerType.startsWith("Content-")) {
129  continue;
130  }
131  // A workaround for #439958
132  // KMime strips sometimes the newlines from long headers, if those
133  // headers are in the signature block, this breaks the signature.
134  // The simplest workaround is not to sign those headers until this
135  // get fixed in KMime.
136  if (header->as7BitString().length() > 70) {
137  continue;
138  }
139  auto copyHeader = KMime::Headers::createHeader(headerType);
140  if (!copyHeader) {
141  copyHeader = new KMime::Headers::Generic(headerType.constData(), headerType.size());
142  }
143  copyHeader->from7BitString(header->as7BitString(false));
144  d->content->appendHeader(copyHeader);
145  }
146 
147  if (d->obvoscate && subject) {
148  subject->clear();
149  subject->from7BitString("...");
150  }
151  auto contentType = d->content->header<KMime::Headers::ContentType>();
152  contentType->setParameter(QStringLiteral("protected-headers"), QStringLiteral("v1"));
153 
154  d->resultContent = d->content;
155 
156  emitResult();
157 }
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-2022 The KDE developers.
Generated on Thu May 19 2022 03:53:26 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.