• Skip to content
  • Skip to link menu
KDE 4.0 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • Sitemap
  • Contact Us
 

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 
00085 void KTNEFWriter::addProperty( int tag, int type, const QVariant &value )
00086 {
00087   d->properties.addProperty( tag, type, value );
00088 }
00089 
00090 //@cond IGNORE
00091 void addToChecksum( quint32 i, quint16 &checksum )
00092 {
00093   checksum += i & 0xff;
00094   checksum += (i >> 8) & 0xff;
00095   checksum += (i >> 16) & 0xff;
00096   checksum += (i >> 24) & 0xff;
00097 }
00098 
00099 void addToChecksum( QByteArray &cs, quint16 &checksum )
00100 {
00101   int len = cs.length();
00102   for ( int i=0; i<len; i++ ) {
00103     checksum += (quint8)cs[i];
00104   }
00105 }
00106 
00107 void writeCString( QDataStream &stream, QByteArray &str )
00108 {
00109   stream.writeRawData( str.data(), str.length() );
00110   stream << (quint8)0;
00111 }
00112 
00113 quint32 mergeTagAndType( quint32 tag, quint32 type )
00114 {
00115   return ( ( type & 0xffff ) << 16 ) | ( tag & 0xffff );
00116 }
00117 //@endcond
00118 
00119 /* This writes a TNEF property to the file.
00120  *
00121  * A TNEF property has a 1 byte type (LVL_MESSAGE or LVL_ATTACHMENT),
00122  * a 4 byte type/tag, a 4 byte length, the data and finally the checksum.
00123  *
00124  * The checksum is a 16 byte int with all bytes in the data added.
00125  */
00126 bool KTNEFWriter::writeProperty( QDataStream &stream, int &bytes, int tag ) const
00127 {
00128   QMap<int,KTNEFProperty*>& properties = d->properties.properties();
00129   QMap<int,KTNEFProperty*>::Iterator it = properties.find( tag );
00130 
00131   if ( it == properties.end() ) {
00132     return false;
00133   }
00134 
00135   KTNEFProperty *property = *it;
00136 
00137   quint32 i;
00138   quint16 checksum = 0;
00139   QList<QVariant> list;
00140   QString s;
00141   QByteArray cs, cs2;
00142   QDateTime dt;
00143   QDate date;
00144   QTime time;
00145   switch( tag ) {
00146   case attMSGSTATUS:
00147     // quint8
00148     i = property->value().toUInt() & 0xff;
00149     checksum = i;
00150 
00151     stream << (quint8)LVL_MESSAGE;
00152     stream << mergeTagAndType( tag, property->type() );
00153     stream << (quint32)1;
00154     stream << (quint8)i;
00155 
00156     bytes += 10;
00157     break;
00158 
00159   case attMSGPRIORITY:
00160   case attREQUESTRES:
00161     // quint16
00162     i = property->value().toUInt() & 0xffff;
00163     addToChecksum( i, checksum );
00164 
00165     stream << (quint8)LVL_MESSAGE;
00166     stream << mergeTagAndType( tag, property->type() );
00167     stream << (quint32)2;
00168     stream << (quint16)i;
00169 
00170     bytes += 11;
00171     break;
00172 
00173   case attTNEFVERSION:
00174     // quint32
00175     i = property->value().toUInt();
00176     addToChecksum( i, checksum );
00177 
00178     stream << (quint8)LVL_MESSAGE;
00179     stream << mergeTagAndType( tag, property->type() );
00180     stream << (quint32)4;
00181     stream << (quint32)i;
00182 
00183     bytes += 13;
00184     break;
00185 
00186   case attOEMCODEPAGE:
00187     // 2 quint32
00188     list = property->value().toList();
00189     assert( list.count() == 2 );
00190 
00191     stream << (quint8)LVL_MESSAGE;
00192     stream << mergeTagAndType( tag, property->type() );
00193     stream << (quint32)8;
00194 
00195     i = list[0].toInt();
00196     addToChecksum( i, checksum );
00197     stream << (quint32)i;
00198     i = list[1].toInt();
00199     addToChecksum( i, checksum );
00200     stream << (quint32)i;
00201 
00202     bytes += 17;
00203     break;
00204 
00205   case attMSGCLASS:
00206   case attSUBJECT:
00207   case attBODY:
00208   case attMSGID:
00209     // QCString
00210     cs = property->value().toString().toLocal8Bit();
00211     addToChecksum( cs, checksum );
00212 
00213     stream << (quint8)LVL_MESSAGE;
00214     stream << mergeTagAndType( tag, property->type() );
00215     stream << (quint32)cs.length()+1;
00216     writeCString( stream, cs );
00217 
00218     bytes += 9 + cs.length()+1;
00219     break;
00220 
00221   case attFROM:
00222     // 2 QString encoded to a TRP structure
00223     list = property->value().toList();
00224     assert( list.count() == 2 );
00225 
00226     cs = list[0].toString().toLocal8Bit();                       // Name
00227     cs2 = (QString("smtp:") + list[1].toString()).toLocal8Bit(); // Email address
00228     i = 18 + cs.length() + cs2.length(); // 2 * sizof(TRP) + strings + 2x'\0'
00229 
00230     stream << (quint8)LVL_MESSAGE;
00231     stream << mergeTagAndType( tag, property->type() );
00232     stream << (quint32)i;
00233 
00234     // The stream has to be aligned to 4 bytes for the strings
00235     // TODO: Or does it? Looks like Outlook doesn't do this
00236     // bytes += 17;
00237     // Write the first TRP structure
00238     stream << (quint16)4;                 // trpidOneOff
00239     stream << (quint16)i;                 // totalsize
00240     stream << (quint16)(cs.length()+1);   // sizeof name
00241     stream << (quint16)(cs2.length()+1);  // sizeof address
00242 
00243     // if ( bytes % 4 != 0 )
00244       // Align the buffer
00245 
00246     // Write the strings
00247     writeCString( stream, cs );
00248     writeCString( stream, cs2 );
00249 
00250     // Write the empty padding TRP structure (just zeroes)
00251     stream << (quint32)0 << (quint32)0;
00252 
00253     addToChecksum( 4, checksum );
00254     addToChecksum( i, checksum );
00255     addToChecksum( cs.length()+1, checksum );
00256     addToChecksum( cs2.length()+1, checksum );
00257     addToChecksum( cs, checksum );
00258     addToChecksum( cs2, checksum );
00259 
00260     bytes += 10;
00261     break;
00262 
00263   case attDATESENT:
00264   case attDATERECD:
00265   case attDATEMODIFIED:
00266     // QDateTime
00267     dt = property->value().toDateTime();
00268     time = dt.time();
00269     date = dt.date();
00270 
00271     stream << (quint8)LVL_MESSAGE;
00272     stream << mergeTagAndType( tag, property->type() );
00273     stream << (quint32)14;
00274 
00275     i = (quint16)date.year();
00276     addToChecksum( i, checksum );
00277     stream << (quint16)i;
00278     i = (quint16)date.month();
00279     addToChecksum( i, checksum );
00280     stream << (quint16)i;
00281     i = (quint16)date.day();
00282     addToChecksum( i, checksum );
00283     stream << (quint16)i;
00284     i = (quint16)time.hour();
00285     addToChecksum( i, checksum );
00286     stream << (quint16)i;
00287     i = (quint16)time.minute();
00288     addToChecksum( i, checksum );
00289     stream << (quint16)i;
00290     i = (quint16)time.second();
00291     addToChecksum( i, checksum );
00292     stream << (quint16)i;
00293     i = (quint16)date.dayOfWeek();
00294     addToChecksum( i, checksum );
00295     stream << (quint16)i;
00296     break;
00297 /*
00298   case attMSGSTATUS:
00299     {
00300       quint8 c;
00301       quint32 flag = 0;
00302       if ( c & fmsRead ) flag |= MSGFLAG_READ;
00303       if ( !( c & fmsModified ) ) flag |= MSGFLAG_UNMODIFIED;
00304       if ( c & fmsSubmitted ) flag |= MSGFLAG_SUBMIT;
00305       if ( c & fmsHasAttach ) flag |= MSGFLAG_HASATTACH;
00306       if ( c & fmsLocal ) flag |= MSGFLAG_UNSENT;
00307       d->stream_ >> c;
00308 
00309       i = property->value().toUInt();
00310       stream << (quint8)LVL_MESSAGE;
00311       stream << (quint32)type;
00312       stream << (quint32)2;
00313       stream << (quint8)i;
00314       addToChecksum( i, checksum );
00315       // from reader: d->message_->addProperty( 0x0E07, MAPI_TYPE_ULONG, flag );
00316     }
00317     kDebug(5975) << "Message Status" << "(length=" << i2 << ")";
00318     break;
00319 */
00320 
00321   default:
00322     kDebug(5975) << "Unknown TNEF tag:" << tag;
00323     return false;
00324   }
00325 
00326   stream << (quint16)checksum;
00327   return true;
00328 }
00329 
00330 bool KTNEFWriter::writeFile( QIODevice &file ) const
00331 {
00332   if ( !file.open( QIODevice::WriteOnly ) ) {
00333     return false;
00334   }
00335 
00336   QDataStream stream( &file );
00337   return writeFile( stream );
00338 }
00339 
00340 bool KTNEFWriter::writeFile( QDataStream &stream ) const
00341 {
00342   stream.setByteOrder( QDataStream::LittleEndian );
00343 
00344   // Start by writing the opening TNEF stuff
00345   stream << TNEF_SIGNATURE;
00346 
00347   // Store the PR_ATTACH_NUM value for the first attachment
00348   // ( must be stored even if *no* attachments are stored )
00349   stream << d->mFirstAttachNum;
00350 
00351   // Now do some writing
00352   bool ok = true;
00353   int bytesWritten = 0;
00354   ok &= writeProperty( stream, bytesWritten, attTNEFVERSION );
00355   ok &= writeProperty( stream, bytesWritten, attOEMCODEPAGE );
00356   ok &= writeProperty( stream, bytesWritten, attMSGCLASS );
00357   ok &= writeProperty( stream, bytesWritten, attMSGPRIORITY );
00358   ok &= writeProperty( stream, bytesWritten, attSUBJECT );
00359   ok &= writeProperty( stream, bytesWritten, attDATESENT );
00360   ok &= writeProperty( stream, bytesWritten, attDATESTART );
00361   ok &= writeProperty( stream, bytesWritten, attDATEEND );
00362   // ok &= writeProperty( stream, bytesWritten, attAIDOWNER );
00363   ok &= writeProperty( stream, bytesWritten, attREQUESTRES );
00364   ok &= writeProperty( stream, bytesWritten, attFROM );
00365   ok &= writeProperty( stream, bytesWritten, attDATERECD );
00366   ok &= writeProperty( stream, bytesWritten, attMSGSTATUS );
00367   ok &= writeProperty( stream, bytesWritten, attBODY );
00368   return ok;
00369 }
00370 
00371 
00372 void KTNEFWriter::setSender( const QString &name, const QString &email )
00373 {
00374   assert( !name.isEmpty() );
00375   assert( !email.isEmpty() );
00376 
00377   QVariant v1( name );
00378   QVariant v2( email );
00379 
00380   QList<QVariant> list;
00381   list << v1;
00382   list << v2;
00383 
00384   QVariant v( list );
00385   addProperty( attFROM, 0, list ); // What's up with the 0 here ??
00386 }
00387 
00388 void KTNEFWriter::setMessageType( MessageType m )
00389 {
00390   // Note that the MessageType list here is probably not long enough,
00391   // more entries are most likely needed later
00392 
00393   QVariant v;
00394   switch( m ) {
00395   case Appointment:
00396     v = QVariant( QString( "IPM.Appointment" ) );
00397     break;
00398 
00399   case MeetingCancelled:
00400     v = QVariant( QString( "IPM.Schedule.Meeting.Cancelled" ) );
00401     break;
00402 
00403   case MeetingRequest:
00404     v = QVariant( QString( "IPM.Schedule.Meeting.Request" ) );
00405     break;
00406 
00407   case MeetingNo:
00408     v = QVariant( QString( "IPM.Schedule.Meeting.Resp.Neg" ) );
00409     break;
00410 
00411   case MeetingYes:
00412     v = QVariant( QString( "IPM.Schedule.Meeting.Resp.Pos" ) );
00413     break;
00414 
00415   case MeetingTent:
00416     // Tent?
00417     v = QVariant( QString( "IPM.Schedule.Meeting.Resp.Tent" ) );
00418     break;
00419 
00420   default:
00421     return;
00422   }
00423 
00424   addProperty( attMSGCLASS, atpWORD, v );
00425 }
00426 
00427 
00428 void KTNEFWriter::setMethod( Method )
00429 {
00430 
00431 }
00432 
00433 
00434 void KTNEFWriter::clearAttendees()
00435 {
00436 
00437 }
00438 
00439 
00440 void KTNEFWriter::addAttendee( const QString &/*cn*/, Role /*r*/,
00441                                PartStat /*p*/, bool /*rsvp*/,
00442                                const QString &/*mailto*/ )
00443 {
00444 
00445 }
00446 
00447 
00448 // I assume this is the same as the sender?
00449 // U also assume that this is like "Name <address>"
00450 void KTNEFWriter::setOrganizer( const QString &organizer )
00451 {
00452   int i = organizer.indexOf( '<' );
00453 
00454   if ( i == -1 ) {
00455     return;
00456   }
00457 
00458   QString name = organizer.left( i );
00459   name.trimmed();
00460 
00461   QString email = organizer.right( i+1 );
00462   email = email.left( email.length()-1 );
00463   email.trimmed();
00464 
00465   setSender( name, email );
00466 }
00467 
00468 void KTNEFWriter::setDtStart( const QDateTime &dtStart )
00469 {
00470   QVariant v( dtStart );
00471   addProperty( attDATESTART, atpDATE, v );
00472 }
00473 
00474 void KTNEFWriter::setDtEnd( const QDateTime &dtEnd )
00475 {
00476   QVariant v( dtEnd );
00477   addProperty( attDATEEND, atpDATE, v );
00478 }
00479 
00480 void KTNEFWriter::setLocation( const QString &/*location*/ )
00481 {
00482 
00483 }
00484 
00485 void KTNEFWriter::setUID( const QString &uid )
00486 {
00487   QVariant v( uid );
00488   addProperty( attMSGID, atpSTRING, v );
00489 }
00490 
00491 // Date sent
00492 void KTNEFWriter::setDtStamp( const QDateTime &dtStamp )
00493 {
00494   QVariant v( dtStamp );
00495   addProperty( attDATESENT, atpDATE, v );
00496 }
00497 
00498 void KTNEFWriter::setCategories( const QStringList &)
00499 {
00500 
00501 }
00502 
00503 // I hope this is the body
00504 void KTNEFWriter::setDescription( const QString &body )
00505 {
00506   QVariant v( body );
00507   addProperty( attBODY, atpTEXT, v );
00508 }
00509 
00510 void KTNEFWriter::setSummary( const QString &s )
00511 {
00512   QVariant v( s );
00513   addProperty( attSUBJECT, atpSTRING, v );
00514 }
00515 
00516 // TNEF encoding: Normal =  3, high = 2, low = 1
00517 // MAPI encoding: Normal = -1, high = 0, low = 1
00518 void KTNEFWriter::setPriority( Priority p )
00519 {
00520   QVariant v( (quint32)p );
00521   addProperty( attMSGPRIORITY, atpSHORT, v );
00522 }
00523 
00524 void KTNEFWriter::setAlarm( const QString &/*description*/,
00525                             AlarmAction /*action*/,
00526                             const QDateTime &/*wakeBefore*/ )
00527 {
00528 }

KTNEF Library

Skip menu "KTNEF Library"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • kabc
  • kblog
  • kcal
  • kimap
  • kioslave
  •   imap4
  •   mbox
  • kldap
  • kmime
  • kpimidentities
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.5.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal