libkmime

kmime_mdn.cpp
1 /*
2  kmime_mdn.cpp
3 
4  This file is part of KMime, the KDE internet mail/usenet news message library.
5  Copyright (c) 2002 Marc Mutz <mutz@kde.org>
6 
7  KMime is free software; you can redistribute it and/or modify it
8  under the terms of the GNU General Public License, version 2, as
9  published by the Free Software Foundation.
10 
11  KMime is distributed in the hope that it will be useful, but
12  WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this library; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 
20  In addition, as a special exception, the copyright holders give
21  permission to link the code of this library with any edition of
22  the TQt library by Trolltech AS, Norway (or with modified versions
23  of TQt that use the same license as TQt), and distribute linked
24  combinations including the two. You must obey the GNU General
25  Public License in all respects for all of the code used other than
26  TQt. If you modify this file, you may extend this exception to
27  your version of the file, but you are not obligated to do so. If
28  you do not wish to do so, delete this exception statement from
29  your version.
30 */
31 
32 #include "kmime_mdn.h"
33 
34 #include "kmime_version.h"
35 #include "kmime_util.h"
36 
37 #include <tdelocale.h>
38 #include <kdebug.h>
39 
40 #include <tqcstring.h>
41 
42 #include <unistd.h> // gethostname
43 
44 namespace KMime {
45 
46 namespace MDN {
47 
48  static const struct {
49  DispositionType dispositionType;
50  const char * string;
51  const char * description;
52  } dispositionTypes[] = {
53  { Displayed, "displayed",
54  I18N_NOOP("The message sent on ${date} to ${to} with subject "
55  "\"${subject}\" has been displayed. This is no guarantee that "
56  "the message has been read or understood.") },
57  { Deleted, "deleted",
58  I18N_NOOP("The message sent on ${date} to ${to} with subject "
59  "\"${subject}\" has been deleted unseen. This is no guarantee "
60  "that the message will not be \"undeleted\" and nonetheless "
61  "read later on.") },
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  { Processed, "processed",
67  I18N_NOOP("The message sent on ${date} to ${to} with subject "
68  "\"${subject}\" has been processed by some automatic means.") },
69  { Denied, "denied",
70  I18N_NOOP("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, "failed",
74  I18N_NOOP("Generation of a Message Disposition Notification for the "
75  "message sent on ${date} to ${to} with subject \"${subject}\" "
76  "failed. Reason is given in the Failure: header field below.") }
77  };
78 
79  static const int numDispositionTypes
80  = sizeof dispositionTypes / sizeof *dispositionTypes;
81 
82 
83  static const char * stringFor( DispositionType d ) {
84  for ( int i = 0 ; i < numDispositionTypes ; ++i )
85  if ( dispositionTypes[i].dispositionType == d )
86  return dispositionTypes[i].string;
87  return 0;
88  }
89 
90 
91  //
92  // disposition-modifier
93  //
94  static const struct {
95  DispositionModifier dispositionModifier;
96  const char * string;
97  } dispositionModifiers[] = {
98  { Error, "error" },
99  { Warning, "warning" },
100  { Superseded, "superseded" },
101  { Expired, "expired" },
102  { MailboxTerminated, "mailbox-terminated" }
103  };
104 
105  static const int numDispositionModifiers
106  = sizeof dispositionModifiers / sizeof * dispositionModifiers;
107 
108 
109  static const char * stringFor( DispositionModifier m ) {
110  for ( int i = 0 ; i < numDispositionModifiers ; ++i )
111  if ( dispositionModifiers[i].dispositionModifier == m )
112  return dispositionModifiers[i].string;
113  return 0;
114  }
115 
116  //
117  // action-mode (part of disposition-mode)
118  //
119 
120  static const struct {
121  ActionMode actionMode;
122  const char * string;
123  } actionModes[] = {
124  { ManualAction, "manual-action" },
125  { AutomaticAction, "automatic-action" }
126  };
127 
128  static const int numActionModes = sizeof actionModes / sizeof *actionModes;
129 
130  static const char * stringFor( ActionMode a ) {
131  for ( int i = 0 ; i < numActionModes ; ++i )
132  if ( actionModes[i].actionMode == a )
133  return actionModes[i].string;
134  return 0;
135  }
136 
137 
138  //
139  // sending-mode (part of disposition-mode)
140  //
141 
142  static const struct {
143  SendingMode sendingMode;
144  const char * string;
145  } sendingModes[] = {
146  { SentManually, "MDN-sent-manually" },
147  { SentAutomatically, "MDN-sent-automatically" }
148  };
149 
150  static const int numSendingModes = sizeof sendingModes / sizeof *sendingModes;
151 
152  static const char * stringFor( SendingMode s ) {
153  for ( int i = 0 ; i < numSendingModes ; ++i )
154  if ( sendingModes[i].sendingMode == s )
155  return sendingModes[i].string;
156  return 0;
157  }
158 
159  static TQCString dispositionField( DispositionType d, ActionMode a, SendingMode s,
160  const TQValueList<DispositionModifier> & m ) {
161 
162  // mandatory parts: Disposition: foo/baz; bar
163  TQCString result = "Disposition: ";
164  result += stringFor( a );
165  result += "/";
166  result += stringFor( s );
167  result += "; ";
168  result += stringFor( d );
169 
170  // optional parts: Disposition: foo/baz; bar/mod1,mod2,mod3
171  bool first = true;
172  for ( TQValueList<DispositionModifier>::const_iterator mt = m.begin() ;
173  mt != m.end() ; ++mt ) {
174  if ( first ) {
175  result += "/";
176  first = false;
177  } else {
178  result += ",";
179  }
180  result += stringFor( *mt );
181  }
182  return result + "\n";
183  }
184 
185  static TQCString finalRecipient( const TQString & recipient ) {
186  if ( recipient.isEmpty() )
187  return TQCString();
188  else
189  return "Final-Recipient: rfc822; "
190  + encodeRFC2047String( recipient, "utf-8" ) + "\n";
191  }
192 
193  static TQCString orginalRecipient( const TQCString & recipient ) {
194  if ( recipient.isEmpty() )
195  return TQCString();
196  else
197  return "Original-Recipient: " + recipient + "\n";
198  }
199 
200  static TQCString originalMessageID( const TQCString & msgid ) {
201  if ( msgid.isEmpty() )
202  return TQCString();
203  else
204  return "Original-Message-ID: " + msgid + "\n";
205  }
206 
207  static TQCString reportingUAField() {
208  char hostName[256];
209  if ( gethostname( hostName, 255 ) )
210  hostName[0] = '\0'; // gethostname failed: pretend empty string
211  else
212  hostName[255] = '\0'; // gethostname may have returned 255 chars (man page)
213  return TQCString("Reporting-UA: ") + hostName
214  + "; KMime " KMIME_VERSION_STRING "\n";
215  }
216 
217  TQCString dispositionNotificationBodyContent( const TQString & r,
218  const TQCString & o,
219  const TQCString & omid,
220  DispositionType d,
221  ActionMode a,
222  SendingMode s,
223  const TQValueList<DispositionModifier> & m,
224  const TQString & special )
225  {
226  // in Perl: chomp(special)
227  TQString spec;
228  if ( special.endsWith("\n") )
229  spec = special.left( special.length() - 1 );
230  else
231  spec = special;
232 
233  // std headers:
234  TQCString result = reportingUAField();
235  result += orginalRecipient( o );
236  result += finalRecipient( r );
237  result += originalMessageID( omid );
238  result += dispositionField( d, a, s, m );
239 
240  // headers that are only present for certain disposition {types,modifiers}:
241  if ( d == Failed )
242  result += "Failure: " + encodeRFC2047String( spec, "utf-8" ) + "\n";
243  else if ( m.contains( Error ) )
244  result += "Error: " + encodeRFC2047String( spec, "utf-8" ) + "\n";
245  else if ( m.contains( Warning ) )
246  result += "Warning: " + encodeRFC2047String( spec, "utf-8" ) + "\n";
247 
248  return result;
249  }
250 
251  TQString descriptionFor( DispositionType d,
252  const TQValueList<DispositionModifier> & ) {
253  for ( int i = 0 ; i < numDispositionTypes ; ++i )
254  if ( dispositionTypes[i].dispositionType == d )
255  return i18n( dispositionTypes[i].description );
256  kdWarning() << "KMime::MDN::descriptionFor(): No such disposition type: "
257  << (int)d << endl;
258  return TQString();
259  }
260 
261 } // namespace MDN
262 } // namespace KMime