• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.10.5 API Reference
  • KDE Home
  • Contact Us
 

KTNEF Library

  • ktnef
ktnefwriter.cpp
Go to the documentation of this file.
1 /*
2  ktnefwriter.cpp
3 
4  Copyright (C) 2002 Bo Thorsen <bo@sonofthor.dk>
5 
6  This file is part of KTNEF, the KDE TNEF support library/program.
7 
8  This library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU Library General Public
10  License as published by the Free Software Foundation; either
11  version 2 of the License, or (at your option) any later version.
12 
13  This library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  Library General Public License for more details.
17 
18  You should have received a copy of the GNU Library General Public License
19  along with this library; see the file COPYING.LIB. If not, write to
20  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  Boston, MA 02110-1301, USA.
22  */
31 #include "ktnefwriter.h"
32 #include "ktnefproperty.h"
33 #include "ktnefpropertyset.h"
34 #include "ktnefdefs.h"
35 
36 #include <kdebug.h>
37 
38 #include <QtCore/QFile>
39 #include <QtCore/QDateTime>
40 #include <QtCore/QDataStream>
41 #include <QtCore/QList>
42 #include <QtCore/QByteArray>
43 
44 #include <assert.h>
45 
46 using namespace KTnef;
47 
52 //@cond PRIVATE
53 class KTnef::KTNEFWriter::PrivateData
54 {
55  public:
56  PrivateData() { mFirstAttachNum = QDateTime::currentDateTime().toTime_t(); }
57  KTNEFPropertySet properties;
58  quint16 mFirstAttachNum;
59 };
60 //@endcond
61 
62 KTNEFWriter::KTNEFWriter() : d( new KTnef::KTNEFWriter::PrivateData )
63 {
64  // This is not something the user should fiddle with
65  // First set the TNEF version
66  QVariant v(0x00010000);
67  addProperty( attTNEFVERSION, atpDWORD, v );
68 
69  // Now set the code page to something reasonable. TODO: Use the right one
70  QVariant v1( (quint32)0x4e4 );
71  QVariant v2( (quint32)0x0 );
72  QList<QVariant> list;
73  list << v1;
74  list << v2;
75  v = QVariant( list );
76  addProperty( attOEMCODEPAGE, atpBYTE, list );
77 }
78 
79 KTNEFWriter::~KTNEFWriter()
80 {
81  delete d;
82 }
83 
84 void KTNEFWriter::addProperty( int tag, int type, const QVariant &value )
85 {
86  d->properties.addProperty( tag, type, value );
87 }
88 
89 //@cond IGNORE
90 void addToChecksum( quint32 i, quint16 &checksum )
91 {
92  checksum += i & 0xff;
93  checksum += ( i >> 8 ) & 0xff;
94  checksum += ( i >> 16 ) & 0xff;
95  checksum += ( i >> 24 ) & 0xff;
96 }
97 
98 void addToChecksum( QByteArray &cs, quint16 &checksum )
99 {
100  int len = cs.length();
101  for ( int i=0; i<len; i++ ) {
102  checksum += (quint8)cs[i];
103  }
104 }
105 
106 void writeCString( QDataStream &stream, QByteArray &str )
107 {
108  stream.writeRawData( str.data(), str.length() );
109  stream << (quint8)0;
110 }
111 
112 quint32 mergeTagAndType( quint32 tag, quint32 type )
113 {
114  return ( ( type & 0xffff ) << 16 ) | ( tag & 0xffff );
115 }
116 //@endcond
117 
118 /* This writes a TNEF property to the file.
119  *
120  * A TNEF property has a 1 byte type (LVL_MESSAGE or LVL_ATTACHMENT),
121  * a 4 byte type/tag, a 4 byte length, the data and finally the checksum.
122  *
123  * The checksum is a 16 byte int with all bytes in the data added.
124  */
125 bool KTNEFWriter::writeProperty( QDataStream &stream, int &bytes, int tag ) const
126 {
127  QMap<int,KTNEFProperty*>& properties = d->properties.properties();
128  QMap<int,KTNEFProperty*>::Iterator it = properties.find( tag );
129 
130  if ( it == properties.end() ) {
131  return false;
132  }
133 
134  KTNEFProperty *property = *it;
135 
136  quint32 i;
137  quint16 checksum = 0;
138  QList<QVariant> list;
139  QString s;
140  QByteArray cs, cs2;
141  QDateTime dt;
142  QDate date;
143  QTime time;
144  switch( tag ) {
145  case attMSGSTATUS:
146  // quint8
147  i = property->value().toUInt() & 0xff;
148  checksum = i;
149 
150  stream << (quint8)LVL_MESSAGE;
151  stream << mergeTagAndType( tag, property->type() );
152  stream << (quint32)1;
153  stream << (quint8)i;
154 
155  bytes += 10;
156  break;
157 
158  case attMSGPRIORITY:
159  case attREQUESTRES:
160  // quint16
161  i = property->value().toUInt() & 0xffff;
162  addToChecksum( i, checksum );
163 
164  stream << (quint8)LVL_MESSAGE;
165  stream << mergeTagAndType( tag, property->type() );
166  stream << (quint32)2;
167  stream << (quint16)i;
168 
169  bytes += 11;
170  break;
171 
172  case attTNEFVERSION:
173  // quint32
174  i = property->value().toUInt();
175  addToChecksum( i, checksum );
176 
177  stream << (quint8)LVL_MESSAGE;
178  stream << mergeTagAndType( tag, property->type() );
179  stream << (quint32)4;
180  stream << (quint32)i;
181 
182  bytes += 13;
183  break;
184 
185  case attOEMCODEPAGE:
186  // 2 quint32
187  list = property->value().toList();
188  assert( list.count() == 2 );
189 
190  stream << (quint8)LVL_MESSAGE;
191  stream << mergeTagAndType( tag, property->type() );
192  stream << (quint32)8;
193 
194  i = list[0].toInt();
195  addToChecksum( i, checksum );
196  stream << (quint32)i;
197  i = list[1].toInt();
198  addToChecksum( i, checksum );
199  stream << (quint32)i;
200 
201  bytes += 17;
202  break;
203 
204  case attMSGCLASS:
205  case attSUBJECT:
206  case attBODY:
207  case attMSGID:
208  // QCString
209  cs = property->value().toString().toLocal8Bit();
210  addToChecksum( cs, checksum );
211 
212  stream << (quint8)LVL_MESSAGE;
213  stream << mergeTagAndType( tag, property->type() );
214  stream << (quint32)cs.length()+1;
215  writeCString( stream, cs );
216 
217  bytes += 9 + cs.length()+1;
218  break;
219 
220  case attFROM:
221  // 2 QString encoded to a TRP structure
222  list = property->value().toList();
223  assert( list.count() == 2 );
224 
225  cs = list[0].toString().toLocal8Bit(); // Name
226  cs2 = QString( QLatin1String( "smtp:" ) + list[1].toString() ).toLocal8Bit(); // Email address
227  i = 18 + cs.length() + cs2.length(); // 2 * sizof(TRP) + strings + 2x'\0'
228 
229  stream << (quint8)LVL_MESSAGE;
230  stream << mergeTagAndType( tag, property->type() );
231  stream << (quint32)i;
232 
233  // The stream has to be aligned to 4 bytes for the strings
234  // TODO: Or does it? Looks like Outlook doesn't do this
235  // bytes += 17;
236  // Write the first TRP structure
237  stream << (quint16)4; // trpidOneOff
238  stream << (quint16)i; // totalsize
239  stream << (quint16)( cs.length() + 1 ); // sizeof name
240  stream << (quint16)( cs2.length() + 1 );// sizeof address
241 
242  // if ( bytes % 4 != 0 )
243  // Align the buffer
244 
245  // Write the strings
246  writeCString( stream, cs );
247  writeCString( stream, cs2 );
248 
249  // Write the empty padding TRP structure (just zeroes)
250  stream << (quint32)0 << (quint32)0;
251 
252  addToChecksum( 4, checksum );
253  addToChecksum( i, checksum );
254  addToChecksum( cs.length()+1, checksum );
255  addToChecksum( cs2.length()+1, checksum );
256  addToChecksum( cs, checksum );
257  addToChecksum( cs2, checksum );
258 
259  bytes += 10;
260  break;
261 
262  case attDATESENT:
263  case attDATERECD:
264  case attDATEMODIFIED:
265  // QDateTime
266  dt = property->value().toDateTime();
267  time = dt.time();
268  date = dt.date();
269 
270  stream << (quint8)LVL_MESSAGE;
271  stream << mergeTagAndType( tag, property->type() );
272  stream << (quint32)14;
273 
274  i = (quint16)date.year();
275  addToChecksum( i, checksum );
276  stream << (quint16)i;
277  i = (quint16)date.month();
278  addToChecksum( i, checksum );
279  stream << (quint16)i;
280  i = (quint16)date.day();
281  addToChecksum( i, checksum );
282  stream << (quint16)i;
283  i = (quint16)time.hour();
284  addToChecksum( i, checksum );
285  stream << (quint16)i;
286  i = (quint16)time.minute();
287  addToChecksum( i, checksum );
288  stream << (quint16)i;
289  i = (quint16)time.second();
290  addToChecksum( i, checksum );
291  stream << (quint16)i;
292  i = (quint16)date.dayOfWeek();
293  addToChecksum( i, checksum );
294  stream << (quint16)i;
295  break;
296 /*
297  case attMSGSTATUS:
298  {
299  quint8 c;
300  quint32 flag = 0;
301  if ( c & fmsRead ) flag |= MSGFLAG_READ;
302  if ( !( c & fmsModified ) ) flag |= MSGFLAG_UNMODIFIED;
303  if ( c & fmsSubmitted ) flag |= MSGFLAG_SUBMIT;
304  if ( c & fmsHasAttach ) flag |= MSGFLAG_HASATTACH;
305  if ( c & fmsLocal ) flag |= MSGFLAG_UNSENT;
306  d->stream_ >> c;
307 
308  i = property->value().toUInt();
309  stream << (quint8)LVL_MESSAGE;
310  stream << (quint32)type;
311  stream << (quint32)2;
312  stream << (quint8)i;
313  addToChecksum( i, checksum );
314  // from reader: d->message_->addProperty( 0x0E07, MAPI_TYPE_ULONG, flag );
315  }
316  kDebug() << "Message Status" << "(length=" << i2 << ")";
317  break;
318 */
319 
320  default:
321  kDebug() << "Unknown TNEF tag:" << tag;
322  return false;
323  }
324 
325  stream << (quint16)checksum;
326  return true;
327 }
328 
329 bool KTNEFWriter::writeFile( QIODevice &file ) const
330 {
331  if ( !file.open( QIODevice::WriteOnly ) ) {
332  return false;
333  }
334 
335  QDataStream stream( &file );
336  return writeFile( stream );
337 }
338 
339 bool KTNEFWriter::writeFile( QDataStream &stream ) const
340 {
341  stream.setByteOrder( QDataStream::LittleEndian );
342 
343  // Start by writing the opening TNEF stuff
344  stream << TNEF_SIGNATURE;
345 
346  // Store the PR_ATTACH_NUM value for the first attachment
347  // ( must be stored even if *no* attachments are stored )
348  stream << d->mFirstAttachNum;
349 
350  // Now do some writing
351  bool ok = true;
352  int bytesWritten = 0;
353  ok &= writeProperty( stream, bytesWritten, attTNEFVERSION );
354  ok &= writeProperty( stream, bytesWritten, attOEMCODEPAGE );
355  ok &= writeProperty( stream, bytesWritten, attMSGCLASS );
356  ok &= writeProperty( stream, bytesWritten, attMSGPRIORITY );
357  ok &= writeProperty( stream, bytesWritten, attSUBJECT );
358  ok &= writeProperty( stream, bytesWritten, attDATESENT );
359  ok &= writeProperty( stream, bytesWritten, attDATESTART );
360  ok &= writeProperty( stream, bytesWritten, attDATEEND );
361  // ok &= writeProperty( stream, bytesWritten, attAIDOWNER );
362  ok &= writeProperty( stream, bytesWritten, attREQUESTRES );
363  ok &= writeProperty( stream, bytesWritten, attFROM );
364  ok &= writeProperty( stream, bytesWritten, attDATERECD );
365  ok &= writeProperty( stream, bytesWritten, attMSGSTATUS );
366  ok &= writeProperty( stream, bytesWritten, attBODY );
367  return ok;
368 }
369 
370 void KTNEFWriter::setSender( const QString &name, const QString &email )
371 {
372  assert( !name.isEmpty() );
373  assert( !email.isEmpty() );
374 
375  QVariant v1( name );
376  QVariant v2( email );
377 
378  QList<QVariant> list;
379  list << v1;
380  list << v2;
381 
382  QVariant v( list );
383  addProperty( attFROM, 0, list ); // What's up with the 0 here ??
384 }
385 
386 void KTNEFWriter::setMessageType( MessageType m )
387 {
388  // Note that the MessageType list here is probably not long enough,
389  // more entries are most likely needed later
390 
391  QVariant v;
392  switch( m ) {
393  case Appointment:
394  v = QVariant( QString( "IPM.Appointment" ) );
395  break;
396 
397  case MeetingCancelled:
398  v = QVariant( QString( "IPM.Schedule.Meeting.Cancelled" ) );
399  break;
400 
401  case MeetingRequest:
402  v = QVariant( QString( "IPM.Schedule.Meeting.Request" ) );
403  break;
404 
405  case MeetingNo:
406  v = QVariant( QString( "IPM.Schedule.Meeting.Resp.Neg" ) );
407  break;
408 
409  case MeetingYes:
410  v = QVariant( QString( "IPM.Schedule.Meeting.Resp.Pos" ) );
411  break;
412 
413  case MeetingTent:
414  // Tent?
415  v = QVariant( QString( "IPM.Schedule.Meeting.Resp.Tent" ) );
416  break;
417 
418  default:
419  return;
420  }
421 
422  addProperty( attMSGCLASS, atpWORD, v );
423 }
424 
425 void KTNEFWriter::setMethod( Method )
426 {
427 
428 }
429 
430 void KTNEFWriter::clearAttendees()
431 {
432 
433 }
434 
435 void KTNEFWriter::addAttendee( const QString &cn, Role r,
436  PartStat p, bool rsvp,
437  const QString &mailto )
438 {
439  Q_UNUSED( cn );
440  Q_UNUSED( r );
441  Q_UNUSED( p );
442  Q_UNUSED( rsvp );
443  Q_UNUSED( mailto );
444 }
445 
446 // I assume this is the same as the sender?
447 // U also assume that this is like "Name <address>"
448 void KTNEFWriter::setOrganizer( const QString &organizer )
449 {
450  int i = organizer.indexOf( '<' );
451 
452  if ( i == -1 ) {
453  return;
454  }
455 
456  QString name = organizer.left( i );
457  name.trimmed();
458 
459  QString email = organizer.right( i+1 );
460  email = email.left( email.length()-1 );
461  email.trimmed();
462 
463  setSender( name, email );
464 }
465 
466 void KTNEFWriter::setDtStart( const QDateTime &dtStart )
467 {
468  QVariant v( dtStart );
469  addProperty( attDATESTART, atpDATE, v );
470 }
471 
472 void KTNEFWriter::setDtEnd( const QDateTime &dtEnd )
473 {
474  QVariant v( dtEnd );
475  addProperty( attDATEEND, atpDATE, v );
476 }
477 
478 void KTNEFWriter::setLocation( const QString &/*location*/ )
479 {
480 
481 }
482 
483 void KTNEFWriter::setUID( const QString &uid )
484 {
485  QVariant v( uid );
486  addProperty( attMSGID, atpSTRING, v );
487 }
488 
489 // Date sent
490 void KTNEFWriter::setDtStamp( const QDateTime &dtStamp )
491 {
492  QVariant v( dtStamp );
493  addProperty( attDATESENT, atpDATE, v );
494 }
495 
496 void KTNEFWriter::setCategories( const QStringList &)
497 {
498 
499 }
500 
501 // I hope this is the body
502 void KTNEFWriter::setDescription( const QString &body )
503 {
504  QVariant v( body );
505  addProperty( attBODY, atpTEXT, v );
506 }
507 
508 void KTNEFWriter::setSummary( const QString &s )
509 {
510  QVariant v( s );
511  addProperty( attSUBJECT, atpSTRING, v );
512 }
513 
514 // TNEF encoding: Normal = 3, high = 2, low = 1
515 // MAPI encoding: Normal = -1, high = 0, low = 1
516 void KTNEFWriter::setPriority( Priority p )
517 {
518  QVariant v( (quint32)p );
519  addProperty( attMSGPRIORITY, atpSHORT, v );
520 }
521 
522 void KTNEFWriter::setAlarm( const QString &description,
523  AlarmAction action,
524  const QDateTime &wakeBefore )
525 {
526  Q_UNUSED( description );
527  Q_UNUSED( action );
528  Q_UNUSED( wakeBefore );
529 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Sat Jul 13 2013 01:29:58 by doxygen 1.8.3.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KTNEF Library

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

kdepimlibs-4.10.5 API Reference

Skip menu "kdepimlibs-4.10.5 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal