attachmentstrategy.cpp 8 KB
Newer Older
1
2
3
4
/*  -*- c++ -*-
    attachmentstrategy.cpp

    This file is part of KMail, the KDE mail client.
5
6
7
8
    SPDX-FileCopyrightText: 2003 Marc Mutz <mutz@kde.org>
    SPDX-FileCopyrightText: 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
    SPDX-FileCopyrightText: 2009 Andras Mantia <andras@kdab.net>

9
    SPDX-License-Identifier: GPL-2.0-or-later
10
11
12
13
*/

#include "attachmentstrategy.h"

14
15
#include <MimeTreeParser/NodeHelper>
#include <MimeTreeParser/Util>
16

17
#include <KMime/Content>
18

19
20
#include <QIcon>

21
#include "messageviewer_debug.h"
22

23
using namespace MessageViewer;
24
25
26
27

static AttachmentStrategy::Display smartDisplay(KMime::Content *node)
{
    const auto cd = node->contentDisposition(false);
Laurent Montel's avatar
Laurent Montel committed
28
29
30
31
32
33
34
35
36
    if (cd) {
        if (cd->disposition() == KMime::Headers::CDinline) {
            // explict "inline" disposition:
            return AttachmentStrategy::Inline;
        }
        if (cd->disposition() == KMime::Headers::CDattachment) {
            // explicit "attachment" disposition:
            return AttachmentStrategy::AsIcon;
        }
37
38
39
    }

    const auto ct = node->contentType(false);
Laurent Montel's avatar
Laurent Montel committed
40
    if (ct && ct->isText() && ct->name().trimmed().isEmpty() && (!cd || cd->filename().trimmed().isEmpty())) {
41
42
43
44
45
46
47
48
49
50
51
52
53
54
        // text/* w/o filename parameter:
        return AttachmentStrategy::Inline;
    }
    return AttachmentStrategy::AsIcon;
}

//
// IconicAttachmentStrategy:
//   show everything but the first text/plain body as icons
//

class IconicAttachmentStrategy : public AttachmentStrategy
{
    friend class AttachmentStrategy;
Laurent Montel's avatar
Laurent Montel committed
55

56
protected:
Laurent Montel's avatar
Laurent Montel committed
57
58
    IconicAttachmentStrategy()
        : AttachmentStrategy()
Laurent Montel's avatar
Laurent Montel committed
59
60
61
    {
    }

62
    ~IconicAttachmentStrategy() override
Laurent Montel's avatar
Laurent Montel committed
63
64
    {
    }
65
66

public:
67
    const char *name() const override
68
69
70
71
    {
        return "iconic";
    }

72
    bool inlineNestedMessages() const override
73
74
75
    {
        return false;
    }
Laurent Montel's avatar
Laurent Montel committed
76

77
    Display defaultDisplay(KMime::Content *node) const override
78
    {
Laurent Montel's avatar
Laurent Montel committed
79
        if (node->contentType()->isText()
Laurent Montel's avatar
Laurent Montel committed
80
            && (!node->parent() || (node->contentDisposition()->filename().trimmed().isEmpty() && node->contentType(false)->name().trimmed().isEmpty()))) {
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
            // text/* w/o filename parameter:
            return Inline;
        }
        return AsIcon;
    }
};

//
// SmartAttachmentStrategy:
//   in addition to Iconic, show all body parts
//   with content-disposition == "inline" and
//   all text parts without a filename or name parameter inline
//

class SmartAttachmentStrategy : public AttachmentStrategy
{
    friend class AttachmentStrategy;
Laurent Montel's avatar
Laurent Montel committed
98

99
protected:
Laurent Montel's avatar
Laurent Montel committed
100
101
    SmartAttachmentStrategy()
        : AttachmentStrategy()
Laurent Montel's avatar
Laurent Montel committed
102
103
104
    {
    }

105
    ~SmartAttachmentStrategy() override
Laurent Montel's avatar
Laurent Montel committed
106
107
    {
    }
108
109

public:
110
    const char *name() const override
111
112
113
114
    {
        return "smart";
    }

115
    bool inlineNestedMessages() const override
116
117
118
    {
        return true;
    }
Laurent Montel's avatar
Laurent Montel committed
119

120
    Display defaultDisplay(KMime::Content *node) const override
121
122
123
124
125
126
127
128
129
130
131
132
133
    {
        return smartDisplay(node);
    }
};

//
// InlinedAttachmentStrategy:
//   show everything possible inline
//

class InlinedAttachmentStrategy : public AttachmentStrategy
{
    friend class AttachmentStrategy;
Laurent Montel's avatar
Laurent Montel committed
134

135
protected:
Laurent Montel's avatar
Laurent Montel committed
136
137
    InlinedAttachmentStrategy()
        : AttachmentStrategy()
Laurent Montel's avatar
Laurent Montel committed
138
139
140
    {
    }

141
    ~InlinedAttachmentStrategy() override
Laurent Montel's avatar
Laurent Montel committed
142
143
    {
    }
144
145

public:
146
    const char *name() const override
147
148
149
150
    {
        return "inlined";
    }

151
    bool inlineNestedMessages() const override
152
153
154
    {
        return true;
    }
Laurent Montel's avatar
Laurent Montel committed
155

156
    Display defaultDisplay(KMime::Content *) const override
157
158
159
160
161
162
163
164
165
166
167
168
169
    {
        return Inline;
    }
};

//
// HiddenAttachmentStrategy
//   show nothing except the first text/plain body part _at all_
//

class HiddenAttachmentStrategy : public AttachmentStrategy
{
    friend class AttachmentStrategy;
Laurent Montel's avatar
Laurent Montel committed
170

171
protected:
Laurent Montel's avatar
Laurent Montel committed
172
173
    HiddenAttachmentStrategy()
        : AttachmentStrategy()
Laurent Montel's avatar
Laurent Montel committed
174
175
176
    {
    }

177
    ~HiddenAttachmentStrategy() override
Laurent Montel's avatar
Laurent Montel committed
178
179
    {
    }
180
181

public:
182
    const char *name() const override
183
184
185
186
    {
        return "hidden";
    }

187
    bool inlineNestedMessages() const override
188
189
190
    {
        return false;
    }
Laurent Montel's avatar
Laurent Montel committed
191

192
    Display defaultDisplay(KMime::Content *node) const override
193
    {
Laurent Montel's avatar
Laurent Montel committed
194
        if (node->contentType()->isText() && node->contentDisposition()->filename().trimmed().isEmpty()
Laurent Montel's avatar
Laurent Montel committed
195
            && node->contentType(false)->name().trimmed().isEmpty()) {
196
197
198
199
200
201
202
            // text/* w/o filename parameter:
            return Inline;
        }
        if (!node->parent()) {
            return Inline;
        }

Laurent Montel's avatar
Laurent Montel committed
203
        if (node->parent() && node->parent()->contentType()->isMultipart() && node->parent()->contentType(false)->subType() == "related") {
204
205
206
207
208
209
210
211
212
213
            return Inline;
        }

        return None;
    }
};

class HeaderOnlyAttachmentStrategy : public AttachmentStrategy
{
    friend class AttachmentStrategy;
Laurent Montel's avatar
Laurent Montel committed
214

215
protected:
Laurent Montel's avatar
Laurent Montel committed
216
217
    HeaderOnlyAttachmentStrategy()
        : AttachmentStrategy()
Laurent Montel's avatar
Laurent Montel committed
218
219
220
    {
    }

221
    ~HeaderOnlyAttachmentStrategy() override
Laurent Montel's avatar
Laurent Montel committed
222
223
    {
    }
224
225

public:
226
    const char *name() const override
227
228
229
230
    {
        return "headerOnly";
    }

231
    bool inlineNestedMessages() const override
232
233
234
235
    {
        return true;
    }

236
    Display defaultDisplay(KMime::Content *node) const override
237
    {
238
        if (MimeTreeParser::NodeHelper::isInEncapsulatedMessage(node)) {
239
240
241
            return smartDisplay(node);
        }

Laurent Montel's avatar
Laurent Montel committed
242
243
        if (!MimeTreeParser::Util::labelForContent(node).isEmpty() && QIcon::hasThemeIcon(MimeTreeParser::Util::iconNameForContent(node))
            && !MimeTreeParser::Util::isTypeBlacklisted(node)) {
244
245
            return None;
        }
246
        return smartDisplay(node);
247
248
    }

249
    bool requiresAttachmentListInHeader() const override
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
    {
        return true;
    }
};

