KTNEF Library
ktnefwriter.cpp
Go to the documentation of this file.
00001 /* 00002 ktnefwriter.cpp 00003 00004 Copyright (C) 2002 Bo Thorsen <bo@sonofthor.dk> 00005 00006 This file is part of KTNEF, the KDE TNEF support library/program. 00007 00008 This library is free software; you can redistribute it and/or 00009 modify it under the terms of the GNU Library General Public 00010 License as published by the Free Software Foundation; either 00011 version 2 of the License, or (at your option) any later version. 00012 00013 This library is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 Library General Public License for more details. 00017 00018 You should have received a copy of the GNU Library General Public License 00019 along with this library; see the file COPYING.LIB. If not, write to 00020 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00021 Boston, MA 02110-1301, USA. 00022 */ 00031 #include "ktnefwriter.h" 00032 #include "ktnefproperty.h" 00033 #include "ktnefpropertyset.h" 00034 #include "ktnefdefs.h" 00035 00036 #include <kdebug.h> 00037 00038 #include <QtCore/QFile> 00039 #include <QtCore/QDateTime> 00040 #include <QtCore/QDataStream> 00041 #include <QtCore/QList> 00042 #include <QtCore/QByteArray> 00043 00044 #include <assert.h> 00045 00046 using namespace KTnef; 00047 00052 //@cond PRIVATE 00053 class KTnef::KTNEFWriter::PrivateData 00054 { 00055 public: 00056 PrivateData() { mFirstAttachNum = QDateTime::currentDateTime().toTime_t(); } 00057 KTNEFPropertySet properties; 00058 quint16 mFirstAttachNum; 00059 }; 00060 //@endcond 00061 00062 KTNEFWriter::KTNEFWriter() : d( new KTnef::KTNEFWriter::PrivateData ) 00063 { 00064 // This is not something the user should fiddle with 00065 // First set the TNEF version 00066 QVariant v(0x00010000); 00067 addProperty( attTNEFVERSION, atpDWORD, v ); 00068 00069 // Now set the code page to something reasonable. TODO: Use the right one 00070 QVariant v1( (quint32)0x4e4 ); 00071 QVariant v2( (quint32)0x0 ); 00072 QList<QVariant> list; 00073 list << v1; 00074 list << v2; 00075 v = QVariant( list ); 00076 addProperty( attOEMCODEPAGE, atpBYTE, list ); 00077 } 00078 00079 KTNEFWriter::~KTNEFWriter() 00080 { 00081 delete d; 00082 } 00083 00084 void KTNEFWriter::addProperty( int tag, int type, const QVariant &value ) 00085 { 00086 d->properties.addProperty( tag, type, value ); 00087 } 00088 00089 //@cond IGNORE 00090 void addToChecksum( quint32 i, quint16 &checksum ) 00091 { 00092 checksum += i & 0xff; 00093 checksum += ( i >> 8 ) & 0xff; 00094 checksum += ( i >> 16 ) & 0xff; 00095 checksum += ( i >> 24 ) & 0xff; 00096 } 00097 00098 void addToChecksum( QByteArray &cs, quint16 &checksum ) 00099 { 00100 int len = cs.length(); 00101 for ( int i=0; i<len; i++ ) { 00102 checksum += (quint8)cs[i]; 00103 } 00104 } 00105 00106 void writeCString( QDataStream &stream, QByteArray &str ) 00107 { 00108 stream.writeRawData( str.data(), str.length() ); 00109 stream << (quint8)0; 00110 } 00111 00112 quint32 mergeTagAndType( quint32 tag, quint32 type ) 00113 { 00114 return ( ( type & 0xffff ) << 16 ) | ( tag & 0xffff ); 00115 } 00116 //@endcond 00117 00118 /* This writes a TNEF property to the file. 00119 * 00120 * A TNEF property has a 1 byte type (LVL_MESSAGE or LVL_ATTACHMENT), 00121 * a 4 byte type/tag, a 4 byte length, the data and finally the checksum. 00122 * 00123 * The checksum is a 16 byte int with all bytes in the data added. 00124 */ 00125 bool KTNEFWriter::writeProperty( QDataStream &stream, int &bytes, int tag ) const 00126 { 00127 QMap<int,KTNEFProperty*>& properties = d->properties.properties(); 00128 QMap<int,KTNEFProperty*>::Iterator it = properties.find( tag ); 00129 00130 if ( it == properties.end() ) { 00131 return false; 00132 } 00133 00134 KTNEFProperty *property = *it; 00135 00136 quint32 i; 00137 quint16 checksum = 0; 00138 QList<QVariant> list; 00139 QString s; 00140 QByteArray cs, cs2; 00141 QDateTime dt; 00142 QDate date; 00143 QTime time; 00144 switch( tag ) { 00145 case attMSGSTATUS: 00146 // quint8 00147 i = property->value().toUInt() & 0xff; 00148 checksum = i; 00149 00150 stream << (quint8)LVL_MESSAGE; 00151 stream << mergeTagAndType( tag, property->type() ); 00152 stream << (quint32)1; 00153 stream << (quint8)i; 00154 00155 bytes += 10; 00156 break; 00157 00158 case attMSGPRIORITY: 00159 case attREQUESTRES: 00160 // quint16 00161 i = property->value().toUInt() & 0xffff; 00162 addToChecksum( i, checksum ); 00163 00164 stream << (quint8)LVL_MESSAGE; 00165 stream << mergeTagAndType( tag, property->type() ); 00166 stream << (quint32)2; 00167 stream << (quint16)i; 00168 00169 bytes += 11; 00170 break; 00171 00172 case attTNEFVERSION: 00173 // quint32 00174 i = property->value().toUInt(); 00175 addToChecksum( i, checksum ); 00176 00177 stream << (quint8)LVL_MESSAGE; 00178 stream << mergeTagAndType( tag, property->type() ); 00179 stream << (quint32)4; 00180 stream << (quint32)i; 00181 00182 bytes += 13; 00183 break; 00184 00185 case attOEMCODEPAGE: 00186 // 2 quint32 00187 list = property->value().toList(); 00188 assert( list.count() == 2 ); 00189 00190 stream << (quint8)LVL_MESSAGE; 00191 stream << mergeTagAndType( tag, property->type() ); 00192 stream << (quint32)8; 00193 00194 i = list[0].toInt(); 00195 addToChecksum( i, checksum ); 00196 stream << (quint32)i; 00197 i = list[1].toInt(); 00198 addToChecksum( i, checksum ); 00199 stream << (quint32)i; 00200 00201 bytes += 17; 00202 break; 00203 00204 case attMSGCLASS: 00205 case attSUBJECT: 00206 case attBODY: 00207 case attMSGID: 00208 // QCString 00209 cs = property->value().toString().toLocal8Bit(); 00210 addToChecksum( cs, checksum ); 00211 00212 stream << (quint8)LVL_MESSAGE; 00213 stream << mergeTagAndType( tag, property->type() ); 00214 stream << (quint32)cs.length()+1; 00215 writeCString( stream, cs ); 00216 00217 bytes += 9 + cs.length()+1; 00218 break; 00219 00220 case attFROM: 00221 // 2 QString encoded to a TRP structure 00222 list = property->value().toList(); 00223 assert( list.count() == 2 ); 00224 00225 cs = list[0].toString().toLocal8Bit(); // Name 00226 cs2 = QString( QLatin1String( "smtp:" ) + list[1].toString() ).toLocal8Bit(); // Email address 00227 i = 18 + cs.length() + cs2.length(); // 2 * sizof(TRP) + strings + 2x'\0' 00228 00229 stream << (quint8)LVL_MESSAGE; 00230 stream << mergeTagAndType( tag, property->type() ); 00231 stream << (quint32)i; 00232 00233 // The stream has to be aligned to 4 bytes for the strings 00234 // TODO: Or does it? Looks like Outlook doesn't do this 00235 // bytes += 17; 00236 // Write the first TRP structure 00237 stream << (quint16)4; // trpidOneOff 00238 stream << (quint16)i; // totalsize 00239 stream << (quint16)( cs.length() + 1 ); // sizeof name 00240 stream << (quint16)( cs2.length() + 1 );// sizeof address 00241 00242 // if ( bytes % 4 != 0 ) 00243 // Align the buffer 00244 00245 // Write the strings 00246 writeCString( stream, cs ); 00247 writeCString( stream, cs2 ); 00248 00249 // Write the empty padding TRP structure (just zeroes) 00250 stream << (quint32)0 << (quint32)0; 00251 00252 addToChecksum( 4, checksum ); 00253 addToChecksum( i, checksum ); 00254 addToChecksum( cs.length()+1, checksum ); 00255 addToChecksum( cs2.length()+1, checksum ); 00256 addToChecksum( cs, checksum ); 00257 addToChecksum( cs2, checksum ); 00258 00259 bytes += 10; 00260 break; 00261 00262 case attDATESENT: 00263 case attDATERECD: 00264 case attDATEMODIFIED: 00265 // QDateTime 00266 dt = property->value().toDateTime(); 00267 time = dt.time(); 00268 date = dt.date(); 00269 00270 stream << (quint8)LVL_MESSAGE; 00271 stream << mergeTagAndType( tag, property->type() ); 00272 stream << (quint32)14; 00273 00274 i = (quint16)date.year(); 00275 addToChecksum( i, checksum ); 00276 stream << (quint16)i; 00277 i = (quint16)date.month(); 00278 addToChecksum( i, checksum ); 00279 stream << (quint16)i; 00280 i = (quint16)date.day(); 00281 addToChecksum( i, checksum ); 00282 stream << (quint16)i; 00283 i = (quint16)time.hour(); 00284 addToChecksum( i, checksum ); 00285 stream << (quint16)i; 00286 i = (quint16)time.minute(); 00287 addToChecksum( i, checksum ); 00288 stream << (quint16)i; 00289 i = (quint16)time.second(); 00290 addToChecksum( i, checksum ); 00291 stream << (quint16)i; 00292 i = (quint16)date.dayOfWeek(); 00293 addToChecksum( i, checksum ); 00294 stream << (quint16)i; 00295 break; 00296 /* 00297 case attMSGSTATUS: 00298 { 00299 quint8 c; 00300 quint32 flag = 0; 00301 if ( c & fmsRead ) flag |= MSGFLAG_READ; 00302 if ( !( c & fmsModified ) ) flag |= MSGFLAG_UNMODIFIED; 00303 if ( c & fmsSubmitted ) flag |= MSGFLAG_SUBMIT; 00304 if ( c & fmsHasAttach ) flag |= MSGFLAG_HASATTACH; 00305 if ( c & fmsLocal ) flag |= MSGFLAG_UNSENT; 00306 d->stream_ >> c; 00307 00308 i = property->value().toUInt(); 00309 stream << (quint8)LVL_MESSAGE; 00310 stream << (quint32)type; 00311 stream << (quint32)2; 00312 stream << (quint8)i; 00313 addToChecksum( i, checksum ); 00314 // from reader: d->message_->addProperty( 0x0E07, MAPI_TYPE_ULONG, flag ); 00315 } 00316 kDebug() << "Message Status" << "(length=" << i2 << ")"; 00317 break; 00318 */ 00319 00320 default: 00321 kDebug() << "Unknown TNEF tag:" << tag; 00322 return false; 00323 } 00324 00325 stream << (quint16)checksum; 00326 return true; 00327 } 00328 00329 bool KTNEFWriter::writeFile( QIODevice &file ) const 00330 { 00331 if ( !file.open( QIODevice::WriteOnly ) ) { 00332 return false; 00333 } 00334 00335 QDataStream stream( &file ); 00336 return writeFile( stream ); 00337 } 00338 00339 bool KTNEFWriter::writeFile( QDataStream &stream ) const 00340 { 00341 stream.setByteOrder( QDataStream::LittleEndian ); 00342 00343 // Start by writing the opening TNEF stuff 00344 stream << TNEF_SIGNATURE; 00345 00346 // Store the PR_ATTACH_NUM value for the first attachment 00347 // ( must be stored even if *no* attachments are stored ) 00348 stream << d->mFirstAttachNum; 00349 00350 // Now do some writing 00351 bool ok = true; 00352 int bytesWritten = 0; 00353 ok &= writeProperty( stream, bytesWritten, attTNEFVERSION ); 00354 ok &= writeProperty( stream, bytesWritten, attOEMCODEPAGE ); 00355 ok &= writeProperty( stream, bytesWritten, attMSGCLASS ); 00356 ok &= writeProperty( stream, bytesWritten, attMSGPRIORITY ); 00357 ok &= writeProperty( stream, bytesWritten, attSUBJECT ); 00358 ok &= writeProperty( stream, bytesWritten, attDATESENT ); 00359 ok &= writeProperty( stream, bytesWritten, attDATESTART ); 00360 ok &= writeProperty( stream, bytesWritten, attDATEEND ); 00361 // ok &= writeProperty( stream, bytesWritten, attAIDOWNER ); 00362 ok &= writeProperty( stream, bytesWritten, attREQUESTRES ); 00363 ok &= writeProperty( stream, bytesWritten, attFROM ); 00364 ok &= writeProperty( stream, bytesWritten, attDATERECD ); 00365 ok &= writeProperty( stream, bytesWritten, attMSGSTATUS ); 00366 ok &= writeProperty( stream, bytesWritten, attBODY ); 00367 return ok; 00368 } 00369 00370 void KTNEFWriter::setSender( const QString &name, const QString &email ) 00371 { 00372 assert( !name.isEmpty() ); 00373 assert( !email.isEmpty() ); 00374 00375 QVariant v1( name ); 00376 QVariant v2( email ); 00377 00378 QList<QVariant> list; 00379 list << v1; 00380 list << v2; 00381 00382 QVariant v( list ); 00383 addProperty( attFROM, 0, list ); // What's up with the 0 here ?? 00384 } 00385 00386 void KTNEFWriter::setMessageType( MessageType m ) 00387 { 00388 // Note that the MessageType list here is probably not long enough, 00389 // more entries are most likely needed later 00390 00391 QVariant v; 00392 switch( m ) { 00393 case Appointment: 00394 v = QVariant( QString( "IPM.Appointment" ) ); 00395 break; 00396 00397 case MeetingCancelled: 00398 v = QVariant( QString( "IPM.Schedule.Meeting.Cancelled" ) ); 00399 break; 00400 00401 case MeetingRequest: 00402 v = QVariant( QString( "IPM.Schedule.Meeting.Request" ) ); 00403 break; 00404 00405 case MeetingNo: 00406 v = QVariant( QString( "IPM.Schedule.Meeting.Resp.Neg" ) ); 00407 break; 00408 00409 case MeetingYes: 00410 v = QVariant( QString( "IPM.Schedule.Meeting.Resp.Pos" ) ); 00411 break; 00412 00413 case MeetingTent: 00414 // Tent? 00415 v = QVariant( QString( "IPM.Schedule.Meeting.Resp.Tent" ) ); 00416 break; 00417 00418 default: 00419 return; 00420 } 00421 00422 addProperty( attMSGCLASS, atpWORD, v ); 00423 } 00424 00425 void KTNEFWriter::setMethod( Method ) 00426 { 00427 00428 } 00429 00430 void KTNEFWriter::clearAttendees() 00431 { 00432 00433 } 00434 00435 void KTNEFWriter::addAttendee( const QString &cn, Role r, 00436 PartStat p, bool rsvp, 00437 const QString &mailto ) 00438 { 00439 Q_UNUSED( cn ); 00440 Q_UNUSED( r ); 00441 Q_UNUSED( p ); 00442 Q_UNUSED( rsvp ); 00443 Q_UNUSED( mailto ); 00444 } 00445 00446 // I assume this is the same as the sender? 00447 // U also assume that this is like "Name <address>" 00448 void KTNEFWriter::setOrganizer( const QString &organizer ) 00449 { 00450 int i = organizer.indexOf( '<' ); 00451 00452 if ( i == -1 ) { 00453 return; 00454 } 00455 00456 QString name = organizer.left( i ); 00457 name.trimmed(); 00458 00459 QString email = organizer.right( i+1 ); 00460 email = email.left( email.length()-1 ); 00461 email.trimmed(); 00462 00463 setSender( name, email ); 00464 } 00465 00466 void KTNEFWriter::setDtStart( const QDateTime &dtStart ) 00467 { 00468 QVariant v( dtStart ); 00469 addProperty( attDATESTART, atpDATE, v ); 00470 } 00471 00472 void KTNEFWriter::setDtEnd( const QDateTime &dtEnd ) 00473 { 00474 QVariant v( dtEnd ); 00475 addProperty( attDATEEND, atpDATE, v ); 00476 } 00477 00478 void KTNEFWriter::setLocation( const QString &/*location*/ ) 00479 { 00480 00481 } 00482 00483 void KTNEFWriter::setUID( const QString &uid ) 00484 { 00485 QVariant v( uid ); 00486 addProperty( attMSGID, atpSTRING, v ); 00487 } 00488 00489 // Date sent 00490 void KTNEFWriter::setDtStamp( const QDateTime &dtStamp ) 00491 { 00492 QVariant v( dtStamp ); 00493 addProperty( attDATESENT, atpDATE, v ); 00494 } 00495 00496 void KTNEFWriter::setCategories( const QStringList &) 00497 { 00498 00499 } 00500 00501 // I hope this is the body 00502 void KTNEFWriter::setDescription( const QString &body ) 00503 { 00504 QVariant v( body ); 00505 addProperty( attBODY, atpTEXT, v ); 00506 } 00507 00508 void KTNEFWriter::setSummary( const QString &s ) 00509 { 00510 QVariant v( s ); 00511 addProperty( attSUBJECT, atpSTRING, v ); 00512 } 00513 00514 // TNEF encoding: Normal = 3, high = 2, low = 1 00515 // MAPI encoding: Normal = -1, high = 0, low = 1 00516 void KTNEFWriter::setPriority( Priority p ) 00517 { 00518 QVariant v( (quint32)p ); 00519 addProperty( attMSGPRIORITY, atpSHORT, v ); 00520 } 00521 00522 void KTNEFWriter::setAlarm( const QString &description, 00523 AlarmAction action, 00524 const QDateTime &wakeBefore ) 00525 { 00526 Q_UNUSED( description ); 00527 Q_UNUSED( action ); 00528 Q_UNUSED( wakeBefore ); 00529 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Aug 27 2012 22:10:31 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Aug 27 2012 22:10:31 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.