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 <[email protected]>
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 <[email protected]>
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 
38 namespace KMime
39 {
40 
41 namespace MDN
42 {
43 
44 static 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 
79 static const int numDispositionTypes =
80  sizeof dispositionTypes / sizeof *dispositionTypes;
81 
82 static 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 //
95 static 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 
106 static const int numDispositionModifiers =
107  sizeof dispositionModifiers / sizeof *dispositionModifiers;
108 
109 static 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 
123 static const struct {
124  ActionMode actionMode;
125  const char *string;
126 } actionModes[] = {
127  { ManualAction, "manual-action" },
128  { AutomaticAction, "automatic-action" }
129 };
130 
131 static const int numActionModes =
132  sizeof actionModes / sizeof *actionModes;
133 
134 static 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 
148 static const struct {
149  SendingMode sendingMode;
150  const char *string;
151 } sendingModes[] = {
152  { SentManually, "MDN-sent-manually" },
153  { SentAutomatically, "MDN-sent-automatically" }
154 };
155 
156 static const int numSendingModes =
157  sizeof sendingModes / sizeof *sendingModes;
158 
159 static 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 
169 static QByteArray dispositionField(DispositionType d, ActionMode a,
170  SendingMode s,
171  const QList<DispositionModifier> &m) {
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 
196 static 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 
206 static QByteArray orginalRecipient(const QByteArray &recipient)
207 {
208  if (recipient.isEmpty()) {
209  return {};
210  } else {
211  return "Original-Recipient: " + recipient + '\n';
212  }
213 }
214 
215 static QByteArray originalMessageID(const QByteArray &msgid)
216 {
217  if (msgid.isEmpty()) {
218  return {};
219  } else {
220  return "Original-Message-ID: " + msgid + '\n';
221  }
222 }
223 
224 static 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 
267 QString 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
ActionMode
The following disposition modes are defined:
Definition: kmime_mdn.h:142
const KIMAP2_EXPORT QByteArray encodeRFC2047String(const QByteArray &str)
bool contains(const T &value) const const
Provides support for Message Disposition Notifications.
bool isEmpty() const const
DispositionType
The following disposition-types are defined:
Definition: kmime_mdn.h:89
const AKONADI_MIME_EXPORT char Deleted[]
DispositionModifier
The following disposition modifiers are defined:
Definition: kmime_mdn.h:119
bool isEmpty() const const
QList::iterator begin()
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: kmime_mdn.cpp:236
QList::iterator end()
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Dec 5 2023 03:53:31 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.