KMime

mdn.cpp
Go to the documentation of this file.
1/* -*- c++ -*-
2 kmime_mdn.cpp
3
4 KMime, the KDE Internet mail/usenet news message library.
5 SPDX-FileCopyrightText: 2002 Marc Mutz <mutz@kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9/**
10 @file
11 This file is part of the API for handling @ref MIME data and
12 provides functions for supporting Message Disposition Notifications (MDNs),
13 also known as email return receipts.
14
15 @brief
16 Provides support for Message Disposition Notifications.
17
18 @authors Marc Mutz <mutz@kde.org>
19*/
20
21#include "mdn.h"
22#include "kmime_version.h"
23#include "util.h"
24#include "codecs_p.h"
25#include "kmime_debug.h"
26
27#include <QByteArray>
28#include <QCoreApplication>
29#include <array>
30
31#ifdef Q_OS_WIN // gethostname
32# include <winsock2.h>
33#else
34# include <unistd.h>
35#endif
36
37namespace KMime
38{
39
40namespace MDN
41{
42
43struct DispositionMetaData {
44 DispositionType dispositionType;
45 const char *string;
46 const char *description;
47};
48
49static constexpr std::array<DispositionMetaData, 6> dispositionTypes = {
50 DispositionMetaData {
51 Displayed,
52 "displayed",
53 QT_TRANSLATE_NOOP("DispositionModifier", "The message sent on ${date} to ${to} with subject "
54 "\"${subject}\" has been displayed. This is no guarantee that "
55 "the message has been read or understood.")
56 },
57 DispositionMetaData{
58 Deleted,
59 "deleted",
60 QT_TRANSLATE_NOOP("DispositionModifier", "The message sent on ${date} to ${to} with subject "
61 "\"${subject}\" has been deleted unseen. This is no guarantee "
62 "that the message will not be \"undeleted\" and nonetheless "
63 "read later on.")
64 },
65 DispositionMetaData{
66 Dispatched,
67 "dispatched",
68 QT_TRANSLATE_NOOP("DispositionModifier", "The message sent on ${date} to ${to} with subject "
69 "\"${subject}\" has been dispatched. This is no guarantee "
70 "that the message will not be read later on.")
71 },
72 DispositionMetaData{
73 Processed,
74 "processed",
75 QT_TRANSLATE_NOOP("DispositionModifier", "The message sent on ${date} to ${to} with subject "
76 "\"${subject}\" has been processed by some automatic means.")
77 },
78 DispositionMetaData{
79 Denied,
80 "denied",
81 QT_TRANSLATE_NOOP("DispositionModifier", "The message sent on ${date} to ${to} with subject "
82 "\"${subject}\" has been acted upon. The sender does not wish "
83 "to disclose more details to you than that.")
84 },
85 DispositionMetaData{
86 Failed,
87 "failed",
88 QT_TRANSLATE_NOOP("DispositionModifier", "Generation of a Message Disposition Notification for the "
89 "message sent on ${date} to ${to} with subject \"${subject}\" "
90 "failed. Reason is given in the Failure: header field below.")
91 }
92};
93
94static const char *stringFor(DispositionType d)
95{
96 for (size_t i = 0 ; i < dispositionTypes.size() ; ++i) {
97 if (dispositionTypes[i].dispositionType == d) {
98 return dispositionTypes[i].string;
99 }
100 }
101 return nullptr;
102}
103
104//
105// disposition-modifier
106//
107struct DispositionModifierMetaData {
108 DispositionModifier dispositionModifier;
109 const char *string;
110};
111
112static constexpr std::array<DispositionModifierMetaData, 5> dispositionModifiers = {
113 DispositionModifierMetaData{ Error, "error" },
114 DispositionModifierMetaData{ Warning, "warning" },
115 DispositionModifierMetaData{ Superseded, "superseded" },
116 DispositionModifierMetaData{ Expired, "expired" },
117 DispositionModifierMetaData{ MailboxTerminated, "mailbox-terminated" }
118};
119
120static const char *stringFor(DispositionModifier m)
121{
122 for (size_t i = 0 ; i < dispositionModifiers.size() ; ++i) {
123 if (dispositionModifiers[i].dispositionModifier == m) {
124 return dispositionModifiers[i].string;
125 }
126 }
127 return nullptr;
128}
129
130//
131// action-mode (part of disposition-mode)
132//
133
134struct ActionModeMetaData {
135 ActionMode actionMode;
136 const char *string;
137};
138
139static constexpr std::array<ActionModeMetaData, 2> actionModes = {
140 ActionModeMetaData{ ManualAction, "manual-action" },
141 ActionModeMetaData{ AutomaticAction, "automatic-action" }
142};
143
144static const char *stringFor(ActionMode a)
145{
146 for (size_t i = 0 ; i < actionModes.size() ; ++i) {
147 if (actionModes[i].actionMode == a) {
148 return actionModes[i].string;
149 }
150 }
151 return nullptr;
152}
153
154//
155// sending-mode (part of disposition-mode)
156//
157
158struct SendingModeMetaData {
159 SendingMode sendingMode;
160 const char *string;
161};
162
163static constexpr std::array<SendingModeMetaData, 2> sendingModes = {
164 SendingModeMetaData{ SentManually, "MDN-sent-manually" },
165 SendingModeMetaData{ SentAutomatically, "MDN-sent-automatically" }
166};
167
168static const char *stringFor(SendingMode s)
169{
170 for (size_t i = 0 ; i < sendingModes.size() ; ++i) {
171 if (sendingModes[i].sendingMode == s) {
172 return sendingModes[i].string;
173 }
174 }
175 return nullptr;
176}
177
178static QByteArray dispositionField(DispositionType d, ActionMode a,
179 SendingMode s,
181
182 // mandatory parts: Disposition: foo/baz; bar
183 QByteArray result = "Disposition: ";
184 result += stringFor(a);
185 result += '/';
186 result += stringFor(s);
187 result += "; ";
188 result += stringFor(d);
189
190 // optional parts: Disposition: foo/baz; bar/mod1,mod2,mod3
191 bool first = true;
193 mt != m.end(); ++mt) {
194 if (first) {
195 result += '/';
196 first = false;
197 } else {
198 result += ',';
199 }
200 result += stringFor(*mt);
201 }
202 return result + '\n';
203}
204
205static QByteArray finalRecipient(const QString &recipient)
206{
207 if (recipient.isEmpty()) {
208 return {};
209 } else {
210 return "Final-Recipient: rfc822; "
211 + encodeRFC2047String(recipient, "utf-8") + '\n';
212 }
213}
214
215static QByteArray orginalRecipient(const QByteArray &recipient)
216{
217 if (recipient.isEmpty()) {
218 return {};
219 } else {
220 return "Original-Recipient: " + recipient + '\n';
221 }
222}
223
224static QByteArray originalMessageID(const QByteArray &msgid)
225{
226 if (msgid.isEmpty()) {
227 return {};
228 } else {
229 return "Original-Message-ID: " + msgid + '\n';
230 }
231}
232
233static QByteArray reportingUAField()
234{
235 char hostName[256];
236 if (gethostname(hostName, 255)) {
237 hostName[0] = '\0'; // gethostname failed: pretend empty string
238 } else {
239 hostName[255] = '\0'; // gethostname may have returned 255 chars (man page)
240 }
241 return QByteArray("Reporting-UA: ") + QByteArray(hostName) +
242 QByteArray("; KMime " KMIME_VERSION_STRING "\n");
243}
244
246 const QString &r, const QByteArray &o, const QByteArray &omid,
248 const QList<DispositionModifier> &m, const QString &special) {
249 // in Perl: chomp(special)
250 QString spec;
251 if (special.endsWith(QLatin1Char('\n'))) {
252 spec = special.left(special.length() - 1);
253 } else {
254 spec = special;
255 }
256
257 // std headers:
258 QByteArray result = reportingUAField();
259 result += orginalRecipient(o);
260 result += finalRecipient(r);
261 result += originalMessageID(omid);
262 result += dispositionField(d, a, s, m);
263
264 // headers that are only present for certain disposition {types,modifiers}:
265 if (d == Failed) {
266 result += "Failure: " + encodeRFC2047String(spec, "utf-8") + '\n';
267 } else if (m.contains(Error)) {
268 result += "Error: " + encodeRFC2047String(spec, "utf-8") + '\n';
269 } else if (m.contains(Warning)) {
270 result += "Warning: " + encodeRFC2047String(spec, "utf-8") + '\n';
271 }
272
273 return result;
274}
275
276QString descriptionFor(DispositionType d, const QList<DispositionModifier> &) {
277 for (size_t i = 0 ; i < dispositionTypes.size() ; ++i) {
278 if (dispositionTypes[i].dispositionType == d) {
279 return QCoreApplication::translate("DispositionModifier", dispositionTypes[i].description);
280 }
281 }
282 qCWarning(KMIME_LOG) << "KMime::MDN::descriptionFor(): No such disposition type:"
283 << static_cast<int>(d);
284 return {};
285}
286
287} // namespace MDN
288} // namespace KMime
QByteArray dispositionNotificationBodyContent(const QString &r, const QByteArray &o, const QByteArray &omid, DispositionType d, ActionMode a, SendingMode s, const QList< DispositionModifier > &m, const QString &special)
Generates the content of the message/disposition-notification body part.
Definition mdn.cpp:245
This file is part of the API for handling MIME data and provides functions for supporting Message Dis...
ActionMode
The following disposition modes are defined:
Definition mdn.h:142
SendingMode
Definition mdn.h:158
DispositionType
The following disposition-types are defined:
Definition mdn.h:89
AKONADI_MIME_EXPORT const char Deleted[]
KCODECS_EXPORT QByteArray encodeRFC2047String(QStringView src, const QByteArray &charset)
bool isEmpty() const const
QString translate(const char *context, const char *sourceText, const char *disambiguation, int n)
iterator begin()
bool contains(const AT &value) const const
iterator end()
bool isEmpty() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:18:08 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.