Messagelib

attachmentstrategy.cpp
1/* -*- c++ -*-
2 attachmentstrategy.cpp
3
4 This file is part of KMail, the KDE mail client.
5 SPDX-FileCopyrightText: 2003 Marc Mutz <mutz@kde.org>
6 SPDX-FileCopyrightText: 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
7 SPDX-FileCopyrightText: 2009 Andras Mantia <andras@kdab.net>
8
9 SPDX-License-Identifier: GPL-2.0-or-later
10*/
11
12#include "attachmentstrategy.h"
13
14#include <MimeTreeParser/NodeHelper>
15#include <MimeTreeParser/Util>
16
17#include <KMime/Content>
18
19#include <QIcon>
20
21#include "messageviewer_debug.h"
22
23using namespace MessageViewer;
24
25static AttachmentStrategy::Display smartDisplay(KMime::Content *node)
26{
27 const auto cd = node->contentDisposition(false);
28 if (cd) {
29 if (cd->disposition() == KMime::Headers::CDinline) {
30 // explicit "inline" disposition:
31 return AttachmentStrategy::Inline;
32 }
33 if (cd->disposition() == KMime::Headers::CDattachment) {
34 // explicit "attachment" disposition:
35 return AttachmentStrategy::AsIcon;
36 }
37 }
38
39 const auto ct = node->contentType(false);
40 if (ct && ct->isText() && ct->name().trimmed().isEmpty() && (!cd || cd->filename().trimmed().isEmpty())) {
41 // text/* w/o filename parameter:
42 return AttachmentStrategy::Inline;
43 }
44 return AttachmentStrategy::AsIcon;
45}
46
47//
48// IconicAttachmentStrategy:
49// show everything but the first text/plain body as icons
50//
51
52class IconicAttachmentStrategy : public AttachmentStrategy
53{
54 friend class AttachmentStrategy;
55
56protected:
57 IconicAttachmentStrategy()
59 {
60 }
61
62 ~IconicAttachmentStrategy() override = default;
63
64public:
65 [[nodiscard]] const char *name() const override
66 {
67 return "iconic";
68 }
69
70 [[nodiscard]] bool inlineNestedMessages() const override
71 {
72 return false;
73 }
74
75 Display defaultDisplay(KMime::Content *node) const override
76 {
77 if (node->contentType()->isText()
78 && (!node->parent() || (node->contentDisposition()->filename().trimmed().isEmpty() && node->contentType(false)->name().trimmed().isEmpty()))) {
79 // text/* w/o filename parameter:
80 return Inline;
81 }
82 return AsIcon;
83 }
84};
85
86//
87// SmartAttachmentStrategy:
88// in addition to Iconic, show all body parts
89// with content-disposition == "inline" and
90// all text parts without a filename or name parameter inline
91//
92
93class SmartAttachmentStrategy : public AttachmentStrategy
94{
95 friend class AttachmentStrategy;
96
97protected:
98 SmartAttachmentStrategy()
100 {
101 }
102
103 ~SmartAttachmentStrategy() override = default;
104
105public:
106 [[nodiscard]] const char *name() const override
107 {
108 return "smart";
109 }
110
111 [[nodiscard]] bool inlineNestedMessages() const override
112 {
113 return true;
114 }
115
116 Display defaultDisplay(KMime::Content *node) const override
117 {
118 return smartDisplay(node);
119 }
120};
121
122//
123// InlinedAttachmentStrategy:
124// show everything possible inline
125//
126
127class InlinedAttachmentStrategy : public AttachmentStrategy
128{
129 friend class AttachmentStrategy;
130
131protected:
132 InlinedAttachmentStrategy()
134 {
135 }
136
137 ~InlinedAttachmentStrategy() override = default;
138
139public:
140 [[nodiscard]] const char *name() const override
141 {
142 return "inlined";
143 }
144
145 [[nodiscard]] bool inlineNestedMessages() const override
146 {
147 return true;
148 }
149
150 Display defaultDisplay(KMime::Content *) const override
151 {
152 return Inline;
153 }
154};
155
156//
157// HiddenAttachmentStrategy
158// show nothing except the first text/plain body part _at all_
159//
160
161class HiddenAttachmentStrategy : public AttachmentStrategy
162{
163 friend class AttachmentStrategy;
164
165protected:
166 HiddenAttachmentStrategy()
168 {
169 }
170
171 ~HiddenAttachmentStrategy() override = default;
172
173public:
174 [[nodiscard]] const char *name() const override
175 {
176 return "hidden";
177 }
178
179 [[nodiscard]] bool inlineNestedMessages() const override
180 {
181 return false;
182 }
183
184 Display defaultDisplay(KMime::Content *node) const override
185 {
186 if (node->contentType()->isText() && node->contentDisposition()->filename().trimmed().isEmpty()
187 && node->contentType(false)->name().trimmed().isEmpty()) {
188 // text/* w/o filename parameter:
189 return Inline;
190 }
191 if (!node->parent()) {
192 return Inline;
193 }
194
195 if (node->parent() && node->parent()->contentType()->isMultipart() && node->parent()->contentType(false)->subType() == "related") {
196 return Inline;
197 }
198
199 return None;
200 }
201};
202
203class HeaderOnlyAttachmentStrategy : public AttachmentStrategy
204{
205 friend class AttachmentStrategy;
206
207protected:
208 HeaderOnlyAttachmentStrategy()
210 {
211 }
212
213 ~HeaderOnlyAttachmentStrategy() override = default;
214
215public:
216 [[nodiscard]] const char *name() const override
217 {
218 return "headerOnly";
219 }
220
221 [[nodiscard]] bool inlineNestedMessages() const override
222 {
223 return true;
224 }
225
226 Display defaultDisplay(KMime::Content *node) const override
227 {
229 return smartDisplay(node);
230 }
231
232 if (!MimeTreeParser::Util::labelForContent(node).isEmpty() && QIcon::hasThemeIcon(MimeTreeParser::Util::iconNameForContent(node))
233 && !MimeTreeParser::Util::isTypeBlacklisted(node)) {
234 return None;
235 }
236 return smartDisplay(node);
237 }
238
239 [[nodiscard]] bool requiresAttachmentListInHeader() const override
240 {
241 return true;
242 }
243};
244
245//
246// AttachmentStrategy abstract base:
247//
248
249AttachmentStrategy::AttachmentStrategy() = default;
250
251AttachmentStrategy::~AttachmentStrategy() = default;
252
253const AttachmentStrategy *AttachmentStrategy::create(Type type)
254{
255 switch (type) {
256 case Iconic:
257 return iconic();
258 case Smart:
259 return smart();
260 case Inlined:
261 return inlined();
262 case Hidden:
263 return hidden();
264 case HeaderOnly:
265 return headerOnly();
266 }
267 qCCritical(MESSAGEVIEWER_LOG) << "Unknown attachment strategy ( type ==" << static_cast<int>(type) << ") requested!";
268 return nullptr; // make compiler happy
269}
270
271const AttachmentStrategy *AttachmentStrategy::create(const QString &type)
272{
273 const QString lowerType = type.toLower();
274 if (lowerType == QLatin1StringView("iconic")) {
275 return iconic();
276 }
277 // if ( lowerType == "smart" ) return smart(); // not needed, see below
278 if (lowerType == QLatin1StringView("inlined")) {
279 return inlined();
280 }
281 if (lowerType == QLatin1StringView("hidden")) {
282 return hidden();
283 }
284 if (lowerType == QLatin1StringView("headeronly")) {
285 return headerOnly();
286 }
287 // don't kFatal here, b/c the strings are user-provided
288 // (KConfig), so fail gracefully to the default:
289 return smart();
290}
291
292static const AttachmentStrategy *iconicStrategy = nullptr;
293static const AttachmentStrategy *smartStrategy = nullptr;
294static const AttachmentStrategy *inlinedStrategy = nullptr;
295static const AttachmentStrategy *hiddenStrategy = nullptr;
296static const AttachmentStrategy *headerOnlyStrategy = nullptr;
297
298const AttachmentStrategy *AttachmentStrategy::iconic()
299{
300 if (!iconicStrategy) {
301 iconicStrategy = new IconicAttachmentStrategy();
302 }
303 return iconicStrategy;
304}
305
306const AttachmentStrategy *AttachmentStrategy::smart()
307{
308 if (!smartStrategy) {
309 smartStrategy = new SmartAttachmentStrategy();
310 }
311 return smartStrategy;
312}
313
314const AttachmentStrategy *AttachmentStrategy::inlined()
315{
316 if (!inlinedStrategy) {
317 inlinedStrategy = new InlinedAttachmentStrategy();
318 }
319 return inlinedStrategy;
320}
321
322const AttachmentStrategy *AttachmentStrategy::hidden()
323{
324 if (!hiddenStrategy) {
325 hiddenStrategy = new HiddenAttachmentStrategy();
326 }
327 return hiddenStrategy;
328}
329
330const AttachmentStrategy *AttachmentStrategy::headerOnly()
331{
332 if (!headerOnlyStrategy) {
333 headerOnlyStrategy = new HeaderOnlyAttachmentStrategy();
334 }
335 return headerOnlyStrategy;
336}
337
338bool AttachmentStrategy::requiresAttachmentListInHeader() const
339{
340 return false;
341}
Headers::ContentType * contentType(bool create=true)
Content * parent() const
Headers::ContentDisposition * contentDisposition(bool create=true)
QByteArray subType() const
The AttachmentStrategy class.
static bool isInEncapsulatedMessage(KMime::Content *node)
bool hasThemeIcon(const QString &name)
bool isEmpty() const const
QString trimmed() const const
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.