kmime_mdn.cpp
Go to the documentation of this file.
00001 /* -*- c++ -*- 00002 kmime_mdn.cpp 00003 00004 KMime, the KDE Internet mail/usenet news message library. 00005 Copyright (c) 2002 Marc Mutz <mutz@kde.org> 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Library General Public 00009 License as published by the Free Software Foundation; either 00010 version 2 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Library General Public License for more details. 00016 00017 You should have received a copy of the GNU Library General Public License 00018 along with this library; see the file COPYING.LIB. If not, write to 00019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00020 Boston, MA 02110-1301, USA. 00021 */ 00034 #include "kmime_mdn.h" 00035 #include "kmime_version.h" 00036 #include "kmime_util.h" 00037 00038 #include <klocale.h> 00039 #include <kdebug.h> 00040 00041 #include <QtCore/QByteArray> 00042 #include <QtCore/QList> 00043 00044 #include <unistd.h> // gethostname 00045 00046 namespace KMime { 00047 00048 namespace MDN { 00049 00050 static const struct { 00051 DispositionType dispositionType; 00052 const char * string; 00053 const char * description; 00054 } dispositionTypes[] = { 00055 { Displayed, "displayed", 00056 I18N_NOOP("The message sent on ${date} to ${to} with subject " 00057 "\"${subject}\" has been displayed. This is no guarantee that " 00058 "the message has been read or understood.") }, 00059 { Deleted, "deleted", 00060 I18N_NOOP("The message sent on ${date} to ${to} with subject " 00061 "\"${subject}\" has been deleted unseen. This is no guarantee " 00062 "that the message will not be \"undeleted\" and nonetheless " 00063 "read later on.") }, 00064 { Dispatched, "dispatched", 00065 I18N_NOOP("The message sent on ${date} to ${to} with subject " 00066 "\"${subject}\" has been dispatched. This is no guarantee " 00067 "that the message will not be read later on.") }, 00068 { Processed, "processed", 00069 I18N_NOOP("The message sent on ${date} to ${to} with subject " 00070 "\"${subject}\" has been processed by some automatic means.") }, 00071 { Denied, "denied", 00072 I18N_NOOP("The message sent on ${date} to ${to} with subject " 00073 "\"${subject}\" has been acted upon. The sender does not wish " 00074 "to disclose more details to you than that.") }, 00075 { Failed, "failed", 00076 I18N_NOOP("Generation of a Message Disposition Notification for the " 00077 "message sent on ${date} to ${to} with subject \"${subject}\" " 00078 "failed. Reason is given in the Failure: header field below.") } 00079 }; 00080 00081 static const int numDispositionTypes = 00082 sizeof dispositionTypes / sizeof *dispositionTypes; 00083 00084 static const char *stringFor( DispositionType d ) 00085 { 00086 for ( int i = 0 ; i < numDispositionTypes ; ++i ) { 00087 if ( dispositionTypes[i].dispositionType == d ) { 00088 return dispositionTypes[i].string; 00089 } 00090 } 00091 return 0; 00092 } 00093 00094 // 00095 // disposition-modifier 00096 // 00097 static const struct { 00098 DispositionModifier dispositionModifier; 00099 const char * string; 00100 } dispositionModifiers[] = { 00101 { Error, "error" }, 00102 { Warning, "warning" }, 00103 { Superseded, "superseded" }, 00104 { Expired, "expired" }, 00105 { MailboxTerminated, "mailbox-terminated" } 00106 }; 00107 00108 static const int numDispositionModifiers = 00109 sizeof dispositionModifiers / sizeof * dispositionModifiers; 00110 00111 static const char *stringFor( DispositionModifier m ) { 00112 for ( int i = 0 ; i < numDispositionModifiers ; ++i ) { 00113 if ( dispositionModifiers[i].dispositionModifier == m ) { 00114 return dispositionModifiers[i].string; 00115 } 00116 } 00117 return 0; 00118 } 00119 00120 // 00121 // action-mode (part of disposition-mode) 00122 // 00123 00124 static const struct { 00125 ActionMode actionMode; 00126 const char * string; 00127 } actionModes[] = { 00128 { ManualAction, "manual-action" }, 00129 { AutomaticAction, "automatic-action" } 00130 }; 00131 00132 static const int numActionModes = 00133 sizeof actionModes / sizeof *actionModes; 00134 00135 static const char *stringFor( ActionMode a ) { 00136 for ( int i = 0 ; i < numActionModes ; ++i ) { 00137 if ( actionModes[i].actionMode == a ) { 00138 return actionModes[i].string; 00139 } 00140 } 00141 return 0; 00142 } 00143 00144 // 00145 // sending-mode (part of disposition-mode) 00146 // 00147 00148 static const struct { 00149 SendingMode sendingMode; 00150 const char * string; 00151 } sendingModes[] = { 00152 { SentManually, "MDN-sent-manually" }, 00153 { SentAutomatically, "MDN-sent-automatically" } 00154 }; 00155 00156 static const int numSendingModes = 00157 sizeof sendingModes / sizeof *sendingModes; 00158 00159 static const char *stringFor( SendingMode s ) { 00160 for ( int i = 0 ; i < numSendingModes ; ++i ) { 00161 if ( sendingModes[i].sendingMode == s ) { 00162 return sendingModes[i].string; 00163 } 00164 } 00165 return 0; 00166 } 00167 00168 static QByteArray dispositionField( DispositionType d, ActionMode a, SendingMode s, 00169 const QList<DispositionModifier> & m ) { 00170 00171 // mandatory parts: Disposition: foo/baz; bar 00172 QByteArray result = "Disposition: "; 00173 result += stringFor( a ); 00174 result += '/'; 00175 result += stringFor( s ); 00176 result += "; "; 00177 result += stringFor( d ); 00178 00179 // optional parts: Disposition: foo/baz; bar/mod1,mod2,mod3 00180 bool first = true; 00181 for ( QList<DispositionModifier>::const_iterator mt = m.begin() ; 00182 mt != m.end() ; ++mt ) { 00183 if ( first ) { 00184 result += '/'; 00185 first = false; 00186 } else { 00187 result += ','; 00188 } 00189 result += stringFor( *mt ); 00190 } 00191 return result + '\n'; 00192 } 00193 00194 static QByteArray finalRecipient( const QString &recipient ) 00195 { 00196 if ( recipient.isEmpty() ) { 00197 return QByteArray(); 00198 } else { 00199 return "Final-Recipient: rfc822; " 00200 + encodeRFC2047String( recipient, "utf-8" ) + '\n'; 00201 } 00202 } 00203 00204 static QByteArray orginalRecipient( const QByteArray & recipient ) 00205 { 00206 if ( recipient.isEmpty() ) { 00207 return QByteArray(); 00208 } else { 00209 return "Original-Recipient: " + recipient + '\n'; 00210 } 00211 } 00212 00213 static QByteArray originalMessageID( const QByteArray &msgid ) 00214 { 00215 if ( msgid.isEmpty() ) { 00216 return QByteArray(); 00217 } else { 00218 return "Original-Message-ID: " + msgid + '\n'; 00219 } 00220 } 00221 00222 static QByteArray reportingUAField() { 00223 char hostName[256]; 00224 if ( gethostname( hostName, 255 ) ) { 00225 hostName[0] = '\0'; // gethostname failed: pretend empty string 00226 } else { 00227 hostName[255] = '\0'; // gethostname may have returned 255 chars (man page) 00228 } 00229 return QByteArray("Reporting-UA: ") + QByteArray( hostName ) + 00230 QByteArray( "; KMime " KMIME_VERSION_STRING "\n" ); 00231 } 00232 00233 QByteArray dispositionNotificationBodyContent( const QString &r, 00234 const QByteArray &o, 00235 const QByteArray &omid, 00236 DispositionType d, 00237 ActionMode a, 00238 SendingMode s, 00239 const QList<DispositionModifier> &m, 00240 const QString &special ) 00241 { 00242 // in Perl: chomp(special) 00243 QString spec; 00244 if ( special.endsWith( QLatin1Char( '\n' ) ) ) { 00245 spec = special.left( special.length() - 1 ); 00246 } else { 00247 spec = special; 00248 } 00249 00250 // std headers: 00251 QByteArray result = reportingUAField(); 00252 result += orginalRecipient( o ); 00253 result += finalRecipient( r ); 00254 result += originalMessageID( omid ); 00255 result += dispositionField( d, a, s, m ); 00256 00257 // headers that are only present for certain disposition {types,modifiers}: 00258 if ( d == Failed ) { 00259 result += "Failure: " + encodeRFC2047String( spec, "utf-8" ) + '\n'; 00260 } else if ( m.contains( Error ) ) { 00261 result += "Error: " + encodeRFC2047String( spec, "utf-8" ) + '\n'; 00262 } else if ( m.contains( Warning ) ) { 00263 result += "Warning: " + encodeRFC2047String( spec, "utf-8" ) + '\n'; 00264 } 00265 00266 return result; 00267 } 00268 00269 QString descriptionFor( DispositionType d, 00270 const QList<DispositionModifier> & ) 00271 { 00272 for ( int i = 0 ; i < numDispositionTypes ; ++i ) { 00273 if ( dispositionTypes[i].dispositionType == d ) { 00274 return i18n( dispositionTypes[i].description ); 00275 } 00276 } 00277 kWarning() << "KMime::MDN::descriptionFor(): No such disposition type:" 00278 << ( int )d; 00279 return QString(); 00280 } 00281 00282 } // namespace MDN 00283 } // namespace KMime