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
44namespace KMime {
45
46namespace 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