KMime

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 "kmime_mdn.h"
22#include "kmime_version.h"
23#include "kmime_util.h"
24#include "kmime_codecs_p.h"
25#include "kmime_debug.h"
26
27#include <KLocalizedString>
28
29#include <QByteArray>
30
31#ifdef Q_OS_WIN // gethostname
32# include <winsock2.h>
33#else
34# include <unistd.h>
35#endif
36#include <KLazyLocalizedString>
37
38namespace KMime
39{
40
41namespace MDN
42{
43
44static const struct {
45 DispositionType dispositionType;
46 const char *string;
47 const KLazyLocalizedString description;
48} dispositionTypes[] = {{Displayed,
49 "displayed",
50 kli18n("The message sent on ${date} to ${to} with subject "
51 "\"${subject}\" has been displayed. This is no guarantee that "
52 "the message has been read or understood.")},
53 {Deleted,
54 "deleted",
55 kli18n("The message sent on ${date} to ${to} with subject "
56 "\"${subject}\" has been deleted unseen. This is no guarantee "
57 "that the message will not be \"undeleted\" and nonetheless "
58 "read later on.")},
59 {Dispatched,
60 "dispatched",
61 kli18n("The message sent on ${date} to ${to} with subject "
62 "\"${subject}\" has been dispatched. This is no guarantee "
63 "that the message will not be read later on.")},
64 {Processed,
65 "processed",
66 kli18n("The message sent on ${date} to ${to} with subject "
67 "\"${subject}\" has been processed by some automatic means.")},
68 {Denied,
69 "denied",
70 kli18n("The message sent on ${date} to ${to} with subject "
71 "\"${subject}\" has been acted upon. The sender does not wish "
72 "to disclose more details to you than that.")},
73 {Failed,
74 "failed",
75 kli18n("Generation of a Message Disposition Notification for the "
76 "message sent on ${date} to ${to} with subject \"${subject}\" "
77 "failed. Reason is given in the Failure: header field below.")}};
78
79static const int numDispositionTypes =
80 sizeof dispositionTypes / sizeof *dispositionTypes;
81
82static const char *stringFor(DispositionType d)
83{
84 for (int i = 0 ; i < numDispositionTypes ; ++i) {
85 if (dispositionTypes[i].dispositionType == d) {
86 return dispositionTypes[i].string;
87 }
88 }
89 return nullptr;
90}
91
92//
93// disposition-modifier
94//
95static const struct {
96 DispositionModifier dispositionModifier;
97 const char *string;
98} dispositionModifiers[] = {
99 { Error, "error" },
100 { Warning, "warning" },
101 { Superseded, "superseded" },
102 { Expired, "expired" },
103 { MailboxTerminated, "mailbox-terminated" }
104};
105
106static const int numDispositionModifiers =
107 sizeof dispositionModifiers / sizeof *dispositionModifiers;
108
109static const char *stringFor(DispositionModifier m)
110{
111 for (int i = 0 ; i < numDispositionModifiers ; ++i) {
112 if (dispositionModifiers[i].dispositionModifier == m) {
113 return dispositionModifiers[i].string;
114 }
115 }
116 return nullptr;
117}
118
119//
120// action-mode (part of disposition-mode)
121//
122
123static const struct {
124 ActionMode actionMode;
125 const char *string;
126} actionModes[] = {
127 { ManualAction, "manual-action" },
128 { AutomaticAction, "automatic-action" }
129};
130
131static const int numActionModes =
132 sizeof actionModes / sizeof *actionModes;
133
134static const char *stringFor(ActionMode a)
135{
136 for (int i = 0 ; i < numActionModes ; ++i) {
137 if (actionModes[i].actionMode == a) {
138 return actionModes[i].string;
139 }
140 }
141 return nullptr;
142}
143
144//
145// sending-mode (part of disposition-mode)
146//
147
148static const struct {
149 SendingMode sendingMode;
150 const char *string;
151} sendingModes[] = {
152 { SentManually, "MDN-sent-manually" },
153 { SentAutomatically, "MDN-sent-automatically" }
154};
155
156static const int numSendingModes =
157 sizeof sendingModes / sizeof *sendingModes;
158
159static const char *stringFor(SendingMode s)
160{
161 for (int i = 0 ; i < numSendingModes ; ++i) {
162 if (sendingModes[i].sendingMode == s) {
163 return sendingModes[i].string;
164 }
165 }
166 return nullptr;
167}
168
169static QByteArray dispositionField(DispositionType d, ActionMode a,
170 SendingMode s,
172
173 // mandatory parts: Disposition: foo/baz; bar
174 QByteArray result = "Disposition: ";
175 result += stringFor(a);
176 result += '/';
177 result += stringFor(s);
178 result += "; ";
179 result += stringFor(d);
180
181 // optional parts: Disposition: foo/baz; bar/mod1,mod2,mod3
182 bool first = true;
184 mt != m.end(); ++mt) {
185 if (first) {
186 result += '/';
187 first = false;
188 } else {
189 result += ',';
190 }
191 result += stringFor(*mt);
192 }
193 return result + '\n';
194}
195
196static QByteArray finalRecipient(const QString &recipient)
197{
198 if (recipient.isEmpty()) {
199 return {};
200 } else {
201 return "Final-Recipient: rfc822; "
202 + encodeRFC2047String(recipient, "utf-8") + '\n';
203 }
204}
205
206static QByteArray orginalRecipient(const QByteArray &recipient)
207{
208 if (recipient.isEmpty()) {
209 return {};
210 } else {
211 return "Original-Recipient: " + recipient + '\n';
212 }
213}
214
215static QByteArray originalMessageID(const QByteArray &msgid)
216{
217 if (msgid.isEmpty()) {
218 return {};
219 } else {
220 return "Original-Message-ID: " + msgid + '\n';
221 }
222}
223
224static QByteArray reportingUAField()
225{
226 char hostName[256];
227 if (gethostname(hostName, 255)) {
228 hostName[0] = '\0'; // gethostname failed: pretend empty string
229 } else {
230 hostName[255] = '\0'; // gethostname may have returned 255 chars (man page)
231 }
232 return QByteArray("Reporting-UA: ") + QByteArray(hostName) +
233 QByteArray("; KMime " KMIME_VERSION_STRING "\n");
234}
235
237 const QString &r, const QByteArray &o, const QByteArray &omid,
239 const QList<DispositionModifier> &m, const QString &special) {
240 // in Perl: chomp(special)
241 QString spec;
242 if (special.endsWith(QLatin1Char('\n'))) {
243 spec = special.left(special.length() - 1);
244 } else {
245 spec = special;
246 }
247
248 // std headers:
249 QByteArray result = reportingUAField();
250 result += orginalRecipient(o);
251 result += finalRecipient(r);
252 result += originalMessageID(omid);
253 result += dispositionField(d, a, s, m);
254
255 // headers that are only present for certain disposition {types,modifiers}:
256 if (d == Failed) {
257 result += "Failure: " + encodeRFC2047String(spec, "utf-8") + '\n';
258 } else if (m.contains(Error)) {
259 result += "Error: " + encodeRFC2047String(spec, "utf-8") + '\n';
260 } else if (m.contains(Warning)) {
261 result += "Warning: " + encodeRFC2047String(spec, "utf-8") + '\n';
262 }
263
264 return result;
265}
266
267QString descriptionFor(DispositionType d, const QList<DispositionModifier> &) {
268 for (int i = 0 ; i < numDispositionTypes ; ++i) {
269 if (dispositionTypes[i].dispositionType == d) {
270 return dispositionTypes[i].description.toString();
271 }
272 }
273 qCWarning(KMIME_LOG) << "KMime::MDN::descriptionFor(): No such disposition type:"
274 << static_cast<int>(d);
275 return {};
276}
277
278} // namespace MDN
279} // 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.
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 kmime_mdn.h:142
DispositionType
The following disposition-types are defined:
Definition kmime_mdn.h:89
AKONADI_MIME_EXPORT const char Deleted[]
KCODECS_EXPORT QByteArray encodeRFC2047String(QStringView src, const QByteArray &charset)
bool isEmpty() const const
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 Tue Mar 26 2024 11:20:12 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.