• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.14.10 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
47using namespace KTnef;
48
49//@cond PRIVATE
50typedef 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
62void clearMAPIName( MAPI_value &mapi );
63void clearMAPIValue( MAPI_value &mapi, bool clearName = true );
64QString readMAPIString( QDataStream &stream, bool isUnicode = false,
65 bool align = true, int len = -1 );
66quint16 readMAPIValue( QDataStream &stream, MAPI_value &mapi );
67QDateTime readTNEFDate( QDataStream &stream );
68QString readTNEFAddress( QDataStream &stream );
69QByteArray readTNEFData( QDataStream &stream, quint32 len );
70QVariant readTNEFAttribute( QDataStream &stream, quint16 type, quint32 len );
71QDateTime formatTime( quint32 lowB, quint32 highB );
72QString formatRecipient( const QMap<int,KTnef::KTNEFProperty*> &props );
73//@endcond
74
75//------------------------------------------------------------------------------
76
81//@cond PRIVATE
82class 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
116KTNEFParser::KTNEFParser()
117 : d( new ParserPrivate )
118{
119}
120
121KTNEFParser::~KTNEFParser()
122{
123 d->deleteDevice();
124 delete d;
125}
126
127KTNEFMessage *KTNEFParser::message() const
128{
129 return d->message_;
130}
131
132void KTNEFParser::ParserPrivate::deleteDevice()
133{
134 if ( deleteDevice_ ) {
135 delete device_;
136 }
137 device_ = 0;
138 deleteDevice_ = false;
139}
140
141bool 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
301bool 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
375void KTNEFParser::setDefaultExtractDir( const QString &dirname )
376{
377 d->defaultdir_ = dirname;
378}
379
380bool 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
437bool 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
446bool 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
490bool 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
502bool 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
514bool 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
524bool KTNEFParser::openDevice( QIODevice *device )
525{
526 d->deleteDevice();
527 d->device_ = device;
528 return d->parseDevice();
529}
530
531void 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
581void clearMAPIName( MAPI_value &mapi )
582{
583 mapi.name.value.clear();
584}
585
586void clearMAPIValue( MAPI_value &mapi, bool clearName )
587{
588 mapi.value.clear();
589 if ( clearName ) {
590 clearMAPIName( mapi );
591 }
592}
593
594QDateTime 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
614QString 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
653QDateTime 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
661QString 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
677QByteArray 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
686QVariant 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
699QString 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::fromLatin1( buf );
724 }
725 delete [] buf;
726 return res;
727}
728
729quint16 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
845bool 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
Represents a TNEF attachment.
Definition: ktnefattach.h:52
KTnef::KTNEFAttach::setFileName
void setFileName(const QString &str)
Sets the filename of this attachment to str.
Definition: ktnefattach.cpp:169
KTnef::KTNEFAttach::size
int size() const
Returns the size of the attachment.
Definition: ktnefattach.cpp:122
KTnef::KTNEFAttach::setSize
void setSize(int size)
Sets the size of the attachment to size.
Definition: ktnefattach.cpp:127
KTnef::KTNEFAttach::setExtension
void setExtension(const QString &str)
Sets the filename extension of this attachment to str.
Definition: ktnefattach.cpp:199
KTnef::KTNEFAttach::setIndex
void setIndex(int indx)
Sets the index of this attachment to indx.
Definition: ktnefattach.cpp:158
KTnef::KTNEFAttach::setOffset
void setOffset(int offset)
Sets the offset value of this attachment to offset.
Definition: ktnefattach.cpp:116
KTnef::KTNEFAttach::setMimeTag
void setMimeTag(const QString &str)
Sets the MIME tag of this attachment to str.
Definition: ktnefattach.cpp:189
KTnef::KTNEFAttach::name
QString name() const
Returns the name of the attachment.
Definition: ktnefattach.cpp:142
KTnef::KTNEFAttach::unsetDataParser
void unsetDataParser()
Unsets the DataParsed flag for this attachment.
Definition: ktnefattach.cpp:81
KTnef::KTNEFAttach::fileName
QString fileName() const
Returns the filename of the attachment.
Definition: ktnefattach.cpp:164
KTnef::KTNEFAttach::setName
void setName(const QString &str)
Sets the name of this attachment to str.
Definition: ktnefattach.cpp:147
KTnef::KTNEFAttach::offset
int offset() const
Returns the offset value of the attachment.
Definition: ktnefattach.cpp:111
KTnef::KTNEFAttach::setDisplaySize
void setDisplaySize(int size)
Sets the display size of the attachment to size.
Definition: ktnefattach.cpp:137
KTnef::KTNEFAttach::setDisplayName
void setDisplayName(const QString &str)
Sets the display name of this attachment to str.
Definition: ktnefattach.cpp:179
KTnef::KTNEFMessage
Represents a TNEF message.
Definition: ktnefmessage.h:50
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::KTNEFParser::openFile
bool openFile(const QString &filename) const
Opens the filename for parsing.
Definition: ktnefparser.cpp:514
KTnef::KTNEFParser::KTNEFParser
KTNEFParser()
Constructs a TNEF parser object.
Definition: ktnefparser.cpp:116
KTnef::KTNEFParser::setDefaultExtractDir
void setDefaultExtractDir(const QString &dirname)
Sets the default extraction directory to dirname.
Definition: ktnefparser.cpp:375
KTnef::KTNEFParser::extractAll
bool extractAll()
Extracts all TNEF attachments into the default directory.
Definition: ktnefparser.cpp:490
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::KTNEFParser::openDevice
bool openDevice(QIODevice *device)
Opens the #QIODevice device for parsing.
Definition: ktnefparser.cpp:524
KTnef::KTNEFParser::~KTNEFParser
~KTNEFParser()
Destroys the TNEF parser object.
Definition: ktnefparser.cpp:121
KTnef::KTNEFParser::message
KTNEFMessage * message() const
Returns the KTNEFMessage used in the parsing process.
Definition: ktnefparser.cpp:127
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::KTNEFPropertySet::addAttribute
void addAttribute(int key, int type, const QVariant &value, bool overwrite=false)
Adds a TNEF attribute.
Definition: ktnefpropertyset.cpp:161
KTnef::KTNEFProperty
Interface for setting MAPI properties.
Definition: ktnefproperty.h:45
KTnef::KTNEFProperty::type
int type() const
Returns the integer type of the property.
Definition: ktnefproperty.cpp:138
KTnef::KTNEFProperty::key
int key() const
Returns the integer key of the property.
Definition: ktnefproperty.cpp:133
ktnefattach.h
This file is part of the API for handling TNEF data and defines the KTNEFAttach class.
ktnefdefs.h
This file is part of the API for handling TNEF data and provides some basic definitions for general u...
ktnefmessage.h
This file is part of the API for handling TNEF data and defines the KTNEFMessage class.
ktnefparser.h
This file is part of the API for handling TNEF data and defines the KTNEFParser class.
ktnefproperty.h
This file is part of the API for handling TNEF data and defines the KTNEFProperty class.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Thu Jul 21 2022 00:00:00 by doxygen 1.9.5 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-4.14.10 API Reference

Skip menu "kdepimlibs-4.14.10 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