//
// AttachmentStrategy abstract base:
//

AttachmentStrategy::AttachmentStrategy()
{
}

AttachmentStrategy::~AttachmentStrategy()
{
}

const AttachmentStrategy *AttachmentStrategy::create(Type type)
{
    switch (type) {
Laurent Montel's avatar
Laurent Montel committed
270
271
272
273
274
275
276
277
278
279
    case Iconic:
        return iconic();
    case Smart:
        return smart();
    case Inlined:
        return inlined();
    case Hidden:
        return hidden();
    case HeaderOnly:
        return headerOnly();
280
    }
Laurent Montel's avatar
Laurent Montel committed
281
    qCCritical(MESSAGEVIEWER_LOG) << "Unknown attachment startegy ( type ==" << static_cast<int>(type) << ") requested!";
Laurent Montel's avatar
Laurent Montel committed
282
    return nullptr; // make compiler happy
283
284
285
286
287
288
289
290
}

const AttachmentStrategy *AttachmentStrategy::create(const QString &type)
{
    const QString lowerType = type.toLower();
    if (lowerType == QLatin1String("iconic")) {
        return iconic();
    }
Laurent Montel's avatar
Laurent Montel committed
291
    // if ( lowerType == "smart" )    return smart(); // not needed, see below
292
293
294
295
296
297
298
299
300
301
302
303
304
305
    if (lowerType == QLatin1String("inlined")) {
        return inlined();
    }
    if (lowerType == QLatin1String("hidden")) {
        return hidden();
    }
    if (lowerType == QLatin1String("headeronly")) {
        return headerOnly();
    }
    // don't kFatal here, b/c the strings are user-provided
    // (KConfig), so fail gracefully to the default:
    return smart();
}

Laurent Montel's avatar
Laurent Montel committed
306
307
308
309
310
static const AttachmentStrategy *iconicStrategy = nullptr;
static const AttachmentStrategy *smartStrategy = nullptr;
static const AttachmentStrategy *inlinedStrategy = nullptr;
static const AttachmentStrategy *hiddenStrategy = nullptr;
static const AttachmentStrategy *headerOnlyStrategy = nullptr;
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354

const AttachmentStrategy *AttachmentStrategy::iconic()
{
    if (!iconicStrategy) {
        iconicStrategy = new IconicAttachmentStrategy();
    }
    return iconicStrategy;
}

const AttachmentStrategy *AttachmentStrategy::smart()
{
    if (!smartStrategy) {
        smartStrategy = new SmartAttachmentStrategy();
    }
    return smartStrategy;
}

const AttachmentStrategy *AttachmentStrategy::inlined()
{
    if (!inlinedStrategy) {
        inlinedStrategy = new InlinedAttachmentStrategy();
    }
    return inlinedStrategy;
}

const AttachmentStrategy *AttachmentStrategy::hidden()
{
    if (!hiddenStrategy) {
        hiddenStrategy = new HiddenAttachmentStrategy();
    }
    return hiddenStrategy;
}

const AttachmentStrategy *AttachmentStrategy::headerOnly()
{
    if (!headerOnlyStrategy) {
        headerOnlyStrategy = new HeaderOnlyAttachmentStrategy();
    }
    return headerOnlyStrategy;
}

bool AttachmentStrategy::requiresAttachmentListInHeader() const
{
    return false;
Laurent Montel's avatar
Laurent Montel committed
355
}