/* ktnefwriter.cpp Copyright (C) 2002 Bo Thorsen This file is part of KTNEF, the KDE TNEF support library/program. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifdef HAVE_CONFIG_H #include #endif /* HAVE_CONFIG_H */ #include "ktnef/ktnefwriter.h" #include "ktnef/ktnefproperty.h" #include "ktnef/ktnefpropertyset.h" #include #include #include #include #include #include "ktnef/ktnefdefs.h" class KTNEFWriter::PrivateData { public: PrivateData() { mFirstAttachNum = TQDateTime::currentDateTime().toTime_t(); } KTNEFPropertySet properties; TQ_UINT16 mFirstAttachNum; }; KTNEFWriter::KTNEFWriter() { mData = new PrivateData; // This is not something the user should fiddle with // First set the TNEF version TQVariant v(0x00010000); addProperty( attTNEFVERSION, atpDWORD, v ); // Now set the code page to something reasonable. TODO: Use the right one TQVariant v1( (TQ_UINT32)0x4e4 ); TQVariant v2( (TQ_UINT32)0x0 ); TQValueList list; list << v1; list << v2; v = TQVariant( list ); addProperty( attOEMCODEPAGE, atpBYTE, list ); } KTNEFWriter::~KTNEFWriter() { delete mData; } void KTNEFWriter::addProperty( int tag, int type, const TQVariant& value ) { mData->properties.addProperty( tag, type, value ); } void addToChecksum( TQ_UINT32 i, TQ_UINT16 &checksum ) { checksum += i & 0xff; checksum += (i >> 8) & 0xff; checksum += (i >> 16) & 0xff; checksum += (i >> 24) & 0xff; } void addToChecksum( TQCString &cs, TQ_UINT16 &checksum ) { int len = cs.length(); for (int i=0; i& properties = mData->properties.properties(); TQMap::Iterator it = properties.find( tag ); if ( it == properties.end() ) return false; KTNEFProperty *property = *it; TQ_UINT32 i; TQ_UINT16 checksum = 0; TQValueList list; TQString s; TQCString cs, cs2; TQDateTime dt; TQDate date; TQTime time; switch( tag ) { case attMSGSTATUS: // TQ_UINT8 i = property->value().toUInt() & 0xff; checksum = i; stream << (TQ_UINT8)LVL_MESSAGE; stream << mergeTagAndType( tag, property->type() ); stream << (TQ_UINT32)1; stream << (TQ_UINT8)i; bytes += 10; break; case attMSGPRIORITY: case attREQUESTRES: // TQ_UINT16 i = property->value().toUInt() & 0xffff; addToChecksum( i, checksum ); stream << (TQ_UINT8)LVL_MESSAGE; stream << mergeTagAndType( tag, property->type() ); stream << (TQ_UINT32)2; stream << (TQ_UINT16)i; bytes += 11; break; case attTNEFVERSION: // TQ_UINT32 i = property->value().toUInt(); addToChecksum( i, checksum ); stream << (TQ_UINT8)LVL_MESSAGE; stream << mergeTagAndType( tag, property->type() ); stream << (TQ_UINT32)4; stream << (TQ_UINT32)i; bytes += 13; break; case attOEMCODEPAGE: // 2 TQ_UINT32 list = property->value().toList(); assert( list.count() == 2 ); stream << (TQ_UINT8)LVL_MESSAGE; stream << mergeTagAndType( tag, property->type() ); stream << (TQ_UINT32)8; i = list[0].toInt(); addToChecksum( i, checksum ); stream << (TQ_UINT32)i; i = list[1].toInt(); addToChecksum( i, checksum ); stream << (TQ_UINT32)i; bytes += 17; break; case attMSGCLASS: case attSUBJECT: case attBODY: case attMSGID: // TQCString cs = property->value().toString().local8Bit(); addToChecksum( cs, checksum ); stream << (TQ_UINT8)LVL_MESSAGE; stream << mergeTagAndType( tag, property->type() ); stream << (TQ_UINT32)cs.length()+1; writeCString( stream, cs ); bytes += 9 + cs.length()+1; break; case attFROM: // 2 TQString encoded to a TRP structure list = property->value().toList(); assert( list.count() == 2 ); cs = list[0].toString().local8Bit(); // Name cs2 = (TQString("smtp:") + list[1].toString()).local8Bit(); // Email address i = 18 + cs.length() + cs2.length(); // 2 * sizof(TRP) + strings + 2x'\0' stream << (TQ_UINT8)LVL_MESSAGE; stream << mergeTagAndType( tag, property->type() ); stream << (TQ_UINT32)i; // The stream has to be aligned to 4 bytes for the strings // TODO: Or does it? Looks like Outlook doesn't do this // bytes += 17; // Write the first TRP structure stream << (TQ_UINT16)4; // trpidOneOff stream << (TQ_UINT16)i; // totalsize stream << (TQ_UINT16)(cs.length()+1); // sizeof name stream << (TQ_UINT16)(cs2.length()+1); // sizeof address // if ( bytes % 4 != 0 ) // Align the buffer // Write the strings writeCString( stream, cs ); writeCString( stream, cs2 ); // Write the empty padding TRP structure (just zeroes) stream << (TQ_UINT32)0 << (TQ_UINT32)0; addToChecksum( 4, checksum ); addToChecksum( i, checksum ); addToChecksum( cs.length()+1, checksum ); addToChecksum( cs2.length()+1, checksum ); addToChecksum( cs, checksum ); addToChecksum( cs2, checksum ); bytes += 10; break; case attDATESENT: case attDATERECD: case attDATEMODIFIED: // TQDateTime dt = property->value().toDateTime(); time = dt.time(); date = dt.date(); stream << (TQ_UINT8)LVL_MESSAGE; stream << mergeTagAndType( tag, property->type() ); stream << (TQ_UINT32)14; i = (TQ_UINT16)date.year(); addToChecksum( i, checksum ); stream << (TQ_UINT16)i; i = (TQ_UINT16)date.month(); addToChecksum( i, checksum ); stream << (TQ_UINT16)i; i = (TQ_UINT16)date.day(); addToChecksum( i, checksum ); stream << (TQ_UINT16)i; i = (TQ_UINT16)time.hour(); addToChecksum( i, checksum ); stream << (TQ_UINT16)i; i = (TQ_UINT16)time.minute(); addToChecksum( i, checksum ); stream << (TQ_UINT16)i; i = (TQ_UINT16)time.second(); addToChecksum( i, checksum ); stream << (TQ_UINT16)i; i = (TQ_UINT16)date.dayOfWeek(); addToChecksum( i, checksum ); stream << (TQ_UINT16)i; break; /* case attMSGSTATUS: { TQ_UINT8 c; TQ_UINT32 flag = 0; if ( c & fmsRead ) flag |= MSGFLAG_READ; if ( !( c & fmsModified ) ) flag |= MSGFLAG_UNMODIFIED; if ( c & fmsSubmitted ) flag |= MSGFLAG_SUBMIT; if ( c & fmsHasAttach ) flag |= MSGFLAG_HASATTACH; if ( c & fmsLocal ) flag |= MSGFLAG_UNSENT; d->stream_ >> c; i = property->value().toUInt(); stream << (TQ_UINT8)LVL_MESSAGE; stream << (TQ_UINT32)type; stream << (TQ_UINT32)2; stream << (TQ_UINT8)i; addToChecksum( i, checksum ); // from reader: d->message_->addProperty( 0x0E07, MAPI_TYPE_ULONG, flag ); } kdDebug() << "Message Status" << " (length=" << i2 << ")" << endl; break; */ default: kdDebug() << "Unknown TNEF tag: " << tag << endl; return false; } stream << (TQ_UINT16)checksum; return true; } bool KTNEFWriter::writeFile( TQIODevice &file ) { if ( !file.open( IO_WriteOnly ) ) return false; TQDataStream stream( &file ); return writeFile( stream ); } bool KTNEFWriter::writeFile( TQDataStream &stream ) { stream.setByteOrder( TQDataStream::LittleEndian ); // Start by writing the opening TNEF stuff stream << TNEF_SIGNATURE; // Store the PR_ATTACH_NUM value for the first attachment // ( must be stored even if *no* attachments are stored ) stream << mData->mFirstAttachNum; // Now do some writing bool ok = true; int bytesWritten = 0; ok &= writeProperty( stream, bytesWritten, attTNEFVERSION ); ok &= writeProperty( stream, bytesWritten, attOEMCODEPAGE ); ok &= writeProperty( stream, bytesWritten, attMSGCLASS ); ok &= writeProperty( stream, bytesWritten, attMSGPRIORITY ); ok &= writeProperty( stream, bytesWritten, attSUBJECT ); ok &= writeProperty( stream, bytesWritten, attDATESENT ); ok &= writeProperty( stream, bytesWritten, attDATESTART ); ok &= writeProperty( stream, bytesWritten, attDATEEND ); // ok &= writeProperty( stream, bytesWritten, attAIDOWNER ); ok &= writeProperty( stream, bytesWritten, attREQUESTRES ); ok &= writeProperty( stream, bytesWritten, attFROM ); ok &= writeProperty( stream, bytesWritten, attDATERECD ); ok &= writeProperty( stream, bytesWritten, attMSGSTATUS ); ok &= writeProperty( stream, bytesWritten, attBODY ); return ok; } void KTNEFWriter::setSender(const TQString &name, const TQString &email) { assert( !name.isEmpty() ); assert( !email.isEmpty() ); TQVariant v1( name ); TQVariant v2( email ); TQValueList list; list << v1; list << v2; TQVariant v( list ); addProperty( attFROM, 0, list ); // What's up with the 0 here ?? } void KTNEFWriter::setMessageType(MessageType m) { // Note that the MessageType list here is probably not long enough, // more entries are most likely needed later TQVariant v; switch( m ) { case Appointment: v = TQVariant( TQString( "IPM.Appointment" ) ); break; case MeetingCancelled: v = TQVariant( TQString( "IPM.Schedule.Meeting.Cancelled" ) ); break; case MeetingRequest: v = TQVariant( TQString( "IPM.Schedule.Meeting.Request" ) ); break; case MeetingNo: v = TQVariant( TQString( "IPM.Schedule.Meeting.Resp.Neg" ) ); break; case MeetingYes: v = TQVariant( TQString( "IPM.Schedule.Meeting.Resp.Pos" ) ); break; case MeetingTent: // Tent? v = TQVariant( TQString( "IPM.Schedule.Meeting.Resp.Tent" ) ); break; default: return; } addProperty( attMSGCLASS, atpWORD, v ); } void KTNEFWriter::setMethod( Method ) { } void KTNEFWriter::clearAttendees() { } void KTNEFWriter::addAttendee( const TQString& /*cn*/, Role /*r*/, PartStat /*p*/, bool /*rsvp*/, const TQString& /*mailto*/ ) { } // I assume this is the same as the sender? // U also assume that this is like "Name
" void KTNEFWriter::setOrganizer( const TQString& organizer ) { int i = organizer.find( '<' ); if ( i == -1 ) return; TQString name = organizer.left( i ); name.stripWhiteSpace(); TQString email = organizer.right( i+1 ); email = email.left( email.length()-1 ); email.stripWhiteSpace(); setSender( name, email ); } void KTNEFWriter::setDtStart( const TQDateTime& dtStart ) { TQVariant v( dtStart ); addProperty( attDATESTART, atpDATE, v ); } void KTNEFWriter::setDtEnd( const TQDateTime& dtEnd ) { TQVariant v( dtEnd ); addProperty( attDATEEND, atpDATE, v ); } void KTNEFWriter::setLocation( const TQString& /*location*/ ) { } void KTNEFWriter::setUID( const TQString& uid ) { TQVariant v( uid ); addProperty( attMSGID, atpSTRING, v ); } // Date sent void KTNEFWriter::setDtStamp( const TQDateTime& dtStamp ) { TQVariant v( dtStamp ); addProperty( attDATESENT, atpDATE, v ); } void KTNEFWriter::setCategories( const TQStringList& ) { } // I hope this is the body void KTNEFWriter::setDescription( const TQString &body ) { TQVariant v( body ); addProperty( attBODY, atpTEXT, v ); } void KTNEFWriter::setSummary( const TQString &s ) { TQVariant v( s ); addProperty( attSUBJECT, atpSTRING, v ); } // TNEF encoding: Normal = 3, high = 2, low = 1 // MAPI encoding: Normal = -1, high = 0, low = 1 void KTNEFWriter::setPriority( Priority p ) { TQVariant v( (TQ_UINT32)p ); addProperty( attMSGPRIORITY, atpSHORT, v ); } void KTNEFWriter::setAlarm( const TQString& /*description*/, AlarmAction /*action*/, const TQDateTime& /*wakeBefore*/ ) { }