00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00031 #include "ktnefparser.h"
00032 #include "ktnefattach.h"
00033 #include "ktnefproperty.h"
00034 #include "ktnefmessage.h"
00035 #include "ktnefdefs.h"
00036
00037 #include <kdebug.h>
00038 #include <kmimetype.h>
00039 #include <ksavefile.h>
00040
00041 #include <QtCore/QDateTime>
00042 #include <QtCore/QDataStream>
00043 #include <QtCore/QFile>
00044 #include <QtCore/QVariant>
00045 #include <QtCore/QList>
00046
00047 using namespace KTnef;
00048
00049
00050 typedef struct {
00051 quint16 type;
00052 quint16 tag;
00053 QVariant value;
00054 struct {
00055 quint32 type;
00056 QVariant value;
00057 } name;
00058 } MAPI_value;
00059
00060
00061
00062 void clearMAPIName( MAPI_value &mapi );
00063 void clearMAPIValue( MAPI_value &mapi, bool clearName = true );
00064 QString readMAPIString( QDataStream &stream, bool isUnicode = false,
00065 bool align = true, int len = -1 );
00066 quint16 readMAPIValue( QDataStream &stream, MAPI_value &mapi );
00067 QDateTime readTNEFDate( QDataStream &stream );
00068 QString readTNEFAddress( QDataStream &stream );
00069 QByteArray readTNEFData( QDataStream &stream, quint32 len );
00070 QVariant readTNEFAttribute( QDataStream &stream, quint16 type, quint32 len );
00071 QDateTime formatTime( quint32 lowB, quint32 highB );
00072 QString formatRecipient( const QMap<int,KTnef::KTNEFProperty*> &props );
00073
00074
00075
00076
00081
00082 class KTnef::KTNEFParser::ParserPrivate
00083 {
00084 public:
00085 ParserPrivate()
00086 {
00087 defaultdir_ = "/tmp/";
00088 current_ = 0;
00089 deleteDevice_ = false;
00090 device_ = 0;
00091 message_ = new KTNEFMessage;
00092 }
00093 ~ParserPrivate()
00094 {
00095 delete message_;
00096 }
00097
00098 bool decodeAttachment();
00099 bool decodeMessage();
00100 bool extractAttachmentTo( KTNEFAttach *att, const QString &dirname );
00101 void checkCurrent( int key );
00102 bool readMAPIProperties( QMap<int,KTNEFProperty*>& props,
00103 KTNEFAttach *attach = 0 );
00104 bool parseDevice();
00105 void deleteDevice();
00106
00107 QDataStream stream_;
00108 QIODevice *device_;
00109 bool deleteDevice_;
00110 QString defaultdir_;
00111 KTNEFAttach *current_;
00112 KTNEFMessage *message_;
00113 };
00114
00115
00116 KTNEFParser::KTNEFParser()
00117 : d( new ParserPrivate )
00118 {
00119 }
00120
00121 KTNEFParser::~KTNEFParser()
00122 {
00123 d->deleteDevice();
00124 delete d;
00125 }
00126
00127 KTNEFMessage *KTNEFParser::message() const
00128 {
00129 return d->message_;
00130 }
00131
00132 void KTNEFParser::ParserPrivate::deleteDevice()
00133 {
00134 if ( deleteDevice_ ) {
00135 delete device_;
00136 }
00137 device_ = 0;
00138 deleteDevice_ = false;
00139 }
00140
00141 bool KTNEFParser::ParserPrivate::decodeMessage()
00142 {
00143 quint32 i1, i2, off;
00144 quint16 u, tag, type;
00145 QVariant value;
00146
00147
00148 stream_ >> i1;
00149 u = 0;
00150 tag = ( i1 & 0x0000FFFF );
00151 type = ( ( i1 & 0xFFFF0000 ) >> 16 );
00152
00153 stream_ >> i2;
00154
00155 off = device_->pos() + i2;
00156 switch ( tag ) {
00157 case attAIDOWNER:
00158 {
00159 uint tmp;
00160 stream_ >> tmp;
00161 value.setValue( tmp );
00162 message_->addProperty( 0x0062, MAPI_TYPE_ULONG, value );
00163 kDebug(5975) << "Message Owner Appointment ID"
00164 << "(length=" << i2 << ")";
00165 break;
00166 }
00167 case attREQUESTRES:
00168 stream_ >> u;
00169 message_->addProperty( 0x0063, MAPI_TYPE_UINT16, u );
00170 value = ( bool )u;
00171 kDebug(5975) << "Message Request Response" << "(length=" << i2 << ")";
00172 break;
00173 case attDATERECD:
00174 value = readTNEFDate( stream_ );
00175 message_->addProperty( 0x0E06, MAPI_TYPE_TIME, value );
00176 kDebug(5975) << "Message Receive Date" << "(length=" << i2 << ")";
00177 break;
00178 case attMSGCLASS:
00179 value = readMAPIString( stream_, false, false, i2 );
00180 message_->addProperty( 0x001A, MAPI_TYPE_STRING8, value );
00181 kDebug(5975) << "Message Class" << "(length=" << i2 << ")";
00182 break;
00183 case attMSGPRIORITY:
00184 stream_ >> u;
00185 message_->addProperty( 0x0026, MAPI_TYPE_ULONG, 2-u );
00186 value = u;
00187 kDebug(5975) << "Message Priority" << "(length=" << i2 << ")";
00188 break;
00189 case attMAPIPROPS:
00190 kDebug(5975) << "Message MAPI Properties" << "(length=" << i2 << ")";
00191 {
00192 int nProps = message_->properties().count();
00193 i2 += device_->pos();
00194 readMAPIProperties( message_->properties(), 0 );
00195 device_->seek( i2 );
00196 kDebug(5975) << "Properties:" << message_->properties().count();
00197 value = QString( "< %1 properties >" ).
00198 arg( message_->properties().count() - nProps );
00199 }
00200 break;
00201 case attTNEFVERSION:
00202 {
00203 uint tmp;
00204 stream_ >> tmp;
00205 value.setValue( tmp );
00206 kDebug(5975) << "Message TNEF Version" << "(length=" << i2 << ")";
00207 }
00208 break;
00209 case attFROM:
00210 message_->addProperty( 0x0024, MAPI_TYPE_STRING8,
00211 readTNEFAddress( stream_ ) );
00212 device_->seek( device_->pos() - i2 );
00213 value = readTNEFData( stream_, i2 );
00214 kDebug(5975) << "Message From" << "(length=" << i2 << ")";
00215 break;
00216 case attSUBJECT:
00217 value = readMAPIString( stream_, false, false, i2 );
00218 message_->addProperty( 0x0037, MAPI_TYPE_STRING8, value );
00219 kDebug(5975) << "Message Subject" << "(length=" << i2 << ")";
00220 break;
00221 case attDATESENT:
00222 value = readTNEFDate( stream_ );
00223 message_->addProperty( 0x0039, MAPI_TYPE_TIME, value );
00224 kDebug(5975) << "Message Date Sent" << "(length=" << i2 << ")";
00225 break;
00226 case attMSGSTATUS:
00227 {
00228 quint8 c;
00229 quint32 flag = 0;
00230 stream_ >> c;
00231 if ( c & fmsRead ) flag |= MSGFLAG_READ;
00232 if ( !( c & fmsModified ) ) flag |= MSGFLAG_UNMODIFIED;
00233 if ( c & fmsSubmitted ) flag |= MSGFLAG_SUBMIT;
00234 if ( c & fmsHasAttach ) flag |= MSGFLAG_HASATTACH;
00235 if ( c & fmsLocal ) flag |= MSGFLAG_UNSENT;
00236 message_->addProperty( 0x0E07, MAPI_TYPE_ULONG, flag );
00237 value = c;
00238 }
00239 kDebug(5975) << "Message Status" << "(length=" << i2 << ")";
00240 break;
00241 case attRECIPTABLE:
00242 {
00243 quint32 rows;
00244 QList<QVariant> recipTable;
00245 stream_ >> rows;
00246 for ( uint i=0; i<rows; i++ ) {
00247 QMap<int,KTNEFProperty*> props;
00248 readMAPIProperties( props, 0 );
00249 recipTable << formatRecipient( props );
00250 }
00251 message_->addProperty( 0x0E12, MAPI_TYPE_STRING8, recipTable );
00252 device_->seek( device_->pos() - i2 );
00253 value = readTNEFData( stream_, i2 );
00254 }
00255 kDebug(5975) << "Message Recipient Table" << "(length=" << i2 << ")";
00256 break;
00257 case attBODY:
00258 value = readMAPIString( stream_, false, false, i2 );
00259 message_->addProperty( 0x1000, MAPI_TYPE_STRING8, value );
00260 kDebug(5975) << "Message Body" << "(length=" << i2 << ")";
00261 break;
00262 case attDATEMODIFIED:
00263 value = readTNEFDate( stream_ );
00264 message_->addProperty( 0x3008, MAPI_TYPE_TIME, value );
00265 kDebug(5975) << "Message Date Modified" << "(length=" << i2 << ")";
00266 break;
00267 case attMSGID:
00268 value = readMAPIString( stream_, false, false, i2 );
00269 message_->addProperty( 0x300B, MAPI_TYPE_STRING8, value );
00270 kDebug(5975) << "Message ID" << "(length=" << i2 << ")";
00271 break;
00272 case attOEMCODEPAGE:
00273 value = readTNEFData( stream_, i2 );
00274 kDebug(5975) << "Message OEM Code Page" << "(length=" << i2 << ")";
00275 break;
00276 default:
00277 value = readTNEFAttribute( stream_, type, i2 );
00278
00279 break;
00280 }
00281
00282 if ( device_->pos() != off && !device_->seek( off ) ) {
00283 return false;
00284 }
00285
00286 stream_ >> u;
00287
00288 message_->addAttribute( tag, type, value, true );
00289
00290 return true;
00291 }
00292
00293 bool KTNEFParser::ParserPrivate::decodeAttachment()
00294 {
00295 quint32 i;
00296 quint16 tag, type, u;
00297 QVariant value;
00298 QString str;
00299
00300 stream_ >> i;
00301 tag = ( i & 0x0000FFFF );
00302 type = ( ( i & 0xFFFF0000 ) >> 16 );
00303 stream_ >> i;
00304 checkCurrent( tag );
00305 switch ( tag ) {
00306 case attATTACHTITLE:
00307 value = readMAPIString( stream_, false, false, i );
00308 current_->setName( value.toString() );
00309 kDebug(5975) << "Attachment Title:" << current_->name();
00310 break;
00311 case attATTACHDATA:
00312 current_->setSize( i );
00313 current_->setOffset( device_->pos() );
00314 device_->seek( device_->pos() + i );
00315 value = QString( "< size=%1 >" ).arg( i );
00316 kDebug(5975) << "Attachment Data: size=" << i;
00317 break;
00318 case attATTACHMENT:
00319 i += device_->pos();
00320 readMAPIProperties( current_->properties(), current_ );
00321 device_->seek( i );
00322 current_->setIndex( current_->property( MAPI_TAG_INDEX ).toUInt() );
00323 current_->setDisplaySize( current_->property( MAPI_TAG_SIZE ).toUInt() );
00324 str = current_->property( MAPI_TAG_DISPLAYNAME ).toString();
00325 if ( !str.isEmpty() ) {
00326 current_->setDisplayName( str );
00327 }
00328 current_->setFileName( current_->property( MAPI_TAG_FILENAME ).
00329 toString() );
00330 str = current_->property( MAPI_TAG_MIMETAG ).toString();
00331 if ( !str.isEmpty() ) {
00332 current_->setMimeTag( str );
00333 }
00334 current_->setExtension( current_->property( MAPI_TAG_EXTENSION ).
00335 toString() );
00336 value = QString( "< %1 properties >" ).
00337 arg( current_->properties().count() );
00338 break;
00339 case attATTACHMODDATE:
00340 value = readTNEFDate( stream_ );
00341 kDebug(5975) << "Attachment Modification Date:" << value.toString();
00342 break;
00343 case attATTACHCREATEDATE:
00344 value = readTNEFDate( stream_ );
00345 kDebug(5975) << "Attachment Creation Date:" << value.toString();
00346 break;
00347 case attATTACHMETAFILE:
00348 kDebug(5975) << "Attachment Metafile: size=" << i;
00349
00350
00351 value = readTNEFData( stream_, i );
00352 break;
00353 default:
00354 value = readTNEFAttribute( stream_, type, i );
00355 kDebug(5975) << "Attachment unknown field: tag="
00356 << hex << tag << ", length=" << dec << i;
00357 break;
00358 }
00359 stream_ >> u;
00360
00361 current_->addAttribute( tag, type, value, true );
00362
00363
00364 return true;
00365 }
00366
00367 void KTNEFParser::setDefaultExtractDir( const QString &dirname )
00368 {
00369 d->defaultdir_ = dirname;
00370 }
00371
00372 bool KTNEFParser::ParserPrivate::parseDevice()
00373 {
00374 quint16 u;
00375 quint32 i;
00376 quint8 c;
00377
00378 message_->clearAttachments();
00379 if ( current_ ) {
00380 delete current_;
00381 current_ = 0;
00382 }
00383
00384 if ( !device_->open( QIODevice::ReadOnly ) ) {
00385 kDebug(5975) << "Couldn't open device";
00386 return false;
00387 }
00388
00389 stream_.setDevice( device_ );
00390 stream_.setByteOrder( QDataStream::LittleEndian );
00391 stream_ >> i;
00392 if ( i == TNEF_SIGNATURE ) {
00393 stream_ >> u;
00394 kDebug(5975).nospace() << "Attachment cross reference key: 0x"
00395 << hex << qSetFieldWidth(4) << qSetPadChar('0') << u;
00396
00397 while (!stream_.atEnd()) {
00398 stream_ >> c;
00399 switch( c ) {
00400 case LVL_MESSAGE:
00401 if ( !decodeMessage() ) goto end;
00402 break;
00403 case LVL_ATTACHMENT:
00404 if ( !decodeAttachment() ) goto end;
00405 break;
00406 default:
00407 kDebug(5975) << "Unknown Level:" << c << ", at offset"
00408 << device_->pos();
00409 goto end;
00410 }
00411 }
00412 if ( current_ ) {
00413 checkCurrent( attATTACHDATA );
00414
00415
00416 delete current_;
00417 current_ = 0;
00418 }
00419 return true;
00420 } else {
00421 kDebug(5975) << "This is not a TNEF file";
00422 end:
00423 device_->close();
00424 return false;
00425 }
00426 }
00427
00428 bool KTNEFParser::extractFile( const QString &filename ) const
00429 {
00430 KTNEFAttach *att = d->message_->attachment( filename );
00431 if ( !att ) {
00432 return false;
00433 }
00434 return d->extractAttachmentTo( att, d->defaultdir_ );
00435 }
00436
00437 bool KTNEFParser::ParserPrivate::extractAttachmentTo( KTNEFAttach *att,
00438 const QString &dirname )
00439 {
00440 QString filename = dirname + '/' + att->name();
00441 if ( !device_->isOpen() ) {
00442 return false;
00443 }
00444 if ( !device_->seek( att->offset() ) ) {
00445 return false;
00446 }
00447 KSaveFile outfile( filename );
00448 if ( !outfile.open() ) {
00449 return false;
00450 }
00451
00452 quint32 len = att->size(), sz( 16384 );
00453 int n( 0 );
00454 char *buf = new char[sz];
00455 bool ok( true );
00456 while ( ok && len > 0 ) {
00457 n = device_->read( buf, qMin( sz, len ) );
00458 if ( n < 0 ) {
00459 ok = false;
00460 } else {
00461 len -= n;
00462 if ( outfile.write( buf, n ) != n ) {
00463 ok = false;
00464 }
00465 }
00466 }
00467 delete [] buf;
00468
00469 return ok;
00470 }
00471
00472 bool KTNEFParser::extractAll()
00473 {
00474 QList<KTNEFAttach*> l = d->message_->attachmentList();
00475 QList<KTNEFAttach*>::const_iterator it = l.begin();
00476 for ( ; it != l.end(); ++it ) {
00477 if ( !d->extractAttachmentTo( *it, d->defaultdir_ ) ) {
00478 return false;
00479 }
00480 }
00481 return true;
00482 }
00483
00484 bool KTNEFParser::extractFileTo( const QString &filename,
00485 const QString &dirname ) const
00486 {
00487 kDebug(5975) << "Extracting attachment: filename="
00488 << filename << ", dir=" << dirname;
00489 KTNEFAttach *att = d->message_->attachment( filename );
00490 if ( !att ) {
00491 return false;
00492 }
00493 return d->extractAttachmentTo( att, dirname );
00494 }
00495
00496 bool KTNEFParser::openFile( const QString &filename ) const
00497 {
00498 d->deleteDevice();
00499 delete d->message_;
00500 d->message_ = new KTNEFMessage();
00501 d->device_ = new QFile( filename );
00502 d->deleteDevice_ = true;
00503 return d->parseDevice();
00504 }
00505
00506 bool KTNEFParser::openDevice( QIODevice *device )
00507 {
00508 d->deleteDevice();
00509 d->device_ = device;
00510 return d->parseDevice();
00511 }
00512
00513 void KTNEFParser::ParserPrivate::checkCurrent( int key )
00514 {
00515 if ( !current_ ) {
00516 current_ = new KTNEFAttach();
00517 } else {
00518 if ( current_->attributes().contains( key ) ) {
00519 if (current_->offset() >= 0 ) {
00520 if (current_->name().isEmpty()) {
00521 current_->setName( "Unnamed" );
00522 }
00523 if ( current_->mimeTag().isEmpty() ) {
00524
00525
00526
00527 KMimeType::Ptr mimetype;
00528 if ( !current_->fileName().isEmpty() ) {
00529 mimetype = KMimeType::findByPath( current_->fileName(), 0, true );
00530 }
00531 if ( !mimetype ) return;
00532 if ( mimetype->name() == "application/octet-stream" &&
00533 current_->size() > 0 ) {
00534 int oldOffset = device_->pos();
00535 QByteArray buffer( qMin( 32, current_->size() ), '\0' );
00536 device_->seek( current_->offset() );
00537 device_->read( buffer.data(), buffer.size() );
00538 mimetype = KMimeType::findByContent( buffer );
00539 device_->seek( oldOffset );
00540 }
00541 current_->setMimeTag( mimetype->name() );
00542 }
00543 message_->addAttachment( current_ );
00544 current_ = 0;
00545 } else {
00546
00547 delete current_;
00548 current_ = 0;
00549 }
00550 current_ = new KTNEFAttach();
00551 }
00552 }
00553 }
00554
00555
00556
00557
00558 #define ALIGN( n, b ) if ( n & ( b-1 ) ) { n = ( n + b ) & ~( b-1 ); }
00559 #define ISVECTOR( m ) ( ( ( m ).type & 0xF000 ) == MAPI_TYPE_VECTOR )
00560
00561 void clearMAPIName( MAPI_value &mapi )
00562 {
00563 mapi.name.value.clear();
00564 }
00565
00566 void clearMAPIValue( MAPI_value &mapi, bool clearName )
00567 {
00568 mapi.value.clear();
00569 if ( clearName ) {
00570 clearMAPIName( mapi );
00571 }
00572 }
00573
00574 QDateTime formatTime( quint32 lowB, quint32 highB )
00575 {
00576 QDateTime dt;
00577 quint64 u64;
00578 u64 = highB;
00579 u64 <<= 32;
00580 u64 |= lowB;
00581 u64 -= 116444736000000000LL;
00582 u64 /= 10000000;
00583 if ( u64 <= 0xffffffffU ) {
00584 dt.setTime_t( ( unsigned int )u64 );
00585 } else {
00586 kWarning().nospace() << "Invalid date: low byte="
00587 << showbase << qSetFieldWidth(8) << qSetPadChar('0')
00588 << lowB << ", high byte=" << highB;
00589 dt.setTime_t( 0xffffffffU );
00590 }
00591 return dt;
00592 }
00593
00594 QString formatRecipient( const QMap<int,KTnef::KTNEFProperty*> &props )
00595 {
00596 QString s, dn, addr, t;
00597 QMap<int,KTnef::KTNEFProperty*>::ConstIterator it;
00598 if ( ( it = props.find( 0x3001 ) ) != props.end() ) {
00599 dn = ( *it )->valueString();
00600 }
00601 if ( ( it = props.find( 0x3003 ) ) != props.end() ) {
00602 addr = ( *it )->valueString();
00603 }
00604 if ( ( it = props.find( 0x0C15 ) ) != props.end() ) {
00605 switch ( ( *it )->value().toInt() ) {
00606 case 0: t = "From:"; break;
00607 case 1: t = "To:"; break;
00608 case 2: t = "Cc:"; break;
00609 case 3: t = "Bcc:"; break;
00610 }
00611 }
00612 if ( !t.isEmpty() ) {
00613 s.append( t );
00614 }
00615 if ( !dn.isEmpty() ) {
00616 s.append( ' ' + dn );
00617 }
00618 if ( !addr.isEmpty() && addr != dn ) {
00619 s.append( " <" + addr + '>' );
00620 }
00621
00622 return s.trimmed();
00623 }
00624
00625 QDateTime readTNEFDate( QDataStream &stream )
00626 {
00627
00628 quint16 y, m, d, hh, mm, ss, dm;
00629 stream >> y >> m >> d >> hh >> mm >> ss >> dm;
00630 return QDateTime( QDate( y, m, d ), QTime( hh, mm, ss ) );
00631 }
00632
00633 QString readTNEFAddress( QDataStream &stream )
00634 {
00635 quint16 totalLen, strLen, addrLen;
00636 QString s;
00637 stream >> totalLen >> totalLen >> strLen >> addrLen;
00638 s.append( readMAPIString( stream, false, false, strLen ) );
00639 s.append( " <" );
00640 s.append( readMAPIString( stream, false, false, addrLen ) );
00641 s.append( ">" );
00642 quint8 c;
00643 for ( int i=8+strLen+addrLen; i<totalLen; i++ ) {
00644 stream >> c;
00645 }
00646 return s;
00647 }
00648
00649 QByteArray readTNEFData( QDataStream &stream, quint32 len )
00650 {
00651 QByteArray array( len, '\0' );
00652 if ( len > 0 ) {
00653 stream.readRawData( array.data(), len );
00654 }
00655 return array;
00656 }
00657
00658 QVariant readTNEFAttribute( QDataStream &stream, quint16 type, quint32 len )
00659 {
00660 switch ( type ) {
00661 case atpTEXT:
00662 case atpSTRING:
00663 return readMAPIString( stream, false, false, len );
00664 case atpDATE:
00665 return readTNEFDate( stream );
00666 default:
00667 return readTNEFData( stream, len );
00668 }
00669 }
00670
00671 QString readMAPIString( QDataStream &stream, bool isUnicode, bool align,
00672 int len_ )
00673 {
00674 quint32 len;
00675 char *buf = 0;
00676 if ( len_ == -1 ) {
00677 stream >> len;
00678 } else {
00679 len = len_;
00680 }
00681 quint32 fullLen = len;
00682 if ( align ) {
00683 ALIGN( fullLen, 4 );
00684 }
00685 buf = new char[ len ];
00686 stream.readRawData( buf, len );
00687 quint8 c;
00688 for ( uint i=len; i<fullLen; i++ ) {
00689 stream >> c;
00690 }
00691 QString res;
00692 if ( isUnicode ) {
00693 res = QString::fromUtf16( ( const unsigned short *)buf );
00694 } else {
00695 res = QString::fromLocal8Bit( buf );
00696 }
00697 delete [] buf;
00698 return res;
00699 }
00700
00701 quint16 readMAPIValue( QDataStream &stream, MAPI_value &mapi )
00702 {
00703 quint32 d;
00704
00705 clearMAPIValue( mapi );
00706 stream >> d;
00707 mapi.type = ( d & 0x0000FFFF );
00708 mapi.tag = ( ( d & 0xFFFF0000 ) >> 16 );
00709 if ( mapi.tag >= 0x8000 && mapi.tag <= 0xFFFE ) {
00710
00711 stream >> d >> d >> d >> d;
00712
00713 stream >> mapi.name.type;
00714
00715 if ( mapi.name.type == 0 ) {
00716 uint tmp;
00717 stream >> tmp;
00718 mapi.name.value.setValue( tmp );
00719 } else if ( mapi.name.type == 1 ) {
00720 mapi.name.value.setValue( readMAPIString( stream, true ) );
00721 }
00722 }
00723
00724 int n = 1;
00725 QVariant value;
00726 if ( ISVECTOR( mapi ) ) {
00727 stream >> n;
00728 mapi.value = QList<QVariant>();
00729 }
00730 for ( int i=0; i<n; i++ ) {
00731 value.clear();
00732 switch( mapi.type & 0x0FFF ) {
00733 case MAPI_TYPE_UINT16:
00734 stream >> d;
00735 value.setValue( d & 0x0000FFFF );
00736 break;
00737 case MAPI_TYPE_BOOLEAN:
00738 case MAPI_TYPE_ULONG:
00739 {
00740 uint tmp;
00741 stream >> tmp;
00742 value.setValue( tmp );
00743 }
00744 break;
00745 case MAPI_TYPE_FLOAT:
00746
00747 stream >> d;
00748 break;
00749 case MAPI_TYPE_DOUBLE:
00750 {
00751 double tmp;
00752 stream >> tmp;
00753 value.setValue( tmp );
00754 }
00755 break;
00756 case MAPI_TYPE_TIME:
00757 {
00758 quint32 lowB, highB;
00759 stream >> lowB >> highB;
00760 value = formatTime( lowB, highB );
00761 }
00762 break;
00763 case MAPI_TYPE_STRING8:
00764
00765
00766 if ( ISVECTOR( mapi ) ) {
00767 d = 1;
00768 } else {
00769 stream >> d;
00770 }
00771 for ( uint i=0; i<d; i++ ) {
00772 value.clear();
00773 value.setValue( readMAPIString( stream ) );
00774 }
00775 break;
00776 case MAPI_TYPE_USTRING:
00777 mapi.type = MAPI_TYPE_NONE;
00778 break;
00779 case MAPI_TYPE_OBJECT:
00780 case MAPI_TYPE_BINARY:
00781 if ( ISVECTOR( mapi ) ) {
00782 d = 1;
00783 } else {
00784 stream >> d;
00785 }
00786 for ( uint i=0; i<d; i++ ) {
00787 value.clear();
00788 quint32 len;
00789 stream >> len;
00790 value = QByteArray( len, '\0' );
00791 if ( len > 0 ) {
00792 int fullLen = len;
00793 ALIGN( fullLen, 4 );
00794 stream.readRawData( value.toByteArray().data(), len );
00795 quint8 c;
00796 for ( int i=len; i<fullLen; i++ ) {
00797 stream >> c;
00798 }
00799
00800 }
00801 }
00802 break;
00803 default:
00804 mapi.type = MAPI_TYPE_NONE;
00805 break;
00806 }
00807 if ( ISVECTOR( mapi ) ) {
00808 QList <QVariant> lst = mapi.value.toList();
00809 lst << value;
00810 mapi.value.setValue( lst );
00811 } else {
00812 mapi.value = value;
00813 }
00814 }
00815 return mapi.tag;
00816 }
00817
00818
00819 bool KTNEFParser::ParserPrivate::readMAPIProperties( QMap<int,KTNEFProperty*> & props,
00820 KTNEFAttach *attach )
00821 {
00822 quint32 n;
00823 MAPI_value mapi;
00824 KTNEFProperty *p;
00825 QMap<int,KTNEFProperty*>::ConstIterator it;
00826 bool foundAttachment = false;
00827
00828
00829 mapi.type = MAPI_TYPE_NONE;
00830 mapi.value.clear();
00831
00832
00833 stream_ >> n;
00834 kDebug(5975) << "MAPI Properties:" << n;
00835 for ( uint i=0; i<n; i++ ) {
00836 if ( stream_.atEnd() ) {
00837 clearMAPIValue( mapi );
00838 return false;
00839 }
00840 readMAPIValue( stream_, mapi );
00841 if ( mapi.type == MAPI_TYPE_NONE ) {
00842 kDebug(5975).nospace() << "MAPI unsupported: tag="
00843 << hex << mapi.tag << ", type=" << mapi.type;
00844 clearMAPIValue( mapi );
00845 return false;
00846 }
00847 int key = mapi.tag;
00848 switch ( mapi.tag ) {
00849 case MAPI_TAG_DATA:
00850 {
00851 if ( mapi.type == MAPI_TYPE_OBJECT && attach ) {
00852 QByteArray data = mapi.value.toByteArray();
00853 int len = data.size();
00854 ALIGN( len, 4 );
00855 device_->seek( device_->pos()-len );
00856 quint32 interface_ID;
00857 stream_ >> interface_ID;
00858 if ( interface_ID == MAPI_IID_IMessage ) {
00859
00860 attach->unsetDataParser();
00861 attach->setOffset( device_->pos()+12 );
00862 attach->setSize( data.size()-16 );
00863 attach->setMimeTag( "application/vnd.ms-tnef" );
00864 attach->setDisplayName( "Embedded Message" );
00865 kDebug(5975) << "MAPI Embedded Message: size=" << data.size();
00866 }
00867 device_->seek( device_->pos() + ( len-4 ) );
00868 break;
00869 } else if ( mapi.type == MAPI_TYPE_BINARY && attach && attach->offset() < 0 ) {
00870 foundAttachment = true;
00871 int len = mapi.value.toByteArray().size();
00872 ALIGN( len, 4 );
00873 attach->setSize( len );
00874 attach->setOffset( device_->pos() - len );
00875 attach->addAttribute( attATTACHDATA, atpBYTE, QString( "< size=%1 >" ).arg( len ), false );
00876 }
00877 }
00878 kDebug(5975) << "MAPI data: size=" << mapi.value.toByteArray().size();
00879 break;
00880 default:
00881 {
00882 QString mapiname = "";
00883 if ( mapi.tag >= 0x8000 && mapi.tag <= 0xFFFE ) {
00884 if ( mapi.name.type == 0 ) {
00885 mapiname = QString().sprintf( " [name = 0x%04x]", mapi.name.value.toUInt() );
00886 } else {
00887 mapiname = QString( " [name = %1]" ).arg( mapi.name.value.toString() );
00888 }
00889 }
00890 switch ( mapi.type & 0x0FFF ) {
00891 case MAPI_TYPE_UINT16:
00892 kDebug(5975).nospace() << "(tag="
00893 << hex << mapi.tag
00894 << ") MAPI short" << mapiname.toAscii().data()
00895 << ":" << hex << mapi.value.toUInt();
00896 break;
00897 case MAPI_TYPE_ULONG:
00898 kDebug(5975).nospace() << "(tag="
00899 << hex << mapi.tag
00900 << ") MAPI long" << mapiname.toAscii().data()
00901 << ":" << hex << mapi.value.toUInt();
00902 break;
00903 case MAPI_TYPE_BOOLEAN:
00904 kDebug(5975).nospace() << "(tag="
00905 << hex << mapi.tag
00906 << ") MAPI boolean" << mapiname.toAscii().data()
00907 << ":" << mapi.value.toBool();
00908 break;
00909 case MAPI_TYPE_TIME:
00910 kDebug(5975).nospace() << "(tag="
00911 << hex << mapi.tag
00912 << ") MAPI time" << mapiname.toAscii().data()
00913 << ":" << mapi.value.toString().toAscii().data();
00914 break;
00915 case MAPI_TYPE_USTRING:
00916 case MAPI_TYPE_STRING8:
00917 kDebug(5975).nospace() << "(tag="
00918 << hex << mapi.tag
00919 << ") MAPI string" << mapiname.toAscii().data()
00920 << ":size=" << mapi.value.toByteArray().size()
00921 << mapi.value.toString();
00922 break;
00923 case MAPI_TYPE_BINARY:
00924 kDebug(5975).nospace() << "(tag="
00925 << hex << mapi.tag
00926 << ") MAPI binary" << mapiname.toAscii().data()
00927 << ":size=" << mapi.value.toByteArray().size();
00928 break;
00929 }
00930 }
00931 break;
00932 }
00933
00934 if ( ( it = props.find( key ) ) == props.end() ) {
00935 p = new KTNEFProperty( key, ( mapi.type & 0x0FFF ),
00936 mapi.value, mapi.name.value );
00937 props[ p->key() ] = p;
00938 }
00939
00940 }
00941
00942 if ( foundAttachment && attach ) {
00943 attach->setIndex( attach->property( MAPI_TAG_INDEX ).toUInt() );
00944 attach->setDisplaySize( attach->property( MAPI_TAG_SIZE ).toUInt() );
00945 QString str = attach->property( MAPI_TAG_DISPLAYNAME ).toString();
00946 if ( !str.isEmpty() )
00947 attach->setDisplayName( str );
00948 attach->setFileName( attach->property( MAPI_TAG_FILENAME ).toString() );
00949 str = attach->property( MAPI_TAG_MIMETAG ).toString();
00950 if ( !str.isEmpty() )
00951 attach->setMimeTag( str );
00952 attach->setExtension( attach->property( MAPI_TAG_EXTENSION ).toString() );
00953 if ( attach->name().isEmpty() )
00954 attach->setName( attach->fileName() );
00955 }
00956
00957 return true;
00958 }