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

KDE's Doxygen guidelines are available online.