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

KTNEF Library

  • ktnef
ktnefparser.cpp
Go to the documentation of this file.
1 /*
2  ktnefparser.cpp
3 
4  Copyright (C) 2002 Michael Goffioul <kdeprint@swing.be>
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 "ktnefparser.h"
32 #include "ktnefattach.h"
33 #include "ktnefproperty.h"
34 #include "ktnefmessage.h"
35 #include "ktnefdefs.h"
36 
37 #include <kdebug.h>
38 #include <kmimetype.h>
39 #include <ksavefile.h>
40 
41 #include <QtCore/QDateTime>
42 #include <QtCore/QDataStream>
43 #include <QtCore/QFile>
44 #include <QtCore/QVariant>
45 #include <QtCore/QList>
46 
47 using namespace KTnef;
48 
49 //@cond PRIVATE
50 typedef struct {
51  quint16 type;
52  quint16 tag;
53  QVariant value;
54  struct {
55  quint32 type;
56  QVariant value;
57  } name;
58 } MAPI_value;
59 //@endcond
60 
61 //@cond IGNORE
62 void clearMAPIName( MAPI_value &mapi );
63 void clearMAPIValue( MAPI_value &mapi, bool clearName = true );
64 QString readMAPIString( QDataStream &stream, bool isUnicode = false,
65  bool align = true, int len = -1 );
66 quint16 readMAPIValue( QDataStream &stream, MAPI_value &mapi );
67 QDateTime readTNEFDate( QDataStream &stream );
68 QString readTNEFAddress( QDataStream &stream );
69 QByteArray readTNEFData( QDataStream &stream, quint32 len );
70 QVariant readTNEFAttribute( QDataStream &stream, quint16 type, quint32 len );
71 QDateTime formatTime( quint32 lowB, quint32 highB );
72 QString formatRecipient( const QMap<int,KTnef::KTNEFProperty*> &props );
73 //@endcond
74 
75 //------------------------------------------------------------------------------
76 
81 //@cond PRIVATE
82 class KTnef::KTNEFParser::ParserPrivate
83 {
84  public:
85  ParserPrivate()
86  {
87  defaultdir_ = "/tmp/";
88  current_ = 0;
89  deleteDevice_ = false;
90  device_ = 0;
91  message_ = new KTNEFMessage;
92  }
93  ~ParserPrivate()
94  {
95  delete message_;
96  }
97 
98  bool decodeAttachment();
99  bool decodeMessage();
100  bool extractAttachmentTo( KTNEFAttach *att, const QString &dirname );
101  void checkCurrent( int key );
102  bool readMAPIProperties( QMap<int,KTNEFProperty*>& props,
103  KTNEFAttach *attach = 0 );
104  bool parseDevice();
105  void deleteDevice();
106 
107  QDataStream stream_;
108  QIODevice *device_;
109  bool deleteDevice_;
110  QString defaultdir_;
111  KTNEFAttach *current_;
112  KTNEFMessage *message_;
113 };
114 //@endcond
115 
116 KTNEFParser::KTNEFParser()
117  : d( new ParserPrivate )
118 {
119 }
120 
121 KTNEFParser::~KTNEFParser()
122 {
123  d->deleteDevice();
124  delete d;
125 }
126 
127 KTNEFMessage *KTNEFParser::message() const
128 {
129  return d->message_;
130 }
131 
132 void KTNEFParser::ParserPrivate::deleteDevice()
133 {
134  if ( deleteDevice_ ) {
135  delete device_;
136  }
137  device_ = 0;
138  deleteDevice_ = false;
139 }
140 
141 bool KTNEFParser::ParserPrivate::decodeMessage()
142 {
143  quint32 i1, i2, off;
144  quint16 u, tag, type;
145  QVariant value;
146 
147  // read (type+name)
148  stream_ >> i1;
149  u = 0;
150  tag = ( i1 & 0x0000FFFF );
151  type = ( ( i1 & 0xFFFF0000 ) >> 16 );
152  // read data length
153  stream_ >> i2;
154  // offset after reading the value
155  off = device_->pos() + i2;
156  switch ( tag ) {
157  case attAIDOWNER:
158  {
159  uint tmp;
160  stream_ >> tmp;
161  value.setValue( tmp );
162  message_->addProperty( 0x0062, MAPI_TYPE_ULONG, value );
163  kDebug() << "Message Owner Appointment ID" << "(length=" << i2 << ")";
164  break;
165  }
166  case attREQUESTRES:
167  stream_ >> u;
168  message_->addProperty( 0x0063, MAPI_TYPE_UINT16, u );
169  value = ( bool )u;
170  kDebug() << "Message Request Response" << "(length=" << i2 << ")";
171  break;
172  case attDATERECD:
173  value = readTNEFDate( stream_ );
174  message_->addProperty( 0x0E06, MAPI_TYPE_TIME, value );
175  kDebug() << "Message Receive Date" << "(length=" << i2 << ")";
176  break;
177  case attMSGCLASS:
178  value = readMAPIString( stream_, false, false, i2 );
179  message_->addProperty( 0x001A, MAPI_TYPE_STRING8, value );
180  kDebug() << "Message Class" << "(length=" << i2 << ")";
181  break;
182  case attMSGPRIORITY:
183  stream_ >> u;
184  message_->addProperty( 0x0026, MAPI_TYPE_ULONG, 2-u );
185  value = u;
186  kDebug() << "Message Priority" << "(length=" << i2 << ")";
187  break;
188  case attMAPIPROPS:
189  kDebug() << "Message MAPI Properties" << "(length=" << i2 << ")";
190  {
191  int nProps = message_->properties().count();
192  i2 += device_->pos();
193  readMAPIProperties( message_->properties(), 0 );
194  device_->seek( i2 );
195  kDebug() << "Properties:" << message_->properties().count();
196  value = QString( "< %1 properties >" ).
197  arg( message_->properties().count() - nProps );
198  }
199  break;
200  case attTNEFVERSION:
201  {
202  uint tmp;
203  stream_ >> tmp;
204  value.setValue( tmp );
205  kDebug() << "Message TNEF Version" << "(length=" << i2 << ")";
206  }
207  break;
208  case attFROM:
209  message_->addProperty( 0x0024, MAPI_TYPE_STRING8, readTNEFAddress( stream_ ) );
210  device_->seek( device_->pos() - i2 );
211  value = readTNEFData( stream_, i2 );
212  kDebug() << "Message From" << "(length=" << i2 << ")";
213  break;
214  case attSUBJECT:
215  value = readMAPIString( stream_, false, false, i2 );
216  message_->addProperty( 0x0037, MAPI_TYPE_STRING8, value );
217  kDebug() << "Message Subject" << "(length=" << i2 << ")";
218  break;
219  case attDATESENT:
220  value = readTNEFDate( stream_ );
221  message_->addProperty( 0x0039, MAPI_TYPE_TIME, value );
222  kDebug() << "Message Date Sent" << "(length=" << i2 << ")";
223  break;
224  case attMSGSTATUS:
225  {
226  quint8 c;
227  quint32 flag = 0;
228  stream_ >> c;
229  if ( c & fmsRead ) {
230  flag |= MSGFLAG_READ;
231  }
232  if ( !( c & fmsModified ) ) {
233  flag |= MSGFLAG_UNMODIFIED;
234  }
235  if ( c & fmsSubmitted ) {
236  flag |= MSGFLAG_SUBMIT;
237  }
238  if ( c & fmsHasAttach ) {
239  flag |= MSGFLAG_HASATTACH;
240  }
241  if ( c & fmsLocal ) {
242  flag |= MSGFLAG_UNSENT;
243  }
244  message_->addProperty( 0x0E07, MAPI_TYPE_ULONG, flag );
245  value = c;
246  }
247  kDebug() << "Message Status" << "(length=" << i2 << ")";
248  break;
249  case attRECIPTABLE:
250  {
251  quint32 rows;
252  QList<QVariant> recipTable;
253  stream_ >> rows;
254  for ( uint i=0; i<rows; i++ ) {
255  QMap<int,KTNEFProperty*> props;
256  readMAPIProperties( props, 0 );
257  recipTable << formatRecipient( props );
258  }
259  message_->addProperty( 0x0E12, MAPI_TYPE_STRING8, recipTable );
260  device_->seek( device_->pos() - i2 );
261  value = readTNEFData( stream_, i2 );
262  }
263  kDebug() << "Message Recipient Table" << "(length=" << i2 << ")";
264  break;
265  case attBODY:
266  value = readMAPIString( stream_, false, false, i2 );
267  message_->addProperty( 0x1000, MAPI_TYPE_STRING8, value );
268  kDebug() << "Message Body" << "(length=" << i2 << ")";
269  break;
270  case attDATEMODIFIED:
271  value = readTNEFDate( stream_ );
272  message_->addProperty( 0x3008, MAPI_TYPE_TIME, value );
273  kDebug() << "Message Date Modified" << "(length=" << i2 << ")";
274  break;
275  case attMSGID:
276  value = readMAPIString( stream_, false, false, i2 );
277  message_->addProperty( 0x300B, MAPI_TYPE_STRING8, value );
278  kDebug() << "Message ID" << "(length=" << i2 << ")";
279  break;
280  case attOEMCODEPAGE:
281  value = readTNEFData( stream_, i2 );
282  kDebug() << "Message OEM Code Page" << "(length=" << i2 << ")";
283  break;
284  default:
285  value = readTNEFAttribute( stream_, type, i2 );
286  //kDebug().form( "Message: type=%x, length=%d, check=%x\n", i1, i2, u );
287  break;
288  }
289  // skip data
290  if ( device_->pos() != off && !device_->seek( off ) ) {
291  return false;
292  }
293  // get checksum
294  stream_ >> u;
295  // add TNEF attribute
296  message_->addAttribute( tag, type, value, true );
297  //kDebug() << "stream:" << device_->pos();
298  return true;
299 }
300 
301 bool KTNEFParser::ParserPrivate::decodeAttachment()
302 {
303  quint32 i;
304  quint16 tag, type, u;
305  QVariant value;
306  QString str;
307 
308  stream_ >> i; // i <- attribute type & name
309  tag = ( i & 0x0000FFFF );
310  type = ( ( i & 0xFFFF0000 ) >> 16 );
311  stream_ >> i; // i <- data length
312  checkCurrent( tag );
313  switch ( tag ) {
314  case attATTACHTITLE:
315  value = readMAPIString( stream_, false, false, i );
316  current_->setName( value.toString() );
317  kDebug() << "Attachment Title:" << current_->name();
318  break;
319  case attATTACHDATA:
320  current_->setSize( i );
321  current_->setOffset( device_->pos() );
322  device_->seek( device_->pos() + i );
323  value = QString( "< size=%1 >" ).arg( i );
324  kDebug() << "Attachment Data: size=" << i;
325  break;
326  case attATTACHMENT: // try to get attachment info
327  i += device_->pos();
328  readMAPIProperties( current_->properties(), current_ );
329  device_->seek( i );
330  current_->setIndex( current_->property( MAPI_TAG_INDEX ).toUInt() );
331  current_->setDisplaySize( current_->property( MAPI_TAG_SIZE ).toUInt() );
332  str = current_->property( MAPI_TAG_DISPLAYNAME ).toString();
333  if ( !str.isEmpty() ) {
334  current_->setDisplayName( str );
335  }
336  current_->setFileName( current_->property( MAPI_TAG_FILENAME ).
337  toString() );
338  str = current_->property( MAPI_TAG_MIMETAG ).toString();
339  if ( !str.isEmpty() ) {
340  current_->setMimeTag( str );
341  }
342  current_->setExtension( current_->property( MAPI_TAG_EXTENSION ).
343  toString() );
344  value = QString( "< %1 properties >" ).
345  arg( current_->properties().count() );
346  break;
347  case attATTACHMODDATE:
348  value = readTNEFDate( stream_ );
349  kDebug() << "Attachment Modification Date:" << value.toString();
350  break;
351  case attATTACHCREATEDATE:
352  value = readTNEFDate( stream_ );
353  kDebug() << "Attachment Creation Date:" << value.toString();
354  break;
355  case attATTACHMETAFILE:
356  kDebug() << "Attachment Metafile: size=" << i;
357  //value = QString( "< size=%1 >" ).arg( i );
358  //device_->seek( device_->pos()+i );
359  value = readTNEFData( stream_, i );
360  break;
361  default:
362  value = readTNEFAttribute( stream_, type, i );
363  kDebug() << "Attachment unknown field: tag="
364  << hex << tag << ", length=" << dec << i;
365  break;
366  }
367  stream_ >> u; // u <- checksum
368  // add TNEF attribute
369  current_->addAttribute( tag, type, value, true );
370  //kDebug() << "stream:" << device_->pos();
371 
372  return true;
373 }
374 
375 void KTNEFParser::setDefaultExtractDir( const QString &dirname )
376 {
377  d->defaultdir_ = dirname;
378 }
379 
380 bool KTNEFParser::ParserPrivate::parseDevice()
381 {
382  quint16 u;
383  quint32 i;
384  quint8 c;
385 
386  message_->clearAttachments();
387  delete current_;
388  current_ = 0;
389 
390  if ( !device_->open( QIODevice::ReadOnly ) ) {
391  kDebug() << "Couldn't open device";
392  return false;
393  }
394 
395  stream_.setDevice( device_ );
396  stream_.setByteOrder( QDataStream::LittleEndian );
397  stream_ >> i;
398  if ( i == TNEF_SIGNATURE ) {
399  stream_ >> u;
400  kDebug().nospace() << "Attachment cross reference key: 0x"
401  << hex << qSetFieldWidth( 4 ) << qSetPadChar( '0' ) << u;
402  //kDebug() << "stream:" << device_->pos();
403  while ( !stream_.atEnd() ) {
404  stream_ >> c;
405  switch( c ) {
406  case LVL_MESSAGE:
407  if ( !decodeMessage() ) {
408  goto end;
409  }
410  break;
411  case LVL_ATTACHMENT:
412  if ( !decodeAttachment() ) {
413  goto end;
414  }
415  break;
416  default:
417  kDebug() << "Unknown Level:" << c << ", at offset" << device_->pos();
418  goto end;
419  }
420  }
421  if ( current_ ) {
422  checkCurrent( attATTACHDATA ); // this line has the effect to append the
423  // attachment, if it has data. If not it does
424  // nothing, and the attachment will be discarded
425  delete current_;
426  current_ = 0;
427  }
428  return true;
429  } else {
430  kDebug() << "This is not a TNEF file";
431  end:
432  device_->close();
433  return false;
434  }
435 }
436 
437 bool KTNEFParser::extractFile( const QString &filename ) const
438 {
439  KTNEFAttach *att = d->message_->attachment( filename );
440  if ( !att ) {
441  return false;
442  }
443  return d->extractAttachmentTo( att, d->defaultdir_ );
444 }
445 
446 bool KTNEFParser::ParserPrivate::extractAttachmentTo( KTNEFAttach *att,
447  const QString &dirname )
448 {
449  QString filename = dirname + '/' + att->name();
450  if ( !device_->isOpen() ) {
451  return false;
452  }
453  if ( !device_->seek( att->offset() ) ) {
454  return false;
455  }
456  KSaveFile outfile( filename );
457  if ( !outfile.open() ) {
458  return false;
459  }
460 
461  quint32 len = att->size(), sz( 16384 );
462  int n( 0 );
463  char *buf = new char[sz];
464  bool ok( true );
465  while ( ok && len > 0 ) {
466  n = device_->read( buf, qMin( sz, len ) );
467  if ( n < 0 ) {
468  ok = false;
469  } else {
470  len -= n;
471  if ( outfile.write( buf, n ) != n ) {
472  ok = false;
473  }
474  }
475  }
476  delete [] buf;
477 
478  return ok;
479 }
480 
481 bool KTNEFParser::extractAll()
482 {
483  QList<KTNEFAttach*> l = d->message_->attachmentList();
484  QList<KTNEFAttach*>::const_iterator it = l.constBegin();
485  for ( ; it != l.constEnd(); ++it ) {
486  if ( !d->extractAttachmentTo( *it, d->defaultdir_ ) ) {
487  return false;
488  }
489  }
490  return true;
491 }
492 
493 bool KTNEFParser::extractFileTo( const QString &filename,
494  const QString &dirname ) const
495 {
496  kDebug() << "Extracting attachment: filename="
497  << filename << ", dir=" << dirname;
498  KTNEFAttach *att = d->message_->attachment( filename );
499  if ( !att ) {
500  return false;
501  }
502  return d->extractAttachmentTo( att, dirname );
503 }
504 
505 bool KTNEFParser::openFile( const QString &filename ) const
506 {
507  d->deleteDevice();
508  delete d->message_;
509  d->message_ = new KTNEFMessage();
510  d->device_ = new QFile( filename );
511  d->deleteDevice_ = true;
512  return d->parseDevice();
513 }
514 
515 bool KTNEFParser::openDevice( QIODevice *device )
516 {
517  d->deleteDevice();
518  d->device_ = device;
519  return d->parseDevice();
520 }
521 
522 void KTNEFParser::ParserPrivate::checkCurrent( int key )
523 {
524  if ( !current_ ) {
525  current_ = new KTNEFAttach();
526  } else {
527  if ( current_->attributes().contains( key ) ) {
528  if ( current_->offset() >= 0 ) {
529  if ( current_->name().isEmpty() ) {
530  current_->setName( "Unnamed" );
531  }
532  if ( current_->mimeTag().isEmpty() ) {
533  // No mime type defined in the TNEF structure,
534  // try to find it from the attachment filename
535  // and/or content (using at most 32 bytes)
536  KMimeType::Ptr mimetype;
537  if ( !current_->fileName().isEmpty() ) {
538  mimetype = KMimeType::findByPath( current_->fileName(), 0, true );
539  }
540  if ( !mimetype ) {
541  return; // FIXME
542  }
543  if ( mimetype->name() == "application/octet-stream" &&
544  current_->size() > 0 ) {
545  int oldOffset = device_->pos();
546  QByteArray buffer( qMin( 32, current_->size() ), '\0' );
547  device_->seek( current_->offset() );
548  device_->read( buffer.data(), buffer.size() );
549  mimetype = KMimeType::findByContent( buffer );
550  device_->seek( oldOffset );
551  }
552  current_->setMimeTag( mimetype->name() );
553  }
554  message_->addAttachment( current_ );
555  current_ = 0;
556  } else {
557  // invalid attachment, skip it
558  delete current_;
559  current_ = 0;
560  }
561  current_ = new KTNEFAttach();
562  }
563  }
564 }
565 
566 //------------------------------------------------------------------------------
567 
568 //@cond IGNORE
569 #define ALIGN( n, b ) if ( n & ( b-1 ) ) { n = ( n + b ) & ~( b-1 ); }
570 #define ISVECTOR( m ) ( ( ( m ).type & 0xF000 ) == MAPI_TYPE_VECTOR )
571 
572 void clearMAPIName( MAPI_value &mapi )
573 {
574  mapi.name.value.clear();
575 }
576 
577 void clearMAPIValue( MAPI_value &mapi, bool clearName )
578 {
579  mapi.value.clear();
580  if ( clearName ) {
581  clearMAPIName( mapi );
582  }
583 }
584 
585 QDateTime formatTime( quint32 lowB, quint32 highB )
586 {
587  QDateTime dt;
588  quint64 u64;
589  u64 = highB;
590  u64 <<= 32;
591  u64 |= lowB;
592  u64 -= 116444736000000000LL;
593  u64 /= 10000000;
594  if ( u64 <= 0xffffffffU ) {
595  dt.setTime_t( ( unsigned int )u64 );
596  } else {
597  kWarning().nospace() << "Invalid date: low byte="
598  << showbase << qSetFieldWidth( 8 ) << qSetPadChar( '0' )
599  << lowB << ", high byte=" << highB;
600  dt.setTime_t( 0xffffffffU );
601  }
602  return dt;
603 }
604 
605 QString formatRecipient( const QMap<int,KTnef::KTNEFProperty*> &props )
606 {
607  QString s, dn, addr, t;
608  QMap<int,KTnef::KTNEFProperty*>::ConstIterator it;
609  if ( ( it = props.find( 0x3001 ) ) != props.end() ) {
610  dn = ( *it )->valueString();
611  }
612  if ( ( it = props.find( 0x3003 ) ) != props.end() ) {
613  addr = ( *it )->valueString();
614  }
615  if ( ( it = props.find( 0x0C15 ) ) != props.end() ) {
616  switch ( ( *it )->value().toInt() ) {
617  case 0:
618  t = "From:";
619  break;
620  case 1:
621  t = "To:";
622  break;
623  case 2:
624  t = "Cc:";
625  break;
626  case 3:
627  t = "Bcc:";
628  break;
629  }
630  }
631  if ( !t.isEmpty() ) {
632  s.append( t );
633  }
634  if ( !dn.isEmpty() ) {
635  s.append( ' ' + dn );
636  }
637  if ( !addr.isEmpty() && addr != dn ) {
638  s.append( " <" + addr + '>' );
639  }
640 
641  return s.trimmed();
642 }
643 
644 QDateTime readTNEFDate( QDataStream &stream )
645 {
646  // 14-bytes long
647  quint16 y, m, d, hh, mm, ss, dm;
648  stream >> y >> m >> d >> hh >> mm >> ss >> dm;
649  return QDateTime( QDate( y, m, d ), QTime( hh, mm, ss ) );
650 }
651 
652 QString readTNEFAddress( QDataStream &stream )
653 {
654  quint16 totalLen, strLen, addrLen;
655  QString s;
656  stream >> totalLen >> totalLen >> strLen >> addrLen;
657  s.append( readMAPIString( stream, false, false, strLen ) );
658  s.append( " <" );
659  s.append( readMAPIString( stream, false, false, addrLen ) );
660  s.append( ">" );
661  quint8 c;
662  for ( int i=8+strLen+addrLen; i<totalLen; i++ ) {
663  stream >> c;
664  }
665  return s;
666 }
667 
668 QByteArray readTNEFData( QDataStream &stream, quint32 len )
669 {
670  QByteArray array( len, '\0' );
671  if ( len > 0 ) {
672  stream.readRawData( array.data(), len );
673  }
674  return array;
675 }
676 
677 QVariant readTNEFAttribute( QDataStream &stream, quint16 type, quint32 len )
678 {
679  switch ( type ) {
680  case atpTEXT:
681  case atpSTRING:
682  return readMAPIString( stream, false, false, len );
683  case atpDATE:
684  return readTNEFDate( stream );
685  default:
686  return readTNEFData( stream, len );
687  }
688 }
689 
690 QString readMAPIString( QDataStream &stream, bool isUnicode, bool align,
691  int len_ )
692 {
693  quint32 len;
694  char *buf = 0;
695  if ( len_ == -1 ) {
696  stream >> len;
697  } else {
698  len = len_;
699  }
700  quint32 fullLen = len;
701  if ( align ) {
702  ALIGN( fullLen, 4 );
703  }
704  buf = new char[ len ];
705  stream.readRawData( buf, len );
706  quint8 c;
707  for ( uint i=len; i<fullLen; i++ ) {
708  stream >> c;
709  }
710  QString res;
711  if ( isUnicode ) {
712  res = QString::fromUtf16( ( const unsigned short *)buf );
713  } else {
714  res = QString::fromLocal8Bit( buf );
715  }
716  delete [] buf;
717  return res;
718 }
719 
720 quint16 readMAPIValue( QDataStream &stream, MAPI_value &mapi )
721 {
722  quint32 d;
723 
724  clearMAPIValue( mapi );
725  stream >> d;
726  mapi.type = ( d & 0x0000FFFF );
727  mapi.tag = ( ( d & 0xFFFF0000 ) >> 16 );
728  if ( mapi.tag >= 0x8000 && mapi.tag <= 0xFFFE ) {
729  // skip GUID
730  stream >> d >> d >> d >> d;
731  // name type
732  stream >> mapi.name.type;
733  // name
734  if ( mapi.name.type == 0 ) {
735  uint tmp;
736  stream >> tmp;
737  mapi.name.value.setValue( tmp );
738  } else if ( mapi.name.type == 1 ) {
739  mapi.name.value.setValue( readMAPIString( stream, true ) );
740  }
741  }
742 
743  int n = 1;
744  QVariant value;
745  if ( ISVECTOR( mapi ) ) {
746  stream >> n;
747  mapi.value = QList<QVariant>();
748  }
749  for ( int i=0; i<n; i++ ) {
750  value.clear();
751  switch( mapi.type & 0x0FFF ) {
752  case MAPI_TYPE_UINT16:
753  stream >> d;
754  value.setValue( d & 0x0000FFFF );
755  break;
756  case MAPI_TYPE_BOOLEAN:
757  case MAPI_TYPE_ULONG:
758  {
759  uint tmp;
760  stream >> tmp;
761  value.setValue( tmp );
762  }
763  break;
764  case MAPI_TYPE_FLOAT:
765  // FIXME: Don't we have to set the value here
766  stream >> d;
767  break;
768  case MAPI_TYPE_DOUBLE:
769  {
770  double tmp;
771  stream >> tmp;
772  value.setValue( tmp );
773  }
774  break;
775  case MAPI_TYPE_TIME:
776  {
777  quint32 lowB, highB;
778  stream >> lowB >> highB;
779  value = formatTime( lowB, highB );
780  }
781  break;
782  case MAPI_TYPE_USTRING:
783  case MAPI_TYPE_STRING8:
784  // in case of a vector'ed value, the number of elements
785  // has already been read in the upper for-loop
786  if ( ISVECTOR( mapi ) ) {
787  d = 1;
788  } else {
789  stream >> d;
790  }
791  for ( uint i=0; i<d; i++ ) {
792  value.clear();
793  value.setValue( readMAPIString( stream,( mapi.type & 0x0FFF ) == MAPI_TYPE_USTRING ) );
794  }
795  break;
796  case MAPI_TYPE_OBJECT:
797  case MAPI_TYPE_BINARY:
798  if ( ISVECTOR( mapi ) ) {
799  d = 1;
800  } else {
801  stream >> d;
802  }
803  for ( uint i=0; i<d; i++ ) {
804  value.clear();
805  quint32 len;
806  stream >> len;
807  value = QByteArray( len, '\0' );
808  if ( len > 0 ) {
809  int fullLen = len;
810  ALIGN( fullLen, 4 );
811  stream.readRawData( value.toByteArray().data(), len );
812  quint8 c;
813  for ( int i=len; i<fullLen; i++ ) {
814  stream >> c;
815  }
816  // FIXME: Shouldn't we do something with the value???
817  }
818  }
819  break;
820  default:
821  mapi.type = MAPI_TYPE_NONE;
822  break;
823  }
824  if ( ISVECTOR( mapi ) ) {
825  QList <QVariant> lst = mapi.value.toList();
826  lst << value;
827  mapi.value.setValue( lst );
828  } else {
829  mapi.value = value;
830  }
831  }
832  return mapi.tag;
833 }
834 //@endcond
835 
836 bool KTNEFParser::ParserPrivate::readMAPIProperties( QMap<int,KTNEFProperty*> & props,
837  KTNEFAttach *attach )
838 {
839  quint32 n;
840  MAPI_value mapi;
841  KTNEFProperty *p;
842  QMap<int,KTNEFProperty*>::ConstIterator it;
843  bool foundAttachment = false;
844 
845  // some initializations
846  mapi.type = MAPI_TYPE_NONE;
847  mapi.value.clear();
848 
849  // get number of properties
850  stream_ >> n;
851  kDebug() << "MAPI Properties:" << n;
852  for ( uint i=0; i<n; i++ ) {
853  if ( stream_.atEnd() ) {
854  clearMAPIValue( mapi );
855  return false;
856  }
857  readMAPIValue( stream_, mapi );
858  if ( mapi.type == MAPI_TYPE_NONE ) {
859  kDebug().nospace() << "MAPI unsupported: tag="
860  << hex << mapi.tag << ", type=" << mapi.type;
861  clearMAPIValue( mapi );
862  return false;
863  }
864  int key = mapi.tag;
865  switch ( mapi.tag ) {
866  case MAPI_TAG_DATA:
867  {
868  if ( mapi.type == MAPI_TYPE_OBJECT && attach ) {
869  QByteArray data = mapi.value.toByteArray();
870  int len = data.size();
871  ALIGN( len, 4 );
872  device_->seek( device_->pos()-len );
873  quint32 interface_ID;
874  stream_ >> interface_ID;
875  if ( interface_ID == MAPI_IID_IMessage ) {
876  // embedded TNEF file
877  attach->unsetDataParser();
878  attach->setOffset( device_->pos()+12 );
879  attach->setSize( data.size()-16 );
880  attach->setMimeTag( "application/vnd.ms-tnef" );
881  attach->setDisplayName( "Embedded Message" );
882  kDebug() << "MAPI Embedded Message: size=" << data.size();
883  }
884  device_->seek( device_->pos() + ( len-4 ) );
885  break;
886  } else if ( mapi.type == MAPI_TYPE_BINARY && attach && attach->offset() < 0 ) {
887  foundAttachment = true;
888  int len = mapi.value.toByteArray().size();
889  ALIGN( len, 4 );
890  attach->setSize( len );
891  attach->setOffset( device_->pos() - len );
892  attach->addAttribute( attATTACHDATA, atpBYTE, QString( "< size=%1 >" ).arg( len ), false );
893  }
894  }
895  kDebug() << "MAPI data: size=" << mapi.value.toByteArray().size();
896  break;
897  default:
898  {
899  QString mapiname = "";
900  if ( mapi.tag >= 0x8000 && mapi.tag <= 0xFFFE ) {
901  if ( mapi.name.type == 0 ) {
902  mapiname = QString().sprintf( " [name = 0x%04x]", mapi.name.value.toUInt() );
903  } else {
904  mapiname = QString( " [name = %1]" ).arg( mapi.name.value.toString() );
905  }
906  }
907  switch ( mapi.type & 0x0FFF ) {
908  case MAPI_TYPE_UINT16:
909  kDebug().nospace() << "(tag="
910  << hex << mapi.tag
911  << ") MAPI short" << mapiname.toLatin1().data()
912  << ":" << hex << mapi.value.toUInt();
913  break;
914  case MAPI_TYPE_ULONG:
915  kDebug().nospace() << "(tag="
916  << hex << mapi.tag
917  << ") MAPI long" << mapiname.toLatin1().data()
918  << ":" << hex << mapi.value.toUInt();
919  break;
920  case MAPI_TYPE_BOOLEAN:
921  kDebug().nospace() << "(tag="
922  << hex << mapi.tag
923  << ") MAPI boolean" << mapiname.toLatin1().data()
924  << ":" << mapi.value.toBool();
925  break;
926  case MAPI_TYPE_TIME:
927  kDebug().nospace() << "(tag="
928  << hex << mapi.tag
929  << ") MAPI time" << mapiname.toLatin1().data()
930  << ":" << mapi.value.toString().toLatin1().data();
931  break;
932  case MAPI_TYPE_USTRING:
933  case MAPI_TYPE_STRING8:
934  kDebug().nospace() << "(tag="
935  << hex << mapi.tag
936  << ") MAPI string" << mapiname.toLatin1().data()
937  << ":size=" << mapi.value.toByteArray().size()
938  << mapi.value.toString();
939  break;
940  case MAPI_TYPE_BINARY:
941  kDebug().nospace() << "(tag="
942  << hex << mapi.tag
943  << ") MAPI binary" << mapiname.toLatin1().data()
944  << ":size=" << mapi.value.toByteArray().size();
945  break;
946  }
947  }
948  break;
949  }
950  // do not remove potential existing similar entry
951  if ( ( it = props.constFind( key ) ) == props.constEnd() ) {
952  p = new KTNEFProperty( key, ( mapi.type & 0x0FFF ),
953  mapi.value, mapi.name.value );
954  props[ p->key() ] = p;
955  }
956  //kDebug() << "stream:" << device_->pos();
957  }
958 
959  if ( foundAttachment && attach ) {
960  attach->setIndex( attach->property( MAPI_TAG_INDEX ).toUInt() );
961  attach->setDisplaySize( attach->property( MAPI_TAG_SIZE ).toUInt() );
962  QString str = attach->property( MAPI_TAG_DISPLAYNAME ).toString();
963  if ( !str.isEmpty() ) {
964  attach->setDisplayName( str );
965  }
966  attach->setFileName( attach->property( MAPI_TAG_FILENAME ).toString() );
967  str = attach->property( MAPI_TAG_MIMETAG ).toString();
968  if ( !str.isEmpty() ) {
969  attach->setMimeTag( str );
970  }
971  attach->setExtension( attach->property( MAPI_TAG_EXTENSION ).toString() );
972  if ( attach->name().isEmpty() ) {
973  attach->setName( attach->fileName() );
974  }
975  }
976 
977  return true;
978 }
KTnef::KTNEFAttach::setOffset
void setOffset(int offset)
Sets the offset value of this attachment to offset.
Definition: ktnefattach.cpp:116
KTnef::KTNEFPropertySet::property
QVariant property(int key) const
Returns the property associcated with the specified key.
Definition: ktnefpropertyset.cpp:135
KTnef::KTNEFPropertySet::addProperty
void addProperty(int key, int type, const QVariant &value, const QVariant &name=QVariant(), bool overwrite=false)
Adds a MAPI property.
Definition: ktnefpropertyset.cpp:59
KTnef::KTNEFAttach::setDisplaySize
void setDisplaySize(int size)
Sets the display size of the attachment to size.
Definition: ktnefattach.cpp:137
KTnef::KTNEFParser::extractAll
bool extractAll()
Extracts all TNEF attachments into the default directory.
Definition: ktnefparser.cpp:481
KTnef::KTNEFProperty::key
int key() const
Returns the integer key of the property.
Definition: ktnefproperty.cpp:133
KTnef::KTNEFParser::~KTNEFParser
~KTNEFParser()
Destroys the TNEF parser object.
Definition: ktnefparser.cpp:121
KTnef::KTNEFParser::setDefaultExtractDir
void setDefaultExtractDir(const QString &dirname)
Sets the default extraction directory to dirname.
Definition: ktnefparser.cpp:375
KTnef::KTNEFAttach::setExtension
void setExtension(const QString &str)
Sets the filename extension of this attachment to str.
Definition: ktnefattach.cpp:199
ktnefmessage.h
This file is part of the API for handling TNEF data and defines the KTNEFMessage class.
KTnef::KTNEFParser::extractFileTo
bool extractFileTo(const QString &filename, const QString &dirname) const
Extracts a TNEF attachment having filename filename into the directory dirname.
Definition: ktnefparser.cpp:493
KTnef::KTNEFProperty::type
int type() const
Returns the integer type of the property.
Definition: ktnefproperty.cpp:138
KTnef::KTNEFParser::extractFile
bool extractFile(const QString &filename) const
Extracts a TNEF attachment having filename filename into the default directory.
Definition: ktnefparser.cpp:437
KTnef::KTNEFMessage
Represents a TNEF message.
Definition: ktnefmessage.h:49
KTnef::KTNEFPropertySet::addAttribute
void addAttribute(int key, int type, const QVariant &value, bool overwrite=false)
Adds a TNEF attribute.
Definition: ktnefpropertyset.cpp:161
ktnefdefs.h
This file is part of the API for handling TNEF data and provides some basic definitions for general u...
ktnefparser.h
This file is part of the API for handling TNEF data and defines the KTNEFParser class.
KTnef::KTNEFAttach::size
int size() const
Returns the size of the attachment.
Definition: ktnefattach.cpp:122
KTnef::KTNEFAttach::fileName
QString fileName() const
Returns the filename of the attachment.
Definition: ktnefattach.cpp:164
KTnef::KTNEFAttach::setMimeTag
void setMimeTag(const QString &str)
Sets the MIME tag of this attachment to str.
Definition: ktnefattach.cpp:189
KTnef::KTNEFAttach::setFileName
void setFileName(const QString &str)
Sets the filename of this attachment to str.
Definition: ktnefattach.cpp:169
KTnef::KTNEFAttach::unsetDataParser
void unsetDataParser()
Unsets the DataParsed flag for this attachment.
Definition: ktnefattach.cpp:81
KTnef::KTNEFAttach
Represents a TNEF attachment.
Definition: ktnefattach.h:51
KTnef::KTNEFParser::openDevice
bool openDevice(QIODevice *device)
Opens the #QIODevice device for parsing.
Definition: ktnefparser.cpp:515
KTnef::KTNEFParser::openFile
bool openFile(const QString &filename) const
Opens the filename for parsing.
Definition: ktnefparser.cpp:505
KTnef::KTNEFAttach::setName
void setName(const QString &str)
Sets the name of this attachment to str.
Definition: ktnefattach.cpp:147
ktnefproperty.h
This file is part of the API for handling TNEF data and defines the KTNEFProperty class...
KTnef::KTNEFAttach::setSize
void setSize(int size)
Sets the size of the attachment to size.
Definition: ktnefattach.cpp:127
KTnef::KTNEFAttach::offset
int offset() const
Returns the offset value of the attachment.
Definition: ktnefattach.cpp:111
KTnef::KTNEFParser::KTNEFParser
KTNEFParser()
Constructs a TNEF parser object.
Definition: ktnefparser.cpp:116
ktnefattach.h
This file is part of the API for handling TNEF data and defines the KTNEFAttach class.
KTnef::KTNEFAttach::setIndex
void setIndex(int indx)
Sets the index of this attachment to indx.
Definition: ktnefattach.cpp:158
KTnef::KTNEFParser::message
KTNEFMessage * message() const
Returns the KTNEFMessage used in the parsing process.
Definition: ktnefparser.cpp:127
KTnef::KTNEFAttach::name
QString name() const
Returns the name of the attachment.
Definition: ktnefattach.cpp:142
KTnef::KTNEFProperty
Interface for setting MAPI properties.
Definition: ktnefproperty.h:44
KTnef::KTNEFAttach::setDisplayName
void setDisplayName(const QString &str)
Sets the display name of this attachment to str.
Definition: ktnefattach.cpp:179
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Jun 10 2014 09:06:10 by doxygen 1.8.5 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