00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <config.h>
00033
00034 #include "partNode.h"
00035 #include "kmreaderwin.h"
00036
00037 #include <klocale.h>
00038 #include <kdebug.h>
00039 #include "kmmimeparttree.h"
00040 #include <mimelib/utility.h>
00041 #include <qregexp.h>
00042 #include <kasciistricmp.h>
00043 #include "util.h"
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058 partNode::partNode()
00059 : mRoot( 0 ), mNext( 0 ), mChild( 0 ),
00060 mWasProcessed( false ),
00061 mDwPart( 0 ),
00062 mType( DwMime::kTypeUnknown ),
00063 mSubType( DwMime::kSubtypeUnknown ),
00064 mEncryptionState( KMMsgNotEncrypted ),
00065 mSignatureState( KMMsgNotSigned ),
00066 mMsgPartOk( false ),
00067 mEncodedOk( false ),
00068 mDeleteDwBodyPart( false ),
00069 mMimePartTreeItem( 0 ),
00070 mBodyPartMementoMap(),
00071 mReader( 0 ),
00072 mDisplayedEmbedded( false )
00073 {
00074 adjustDefaultType( this );
00075 }
00076
00077 partNode::partNode( KMReaderWin * win, DwBodyPart* dwPart, int explicitType, int explicitSubType,
00078 bool deleteDwBodyPart )
00079 : mRoot( 0 ), mNext( 0 ), mChild( 0 ),
00080 mWasProcessed( false ),
00081 mDwPart( dwPart ),
00082 mEncryptionState( KMMsgNotEncrypted ),
00083 mSignatureState( KMMsgNotSigned ),
00084 mMsgPartOk( false ),
00085 mEncodedOk( false ),
00086 mDeleteDwBodyPart( deleteDwBodyPart ),
00087 mMimePartTreeItem( 0 ),
00088 mBodyPartMementoMap(),
00089 mReader( win ),
00090 mDisplayedEmbedded( false ),
00091 mDisplayedHidden( false )
00092 {
00093 if ( explicitType != DwMime::kTypeUnknown ) {
00094 mType = explicitType;
00095 mSubType = explicitSubType;
00096 } else {
00097 if(dwPart && dwPart->hasHeaders() && dwPart->Headers().HasContentType()) {
00098 mType = (!dwPart->Headers().ContentType().Type())?DwMime::kTypeUnknown:dwPart->Headers().ContentType().Type();
00099 mSubType = dwPart->Headers().ContentType().Subtype();
00100 } else {
00101 mType = DwMime::kTypeUnknown;
00102 mSubType = DwMime::kSubtypeUnknown;
00103 }
00104 }
00105 }
00106
00107 partNode * partNode::fromMessage( const KMMessage * msg, KMReaderWin * win ) {
00108 if ( !msg )
00109 return 0;
00110
00111 int mainType = msg->type();
00112 int mainSubType = msg->subtype();
00113 if( (DwMime::kTypeNull == mainType)
00114 || (DwMime::kTypeUnknown == mainType) ){
00115 mainType = DwMime::kTypeText;
00116 mainSubType = DwMime::kSubtypePlain;
00117 }
00118
00119
00120
00121
00122
00123
00124 DwBodyPart * mainBody = new DwBodyPart( *msg->getTopLevelPart() );
00125
00126 partNode * root = new partNode( win, mainBody, mainType, mainSubType, true );
00127 root->buildObjectTree();
00128
00129 root->setFromAddress( msg->from() );
00130
00131 return root;
00132 }
00133
00134 partNode::partNode( bool deleteDwBodyPart, DwBodyPart* dwPart )
00135 : mRoot( 0 ), mNext( 0 ), mChild( 0 ),
00136 mWasProcessed( false ),
00137 mDwPart( dwPart ),
00138 mEncryptionState( KMMsgNotEncrypted ),
00139 mSignatureState( KMMsgNotSigned ),
00140 mMsgPartOk( false ),
00141 mEncodedOk( false ),
00142 mDeleteDwBodyPart( deleteDwBodyPart ),
00143 mMimePartTreeItem( 0 ),
00144 mBodyPartMementoMap(),
00145 mReader( 0 ),
00146 mDisplayedEmbedded( false )
00147 {
00148 if ( dwPart && dwPart->hasHeaders() && dwPart->Headers().HasContentType() ) {
00149 mType = (!dwPart->Headers().ContentType().Type())?DwMime::kTypeUnknown:dwPart->Headers().ContentType().Type();
00150 mSubType = dwPart->Headers().ContentType().Subtype();
00151 } else {
00152 mType = DwMime::kTypeUnknown;
00153 mSubType = DwMime::kSubtypeUnknown;
00154 }
00155 }
00156
00157 partNode::~partNode() {
00158 if( mDeleteDwBodyPart )
00159 delete mDwPart;
00160 mDwPart = 0;
00161 delete mChild; mChild = 0;
00162 delete mNext; mNext = 0;
00163 for ( std::map<QCString,KMail::Interface::BodyPartMemento*>::const_iterator it = mBodyPartMementoMap.begin(), end = mBodyPartMementoMap.end() ; it != end ; ++it )
00164 delete it->second;
00165 mBodyPartMementoMap.clear();
00166 }
00167
00168 #ifndef NDEBUG
00169 void partNode::dump( int chars ) const {
00170 kdDebug(5006) << nodeId() << " " << QString().fill( ' ', chars ) << "+ "
00171 << typeString() << '/' << subTypeString() << " embedded:" << mDisplayedEmbedded
00172 << " address:" << this << endl;
00173 if ( mChild )
00174 mChild->dump( chars + 1 );
00175 if ( mNext )
00176 mNext->dump( chars );
00177 }
00178 #else
00179 void partNode::dump( int ) const {}
00180 #endif
00181
00182 const QCString & partNode::encodedBody() {
00183 if ( mEncodedOk )
00184 return mEncodedBody;
00185
00186 if ( mDwPart )
00187 mEncodedBody = KMail::Util::CString( mDwPart->Body().AsString() );
00188 else
00189 mEncodedBody = 0;
00190 mEncodedOk = true;
00191 return mEncodedBody;
00192 }
00193
00194
00195 void partNode::buildObjectTree( bool processSiblings )
00196 {
00197 partNode* curNode = this;
00198 while( curNode && curNode->dwPart() ) {
00199
00200 while( DwMime::kTypeMultipart == curNode->type() ) {
00201 partNode * newNode = new partNode( mReader, curNode->dwPart()->Body().FirstBodyPart() );
00202 curNode->setFirstChild( newNode );
00203 curNode = newNode;
00204 }
00205
00206
00207 while( curNode
00208 && !( curNode->dwPart()
00209 && curNode->dwPart()->Next() ) ) {
00210 curNode = curNode->mRoot;
00211 }
00212
00213 if( this == curNode && !processSiblings )
00214 return;
00215
00216 if( curNode && curNode->dwPart() && curNode->dwPart()->Next() ) {
00217 partNode* nextNode = new partNode( mReader, curNode->dwPart()->Next() );
00218 curNode->setNext( nextNode );
00219 curNode = nextNode;
00220 } else
00221 curNode = 0;
00222 }
00223 }
00224
00225 QCString partNode::typeString() const {
00226 DwString s;
00227 DwTypeEnumToStr( type(), s );
00228 return s.c_str();
00229 }
00230
00231 QCString partNode::subTypeString() const {
00232 DwString s;
00233 DwSubtypeEnumToStr( subType(), s );
00234 return s.c_str();
00235 }
00236
00237 const partNode* partNode::topLevelParent() const {
00238 const partNode *ret = this;
00239 while ( ret->parentNode() )
00240 ret = ret->parentNode();
00241 return ret;
00242 }
00243
00244 int partNode::childCount() const {
00245 int count = 0;
00246 for ( partNode * child = firstChild() ; child ; child = child->nextSibling() )
00247 ++ count;
00248 return count;
00249 }
00250
00251 int partNode::totalChildCount() const {
00252 int count = 0;
00253 for ( partNode * child = firstChild() ; child ; child = child->nextSibling() ) {
00254 ++count;
00255 count += child->totalChildCount();
00256 }
00257 return count;
00258 }
00259
00260 QString partNode::contentTypeParameter( const char * name ) const {
00261 if ( !mDwPart || !mDwPart->hasHeaders() )
00262 return QString::null;
00263 DwHeaders & headers = mDwPart->Headers();
00264 if ( !headers.HasContentType() )
00265 return QString::null;
00266 DwString attr = name;
00267 attr.ConvertToLowerCase();
00268 for ( DwParameter * param = headers.ContentType().FirstParameter() ; param ; param = param->Next() ) {
00269 DwString this_attr = param->Attribute();
00270 this_attr.ConvertToLowerCase();
00271 if ( this_attr == attr )
00272 return QString::fromLatin1( param->Value().data(), param->Value().size() );
00273
00274 }
00275 return QString::null;
00276 }
00277
00278 KMMsgEncryptionState partNode::overallEncryptionState() const
00279 {
00280 KMMsgEncryptionState myState = KMMsgEncryptionStateUnknown;
00281 if( mEncryptionState == KMMsgNotEncrypted ) {
00282
00283 if( mChild )
00284 myState = mChild->overallEncryptionState();
00285 else
00286 myState = KMMsgNotEncrypted;
00287 }
00288 else {
00289 myState = mEncryptionState;
00290 }
00291
00292 if( mNext ) {
00293 KMMsgEncryptionState otherState = mNext->overallEncryptionState();
00294 switch( otherState ) {
00295 case KMMsgEncryptionStateUnknown:
00296 break;
00297 case KMMsgNotEncrypted:
00298 if( myState == KMMsgFullyEncrypted )
00299 myState = KMMsgPartiallyEncrypted;
00300 else if( myState != KMMsgPartiallyEncrypted )
00301 myState = KMMsgNotEncrypted;
00302 break;
00303 case KMMsgPartiallyEncrypted:
00304 myState = KMMsgPartiallyEncrypted;
00305 break;
00306 case KMMsgFullyEncrypted:
00307 if( myState != KMMsgFullyEncrypted )
00308 myState = KMMsgPartiallyEncrypted;
00309 break;
00310 case KMMsgEncryptionProblematic:
00311 break;
00312 }
00313 }
00314
00315 return myState;
00316 }
00317
00318
00319 KMMsgSignatureState partNode::overallSignatureState() const
00320 {
00321 KMMsgSignatureState myState = KMMsgSignatureStateUnknown;
00322 if( mSignatureState == KMMsgNotSigned ) {
00323
00324 if( mChild )
00325 myState = mChild->overallSignatureState();
00326 else
00327 myState = KMMsgNotSigned;
00328 }
00329 else {
00330 myState = mSignatureState;
00331 }
00332
00333 if( mNext ) {
00334 KMMsgSignatureState otherState = mNext->overallSignatureState();
00335 switch( otherState ) {
00336 case KMMsgSignatureStateUnknown:
00337 break;
00338 case KMMsgNotSigned:
00339 if( myState == KMMsgFullySigned )
00340 myState = KMMsgPartiallySigned;
00341 else if( myState != KMMsgPartiallySigned )
00342 myState = KMMsgNotSigned;
00343 break;
00344 case KMMsgPartiallySigned:
00345 myState = KMMsgPartiallySigned;
00346 break;
00347 case KMMsgFullySigned:
00348 if( myState != KMMsgFullySigned )
00349 myState = KMMsgPartiallySigned;
00350 break;
00351 case KMMsgEncryptionProblematic:
00352 break;
00353 }
00354 }
00355
00356 return myState;
00357 }
00358
00359 QCString partNode::path() const
00360 {
00361 if ( !parentNode() )
00362 return ':';
00363 const partNode * p = parentNode();
00364
00365
00366 int nth = 0;
00367 for ( const partNode * c = p->firstChild() ; c != this ; c = c->nextSibling() )
00368 if ( c->type() == type() && c->subType() == subType() )
00369 ++nth;
00370
00371 return p->path() + QCString().sprintf( ":%X/%X[%X]", type(), subType(), nth );
00372 }
00373
00374
00375 int partNode::nodeId() const
00376 {
00377 int curId = 0;
00378 partNode* rootNode = const_cast<partNode*>( this );
00379 while( rootNode->mRoot )
00380 rootNode = rootNode->mRoot;
00381 return rootNode->calcNodeIdOrFindNode( curId, this, 0, 0 );
00382 }
00383
00384
00385 partNode* partNode::findId( int id )
00386 {
00387 int curId = 0;
00388 partNode* rootNode = this;
00389 while( rootNode->mRoot )
00390 rootNode = rootNode->mRoot;
00391 partNode* foundNode;
00392 rootNode->calcNodeIdOrFindNode( curId, 0, id, &foundNode );
00393 return foundNode;
00394 }
00395
00396
00397 int partNode::calcNodeIdOrFindNode( int &curId, const partNode* findNode, int findId, partNode** foundNode )
00398 {
00399
00400
00401 curId++;
00402
00403 if( findNode && this == findNode )
00404 return curId;
00405
00406 if( foundNode && curId == findId ) {
00407 *foundNode = this;
00408 return curId;
00409 }
00410 if( mChild )
00411 {
00412 int res = mChild->calcNodeIdOrFindNode( curId, findNode, findId, foundNode );
00413 if (res != -1) return res;
00414 }
00415 if( mNext )
00416 return mNext->calcNodeIdOrFindNode( curId, findNode, findId, foundNode );
00417
00418 if( foundNode )
00419 *foundNode = 0;
00420 return -1;
00421 }
00422
00423
00424 partNode* partNode::findType( int type, int subType, bool deep, bool wide )
00425 {
00426 if( (mType != DwMime::kTypeUnknown)
00427 && ( (type == DwMime::kTypeUnknown)
00428 || (type == mType) )
00429 && ( (subType == DwMime::kSubtypeUnknown)
00430 || (subType == mSubType) ) )
00431 return this;
00432 if ( mChild && deep )
00433 return mChild->findType( type, subType, deep, wide );
00434 if ( mNext && wide )
00435 return mNext->findType( type, subType, deep, wide );
00436 return 0;
00437 }
00438
00439 partNode* partNode::findNodeForDwPart( DwBodyPart* part )
00440 {
00441 partNode* found = 0;
00442 if( kasciistricmp( dwPart()->partId(), part->partId() ) == 0 )
00443 return this;
00444 if( mChild )
00445 found = mChild->findNodeForDwPart( part );
00446 if( mNext && !found )
00447 found = mNext->findNodeForDwPart( part );
00448 return found;
00449 }
00450
00451 partNode* partNode::findTypeNot( int type, int subType, bool deep, bool wide )
00452 {
00453 if( (mType != DwMime::kTypeUnknown)
00454 && ( (type == DwMime::kTypeUnknown)
00455 || (type != mType) )
00456 && ( (subType == DwMime::kSubtypeUnknown)
00457 || (subType != mSubType) ) )
00458 return this;
00459 if ( mChild && deep )
00460 return mChild->findTypeNot( type, subType, deep, wide );
00461 if ( mNext && wide )
00462 return mNext->findTypeNot( type, subType, deep, wide );
00463 return 0;
00464 }
00465
00466 void partNode::fillMimePartTree( KMMimePartTreeItem* parentItem,
00467 KMMimePartTree* mimePartTree,
00468 QString labelDescr,
00469 QString labelCntType,
00470 QString labelEncoding,
00471 KIO::filesize_t size,
00472 bool revertOrder )
00473 {
00474 if( parentItem || mimePartTree ) {
00475
00476 if( mNext )
00477 mNext->fillMimePartTree( parentItem, mimePartTree,
00478 QString::null, QString::null, QString::null, 0,
00479 revertOrder );
00480
00481 QString cntDesc, cntType, cntEnc;
00482 KIO::filesize_t cntSize = 0;
00483
00484 if( labelDescr.isEmpty() ) {
00485 DwHeaders* headers = 0;
00486 if( mDwPart && mDwPart->hasHeaders() )
00487 headers = &mDwPart->Headers();
00488 if( headers && headers->HasSubject() )
00489 cntDesc = KMMsgBase::decodeRFC2047String( headers->Subject().AsString().c_str() );
00490 if( headers && headers->HasContentType()) {
00491 cntType = headers->ContentType().TypeStr().c_str();
00492 cntType += '/';
00493 cntType += headers->ContentType().SubtypeStr().c_str();
00494 }
00495 else
00496 cntType = "text/plain";
00497 if( cntDesc.isEmpty() )
00498 cntDesc = msgPart().contentDescription();
00499 if( cntDesc.isEmpty() )
00500 cntDesc = msgPart().name().stripWhiteSpace();
00501 if( cntDesc.isEmpty() )
00502 cntDesc = msgPart().fileName();
00503 if( cntDesc.isEmpty() ) {
00504 if( mRoot && mRoot->mRoot )
00505 cntDesc = i18n("internal part");
00506 else
00507 cntDesc = i18n("body part");
00508 }
00509 cntEnc = msgPart().contentTransferEncodingStr();
00510 if( mDwPart )
00511 cntSize = mDwPart->BodySize();
00512 } else {
00513 cntDesc = labelDescr;
00514 cntType = labelCntType;
00515 cntEnc = labelEncoding;
00516 cntSize = size;
00517 }
00518
00519 cntDesc.replace( QRegExp("\\n\\s*"), " " );
00520
00521 if( parentItem )
00522 mMimePartTreeItem = new KMMimePartTreeItem( parentItem,
00523 this,
00524 cntDesc,
00525 cntType,
00526 cntEnc,
00527 cntSize,
00528 revertOrder );
00529 else if( mimePartTree )
00530 mMimePartTreeItem = new KMMimePartTreeItem( mimePartTree,
00531 this,
00532 cntDesc,
00533 cntType,
00534 cntEnc,
00535 cntSize );
00536 mMimePartTreeItem->setOpen( true );
00537 if( mChild )
00538 mChild->fillMimePartTree( mMimePartTreeItem, 0,
00539 QString::null, QString::null, QString::null, 0,
00540 revertOrder );
00541
00542 }
00543 }
00544
00545 void partNode::adjustDefaultType( partNode* node )
00546 {
00547
00548
00549
00550 if( node && DwMime::kTypeUnknown == node->type() ) {
00551 if( node->mRoot
00552 && DwMime::kTypeMultipart == node->mRoot->type()
00553 && DwMime::kSubtypeDigest == node->mRoot->subType() ) {
00554 node->setType( DwMime::kTypeMessage );
00555 node->setSubType( DwMime::kSubtypeRfc822 );
00556 }
00557 else
00558 {
00559 node->setType( DwMime::kTypeText );
00560 node->setSubType( DwMime::kSubtypePlain );
00561 }
00562 }
00563 }
00564
00565 bool partNode::isAttachment() const
00566 {
00567 if( !dwPart() )
00568 return false;
00569 if ( !dwPart()->hasHeaders() )
00570 return false;
00571 DwHeaders& headers = dwPart()->Headers();
00572 if ( headers.HasContentType() &&
00573 headers.ContentType().Type() == DwMime::kTypeMessage &&
00574 headers.ContentType().Subtype() == DwMime::kSubtypeRfc822 ) {
00575
00576
00577 return true;
00578 }
00579 if( !headers.HasContentDisposition() )
00580 return false;
00581 return ( headers.ContentDisposition().DispositionType()
00582 == DwMime::kDispTypeAttachment );
00583 }
00584
00585 bool partNode::isHeuristicalAttachment() const {
00586 if ( isAttachment() )
00587 return true;
00588 const KMMessagePart & p = msgPart();
00589 return !p.fileName().isEmpty() || !p.name().isEmpty() ;
00590 }
00591
00592 partNode * partNode::next( bool allowChildren ) const {
00593 if ( allowChildren )
00594 if ( partNode * c = firstChild() )
00595 return c;
00596 if ( partNode * s = nextSibling() )
00597 return s;
00598 for ( partNode * p = parentNode() ; p ; p = p->parentNode() )
00599 if ( partNode * s = p->nextSibling() )
00600 return s;
00601 return 0;
00602 }
00603
00604 bool partNode::isFirstTextPart() const {
00605 if ( type() != DwMime::kTypeText )
00606 return false;
00607 const partNode * root = this;
00608
00609
00610 while ( const partNode * p = root->parentNode() ) {
00611 if ( p->type() == DwMime::kTypeMessage )
00612 break;
00613 else
00614 root = p;
00615 }
00616 for ( const partNode * n = root ; n ; n = n->next() )
00617 if ( n->type() == DwMime::kTypeText )
00618 return n == this;
00619 kdFatal() << "partNode::isFirstTextPart(): Didn't expect to end up here..." << endl;
00620 return false;
00621 }
00622
00623 bool partNode::isToltecMessage() const
00624 {
00625 if ( type() != DwMime::kTypeMultipart || subType() != DwMime::kSubtypeMixed )
00626 return false;
00627
00628 if ( childCount() != 3 )
00629 return false;
00630
00631 const DwField* library = dwPart()->Headers().FindField( "X-Library" );
00632 if ( !library )
00633 return false;
00634
00635 if ( !library->FieldBody() ||
00636 QString( library->FieldBody()->AsString().c_str() ) != QString( "Toltec" ) )
00637 return false;
00638
00639 const DwField* kolabType = dwPart()->Headers().FindField( "X-Kolab-Type" );
00640 if ( !kolabType )
00641 return false;
00642
00643 if ( !kolabType->FieldBody() ||
00644 !QString( kolabType->FieldBody()->AsString().c_str() ).startsWith( "application/x-vnd.kolab" ) )
00645 return false;
00646
00647 return true;
00648 }
00649
00650 bool partNode::isInEncapsulatedMessage() const
00651 {
00652 const partNode * const topLevel = topLevelParent();
00653 const partNode *cur = this;
00654 while ( cur && cur != topLevel ) {
00655 const bool parentIsMessage = cur->parentNode() &&
00656 cur->parentNode()->msgPart().typeStr().lower() == "message";
00657 if ( parentIsMessage && cur->parentNode() != topLevel )
00658 return true;
00659 cur = cur->parentNode();
00660 }
00661 return false;
00662 }
00663
00664 bool partNode::hasContentDispositionInline() const
00665 {
00666 if( !dwPart() )
00667 return false;
00668 DwHeaders& headers = dwPart()->Headers();
00669 if( headers.HasContentDisposition() )
00670 return ( headers.ContentDisposition().DispositionType()
00671 == DwMime::kDispTypeInline );
00672 else
00673 return false;
00674 }
00675
00676 const QString& partNode::trueFromAddress() const
00677 {
00678 const partNode* node = this;
00679 while( node->mFromAddress.isEmpty() && node->mRoot )
00680 node = node->mRoot;
00681 return node->mFromAddress;
00682 }
00683
00684 KMail::Interface::BodyPartMemento * partNode::bodyPartMemento( const QCString & which ) const
00685 {
00686 if ( const KMReaderWin * r = reader() )
00687 return r->bodyPartMemento( this, which );
00688 else
00689 return internalBodyPartMemento( which );
00690 }
00691
00692 KMail::Interface::BodyPartMemento * partNode::internalBodyPartMemento( const QCString & which ) const
00693 {
00694 assert( !reader() );
00695
00696 const std::map<QCString,KMail::Interface::BodyPartMemento*>::const_iterator it = mBodyPartMementoMap.find( which.lower() );
00697 return it != mBodyPartMementoMap.end() ? it->second : 0 ;
00698 }
00699
00700 void partNode::setBodyPartMemento( const QCString & which, KMail::Interface::BodyPartMemento * memento )
00701 {
00702 if ( KMReaderWin * r = reader() )
00703 r->setBodyPartMemento( this, which, memento );
00704 else
00705 internalSetBodyPartMemento( which, memento );
00706 }
00707
00708 void partNode::internalSetBodyPartMemento( const QCString & which, KMail::Interface::BodyPartMemento * memento )
00709 {
00710 assert( !reader() );
00711
00712 const std::map<QCString,KMail::Interface::BodyPartMemento*>::iterator it = mBodyPartMementoMap.lower_bound( which.lower() );
00713 if ( it != mBodyPartMementoMap.end() && it->first == which.lower() ) {
00714 delete it->second;
00715 if ( memento ) {
00716 it->second = memento;
00717 }
00718 else {
00719 mBodyPartMementoMap.erase( it );
00720 }
00721 } else {
00722 mBodyPartMementoMap.insert( it, std::make_pair( which.lower(), memento ) );
00723 }
00724 }
00725
00726 bool partNode::isDisplayedEmbedded() const
00727 {
00728 return mDisplayedEmbedded;
00729 }
00730
00731 void partNode::setDisplayedEmbedded( bool displayedEmbedded )
00732 {
00733 mDisplayedEmbedded = displayedEmbedded;
00734 }
00735
00736 bool partNode::isDisplayedHidden() const
00737 {
00738 return mDisplayedHidden;
00739 }
00740
00741 void partNode::setDisplayedHidden( bool displayedHidden )
00742 {
00743 mDisplayedHidden = displayedHidden;
00744 }
00745
00746
00747 QString partNode::asHREF( const QString &place ) const
00748 {
00749 return QString( "attachment:%1?place=%2" ).arg( nodeId() ).arg( place );
00750 }
00751
00752 partNode::AttachmentDisplayInfo partNode::attachmentDisplayInfo() const
00753 {
00754 AttachmentDisplayInfo info;
00755 info.icon = msgPart().iconName( KIcon::Small );
00756 info.label = msgPart().name().stripWhiteSpace();
00757 if ( info.label.isEmpty() )
00758 info.label = msgPart().fileName();
00759 if ( info.label.isEmpty() )
00760 info.label = msgPart().contentDescription();
00761 bool typeBlacklisted = msgPart().typeStr().lower() == "multipart";
00762 if ( !typeBlacklisted && msgPart().typeStr().lower() == "application" ) {
00763 typeBlacklisted = msgPart().subtypeStr() == "pgp-encrypted"
00764 || msgPart().subtypeStr().lower() == "pgp-signature"
00765 || msgPart().subtypeStr().lower() == "pkcs7-mime"
00766 || msgPart().subtypeStr().lower() == "pkcs7-signature";
00767 }
00768 typeBlacklisted = typeBlacklisted || this == topLevelParent();
00769 bool firstTextChildOfEncapsulatedMsg = msgPart().typeStr().lower() == "text" &&
00770 msgPart().subtypeStr().lower() == "plain" &&
00771 parentNode() &&
00772 parentNode()->msgPart().typeStr().lower() == "message";
00773 typeBlacklisted = typeBlacklisted || firstTextChildOfEncapsulatedMsg;
00774 info.displayInHeader = !info.label.isEmpty() && !info.icon.isEmpty() && !typeBlacklisted;
00775 return info;
00776 }