00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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>
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
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
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
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
00172 QByteArray result = "Disposition: ";
00173 result += stringFor( a );
00174 result += '/';
00175 result += stringFor( s );
00176 result += "; ";
00177 result += stringFor( d );
00178
00179
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';
00226 } else {
00227 hostName[255] = '\0';
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
00243 QString spec;
00244 if ( special.endsWith('\n') ) {
00245 spec = special.left( special.length() - 1 );
00246 } else {
00247 spec = special;
00248 }
00249
00250
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
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 }
00283 }