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

KTNEF Library

  • sources
  • kde-4.12
  • kdepimlibs
  • 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 + '/';
450  if ( !att->fileName().isEmpty()) {
451  filename += att->fileName();
452  } else {
453  filename += att->name();
454  }
455  if ( filename.endsWith( '/') ) {
456  return false;
457  }
458 
459  if ( !device_->isOpen() ) {
460  return false;
461  }
462  if ( !device_->seek( att->offset() ) ) {
463  return false;
464  }
465  KSaveFile outfile( filename );
466  if ( !outfile.open() ) {
467  return false;
468  }
469 
470  quint32 len = att->size(), sz( 16384 );
471  int n( 0 );
472  char *buf = new char[sz];
473  bool ok( true );
474  while ( ok && len > 0 ) {
475  n = device_->read( buf, qMin( sz, len ) );
476  if ( n < 0 ) {
477  ok = false;
478  } else {
479  len -= n;
480  if ( outfile.write( buf, n ) != n ) {
481  ok = false;
482  }
483  }
484  }
485  delete [] buf;
486 
487  return ok;
488 }
489 
490 bool KTNEFParser::extractAll()
491 {
492  QList<KTNEFAttach*> l = d->message_->attachmentList();
493  QList<KTNEFAttach*>::const_iterator it = l.constBegin();
494  for ( ; it != l.constEnd(); ++it ) {
495  if ( !d->extractAttachmentTo( *it, d->defaultdir_ ) ) {
496  return false;
497  }
498  }
499  return true;
500 }
501 
502 bool KTNEFParser::extractFileTo( const QString &filename,
503  const QString &dirname ) const
504 {
505  kDebug() << "Extracting attachment: filename="
506  << filename << ", dir=" << dirname;
507  KTNEFAttach *att = d->message_->attachment( filename );
508  if ( !att ) {
509  return false;
510  }
511  return d->extractAttachmentTo( att, dirname );
512 }
513 
514 bool KTNEFParser::openFile( const QString &filename ) const
515 {
516  d->deleteDevice();
517  delete d->message_;
518  d->message_ = new KTNEFMessage();
519  d->device_ = new QFile( filename );
520  d->deleteDevice_ = true;
521  return d->parseDevice();
522 }
523 
524 bool KTNEFParser::openDevice( QIODevice *device )
525 {
526  d->deleteDevice();
527  d->device_ = device;
528  return d->parseDevice();
529 }
530 
531 void KTNEFParser::ParserPrivate::checkCurrent( int key )
532 {
533  if ( !current_ ) {
534  current_ = new KTNEFAttach();
535  } else {
536  if ( current_->attributes().contains( key ) ) {
537  if ( current_->offset() >= 0 ) {
538  if ( current_->name().isEmpty() ) {
539  current_->setName( "Unnamed" );
540  }
541  if ( current_->mimeTag().isEmpty() ) {
542  // No mime type defined in the TNEF structure,
543  // try to find it from the attachment filename
544  // and/or content (using at most 32 bytes)
545  KMimeType::Ptr mimetype;
546  if ( !current_->fileName().isEmpty() ) {
547  mimetype = KMimeType::findByPath( current_->fileName(), 0, true );
548  }
549  if ( !mimetype ) {
550  return; // FIXME
551  }
552  if ( mimetype->name() == "application/octet-stream" &&
553  current_->size() > 0 ) {
554  int oldOffset = device_->pos();
555  QByteArray buffer( qMin( 32, current_->size() ), '\0' );
556  device_->seek( current_->offset() );
557  device_->read( buffer.data(), buffer.size() );
558  mimetype = KMimeType::findByContent( buffer );
559  device_->seek( oldOffset );
560  }
561  current_->setMimeTag( mimetype->name() );
562  }
563  message_->addAttachment( current_ );
564  current_ = 0;
565  } else {
566  // invalid attachment, skip it
567  delete current_;
568  current_ = 0;
569  }
570  current_ = new KTNEFAttach();
571  }
572  }
573 }
574 
575 //------------------------------------------------------------------------------
576 
577 //@cond IGNORE
578 #define ALIGN( n, b ) if ( n & ( b-1 ) ) { n = ( n + b ) & ~( b-1 ); }
579 #define ISVECTOR( m ) ( ( ( m ).type & 0xF000 ) == MAPI_TYPE_VECTOR )
580 
581 void clearMAPIName( MAPI_value &mapi )
582 {
583  mapi.name.value.clear();
584 }
585 
586 void clearMAPIValue( MAPI_value &mapi, bool clearName )
587 {
588  mapi.value.clear();
589  if ( clearName ) {
590  clearMAPIName( mapi );
591  }
592 }
593 
594 QDateTime formatTime( quint32 lowB, quint32 highB )
595 {
596  QDateTime dt;
597  quint64 u64;
598  u64 = highB;
599  u64 <<= 32;
600  u64 |= lowB;
601  u64 -= 116444736000000000LL;
602  u64 /= 10000000;
603  if ( u64 <= 0xffffffffU ) {
604  dt.setTime_t( ( unsigned int )u64 );
605  } else {
606  kWarning().nospace() << "Invalid date: low byte="
607  << showbase << qSetFieldWidth( 8 ) << qSetPadChar( '0' )
608  << lowB << ", high byte=" << highB;
609  dt.setTime_t( 0xffffffffU );
610  }
611  return dt;
612 }
613 
614 QString formatRecipient( const QMap<int,KTnef::KTNEFProperty*> &props )
615 {
616  QString s, dn, addr, t;
617  QMap<int,KTnef::KTNEFProperty*>::ConstIterator it;
618  if ( ( it = props.find( 0x3001 ) ) != props.end() ) {
619  dn = ( *it )->valueString();
620  }
621  if ( ( it = props.find( 0x3003 ) ) != props.end() ) {
622  addr = ( *it )->valueString();
623  }
624  if ( ( it = props.find( 0x0C15 ) ) != props.end() ) {
625  switch ( ( *it )->value().toInt() ) {
626  case 0:
627  t = "From:";
628  break;
629  case 1:
630  t = "To:";
631  break;
632  case 2:
633  t = "Cc:";
634  break;
635  case 3:
636  t = "Bcc:";
637  break;
638  }
639  }
640  if ( !t.isEmpty() ) {
641  s.append( t );
642  }
643  if ( !dn.isEmpty() ) {
644  s.append( ' ' + dn );
645  }
646  if ( !addr.isEmpty() && addr != dn ) {
647  s.append( " <" + addr + '>' );
648  }
649 
650  return s.trimmed();
651 }
652 
653 QDateTime readTNEFDate( QDataStream &stream )
654 {
655  // 14-bytes long
656  quint16 y, m, d, hh, mm, ss, dm;
657  stream >> y >> m >> d >> hh >> mm >> ss >> dm;
658  return QDateTime( QDate( y, m, d ), QTime( hh, mm, ss ) );
659 }
660 
661 QString readTNEFAddress( QDataStream &stream )
662 {
663  quint16 totalLen, strLen, addrLen;
664  QString s;
665  stream >> totalLen >> totalLen >> strLen >> addrLen;
666  s.append( readMAPIString( stream, false, false, strLen ) );
667  s.append( " <" );
668  s.append( readMAPIString( stream, false, false, addrLen ) );
669  s.append( ">" );
670  quint8 c;
671  for ( int i=8+strLen+addrLen; i<totalLen; i++ ) {
672  stream >> c;
673  }
674  return s;
675 }
676 
677 QByteArray readTNEFData( QDataStream &stream, quint32 len )
678 {
679  QByteArray array( len, '\0' );
680  if ( len > 0 ) {
681  stream.readRawData( array.data(), len );
682  }
683  return array;
684 }
685 
686 QVariant readTNEFAttribute( QDataStream &stream, quint16 type, quint32 len )
687 {
688  switch ( type ) {
689  case atpTEXT:
690  case atpSTRING:
691  return readMAPIString( stream, false, false, len );
692  case atpDATE:
693  return readTNEFDate( stream );
694  default:
695  return readTNEFData( stream, len );
696  }
697 }
698 
699 QString readMAPIString( QDataStream &stream, bool isUnicode, bool align,
700  int len_ )
701 {
702  quint32 len;
703  char *buf = 0;
704  if ( len_ == -1 ) {
705  stream >> len;
706  } else {
707  len = len_;
708  }
709  quint32 fullLen = len;
710  if ( align ) {
711  ALIGN( fullLen, 4 );
712  }
713  buf = new char[ len ];
714  stream.readRawData( buf, len );
715  quint8 c;
716  for ( uint i=len; i<fullLen; i++ ) {
717  stream >> c;
718  }
719  QString res;
720  if ( isUnicode ) {
721  res = QString::fromUtf16( ( const unsigned short *)buf );
722  } else {
723  res = QString::fromLocal8Bit( buf );
724  }
725  delete [] buf;
726  return res;
727 }
728 
729 quint16 readMAPIValue( QDataStream &stream, MAPI_value &mapi )
730 {
731  quint32 d;
732 
733  clearMAPIValue( mapi );
734  stream >> d;
735  mapi.type = ( d & 0x0000FFFF );
736  mapi.tag = ( ( d & 0xFFFF0000 ) >> 16 );
737  if ( mapi.tag >= 0x8000 && mapi.tag <= 0xFFFE ) {
738  // skip GUID
739  stream >> d >> d >> d >> d;
740  // name type
741  stream >> mapi.name.type;
742  // name
743  if ( mapi.name.type == 0 ) {
744  uint tmp;
745  stream >> tmp;
746  mapi.name.value.setValue( tmp );
747  } else if ( mapi.name.type == 1 ) {
748  mapi.name.value.setValue( readMAPIString( stream, true ) );
749  }
750  }
751 
752  int n = 1;
753  QVariant value;
754  if ( ISVECTOR( mapi ) ) {
755  stream >> n;
756  mapi.value = QList<QVariant>();
757  }
758  for ( int i=0; i<n; i++ ) {
759  value.clear();
760  switch( mapi.type & 0x0FFF ) {
761  case MAPI_TYPE_UINT16:
762  stream >> d;
763  value.setValue( d & 0x0000FFFF );
764  break;
765  case MAPI_TYPE_BOOLEAN:
766  case MAPI_TYPE_ULONG:
767  {
768  uint tmp;
769  stream >> tmp;
770  value.setValue( tmp );
771  }
772  break;
773  case MAPI_TYPE_FLOAT:
774  // FIXME: Don't we have to set the value here
775  stream >> d;
776  break;
777  case MAPI_TYPE_DOUBLE:
778  {
779  double tmp;
780  stream >> tmp;
781  value.setValue( tmp );
782  }
783  break;
784  case MAPI_TYPE_TIME:
785  {
786  quint32 lowB, highB;
787  stream >> lowB >> highB;
788  value = formatTime( lowB, highB );
789  }
790  break;
791  case MAPI_TYPE_USTRING:
792  case MAPI_TYPE_STRING8:
793  // in case of a vector'ed value, the number of elements
794  // has already been read in the upper for-loop
795  if ( ISVECTOR( mapi ) ) {
796  d = 1;
797  } else {
798  stream >> d;
799  }
800  for ( uint i=0; i<d; i++ ) {
801  value.clear();
802  value.setValue( readMAPIString( stream,( mapi.type & 0x0FFF ) == MAPI_TYPE_USTRING ) );
803  }
804  break;
805  case MAPI_TYPE_OBJECT:
806  case MAPI_TYPE_BINARY:
807  if ( ISVECTOR( mapi ) ) {
808  d = 1;
809  } else {
810  stream >> d;
811  }
812  for ( uint i=0; i<d; i++ ) {
813  value.clear();
814  quint32 len;
815  stream >> len;
816  value = QByteArray( len, '\0' );
817  if ( len > 0 ) {
818  int fullLen = len;
819  ALIGN( fullLen, 4 );
820  stream.readRawData( value.toByteArray().data(), len );
821  quint8 c;
822  for ( int i=len; i<fullLen; i++ ) {
823  stream >> c;
824  }
825  // FIXME: Shouldn't we do something with the value???
826  }
827  }
828  break;
829  default:
830  mapi.type = MAPI_TYPE_NONE;
831  break;
832  }
833  if ( ISVECTOR( mapi ) ) {
834  QList <QVariant> lst = mapi.value.toList();
835  lst << value;
836  mapi.value.setValue( lst );
837  } else {
838  mapi.value = value;
839  }
840  }
841  return mapi.tag;
842 }
843 //@endcond
844 
845 bool KTNEFParser::ParserPrivate::readMAPIProperties( QMap<int,KTNEFProperty*> & props,
846  KTNEFAttach *attach )
847 {
848  quint32 n;
849  MAPI_value mapi;
850  KTNEFProperty *p;
851  QMap<int,KTNEFProperty*>::ConstIterator it;
852  bool foundAttachment = false;
853 
854  // some initializations
855  mapi.type = MAPI_TYPE_NONE;
856  mapi.value.clear();
857 
858  // get number of properties
859  stream_ >> n;
860  kDebug() << "MAPI Properties:" << n;
861  for ( uint i=0; i<n; i++ ) {
862  if ( stream_.atEnd() ) {
863  clearMAPIValue( mapi );
864  return false;
865  }
866  readMAPIValue( stream_, mapi );
867  if ( mapi.type == MAPI_TYPE_NONE ) {
868  kDebug().nospace() << "MAPI unsupported: tag="
869  << hex << mapi.tag << ", type=" << mapi.type;
870  clearMAPIValue( mapi );
871  return false;
872  }
873  int key = mapi.tag;
874  switch ( mapi.tag ) {
875  case MAPI_TAG_DATA:
876  {
877  if ( mapi.type == MAPI_TYPE_OBJECT && attach ) {
878  QByteArray data = mapi.value.toByteArray();
879  int len = data.size();
880  ALIGN( len, 4 );
881  device_->seek( device_->pos()-len );
882  quint32 interface_ID;
883  stream_ >> interface_ID;
884  if ( interface_ID == MAPI_IID_IMessage ) {
885  // embedded TNEF file
886  attach->unsetDataParser();
887  attach->setOffset( device_->pos()+12 );
888  attach->setSize( data.size()-16 );
889  attach->setMimeTag( "application/vnd.ms-tnef" );
890  attach->setDisplayName( "Embedded Message" );
891  kDebug() << "MAPI Embedded Message: size=" << data.size();
892  }
893  device_->seek( device_->pos() + ( len-4 ) );
894  break;
895  } else if ( mapi.type == MAPI_TYPE_BINARY && attach && attach->offset() < 0 ) {
896  foundAttachment = true;
897  int len = mapi.value.toByteArray().size();
898  ALIGN( len, 4 );
899  attach->setSize( len );
900  attach->setOffset( device_->pos() - len );
901  attach->addAttribute( attATTACHDATA, atpBYTE, QString( "< size=%1 >" ).arg( len ), false );
902  }
903  }
904  kDebug() << "MAPI data: size=" << mapi.value.toByteArray().size();
905  break;
906  default:
907  {
908  QString mapiname = "";
909  if ( mapi.tag >= 0x8000 && mapi.tag <= 0xFFFE ) {
910  if ( mapi.name.type == 0 ) {
911  mapiname = QString().sprintf( " [name = 0x%04x]", mapi.name.value.toUInt() );
912  } else {
913  mapiname = QString( " [name = %1]" ).arg( mapi.name.value.toString() );
914  }
915  }
916  switch ( mapi.type & 0x0FFF ) {
917  case MAPI_TYPE_UINT16:
918  kDebug().nospace() << "(tag="
919  << hex << mapi.tag
920  << ") MAPI short" << mapiname.toLatin1().data()
921  << ":" << hex << mapi.value.toUInt();
922  break;
923  case MAPI_TYPE_ULONG:
924  kDebug().nospace() << "(tag="
925  << hex << mapi.tag
926  << ") MAPI long" << mapiname.toLatin1().data()
927  << ":" << hex << mapi.value.toUInt();
928  break;
929  case MAPI_TYPE_BOOLEAN:
930  kDebug().nospace() << "(tag="
931  << hex << mapi.tag
932  << ") MAPI boolean" << mapiname.toLatin1().data()
933  << ":" << mapi.value.toBool();
934  break;
935  case MAPI_TYPE_TIME:
936  kDebug().nospace() << "(tag="
937  << hex << mapi.tag
938  << ") MAPI time" << mapiname.toLatin1().data()
939  << ":" << mapi.value.toString().toLatin1().data();
940  break;
941  case MAPI_TYPE_USTRING:
942  case MAPI_TYPE_STRING8:
943  kDebug().nospace() << "(tag="
944  << hex << mapi.tag
945  << ") MAPI string" << mapiname.toLatin1().data()
946  << ":size=" << mapi.value.toByteArray().size()
947  << mapi.value.toString();
948  break;
949  case MAPI_TYPE_BINARY:
950  kDebug().nospace() << "(tag="
951  << hex << mapi.tag
952  << ") MAPI binary" << mapiname.toLatin1().data()
953  << ":size=" << mapi.value.toByteArray().size();
954  break;
955  }
956  }
957  break;
958  }
959  // do not remove potential existing similar entry
960  if ( ( it = props.constFind( key ) ) == props.constEnd() ) {
961  p = new KTNEFProperty( key, ( mapi.type & 0x0FFF ),
962  mapi.value, mapi.name.value );
963  props[ p->key() ] = p;
964  }
965  //kDebug() << "stream:" << device_->pos();
966  }
967 
968  if ( foundAttachment && attach ) {
969  attach->setIndex( attach->property( MAPI_TAG_INDEX ).toUInt() );
970  attach->setDisplaySize( attach->property( MAPI_TAG_SIZE ).toUInt() );
971  QString str = attach->property( MAPI_TAG_DISPLAYNAME ).toString();
972  if ( !str.isEmpty() ) {
973  attach->setDisplayName( str );
974  }
975  attach->setFileName( attach->property( MAPI_TAG_FILENAME ).toString() );
976  str = attach->property( MAPI_TAG_MIMETAG ).toString();
977  if ( !str.isEmpty() ) {
978  attach->setMimeTag( str );
979  }
980  attach->setExtension( attach->property( MAPI_TAG_EXTENSION ).toString() );
981  if ( attach->name().isEmpty() ) {
982  attach->setName( attach->fileName() );
983  }
984  }
985 
986  return true;
987 }
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:490
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:502
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:524
KTnef::KTNEFParser::openFile
bool openFile(const QString &filename) const
Opens the filename for parsing.
Definition: ktnefparser.cpp:514
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 Oct 14 2014 23:01:10 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KTNEF Library

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

kdepimlibs API Reference

Skip menu "kdepimlibs API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kldap
  • kmbox
  • kmime
  • kpimidentities
  • kpimtextedit
  • kresources
  • ktnef
  • kxmlrpcclient
  • microblog

Search



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