partNode.cpp
00001 /* -*- c++ -*- 00002 partNode.cpp A node in a MIME tree. 00003 00004 This file is part of KMail, the KDE mail client. 00005 Copyright (c) 2002 Klarälvdalens Datakonsult AB 00006 00007 KMail is free software; you can redistribute it and/or modify it 00008 under the terms of the GNU General Public License, version 2, as 00009 published by the Free Software Foundation. 00010 00011 KMail is distributed in the hope that it will be useful, but 00012 WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License 00017 along with this program; if not, write to the Free Software 00018 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 00020 In addition, as a special exception, the copyright holders give 00021 permission to link the code of this program with any edition of 00022 the TQt library by Trolltech AS, Norway (or with modified versions 00023 of TQt that use the same license as TQt), and distribute linked 00024 combinations including the two. You must obey the GNU General 00025 Public License in all respects for all of the code used other than 00026 TQt. If you modify this file, you may extend this exception to 00027 your version of the file, but you are not obligated to do so. If 00028 you do not wish to do so, delete this exception statement from 00029 your version. 00030 */ 00031 00032 #include <config.h> 00033 00034 #include "partNode.h" 00035 #include "kmreaderwin.h" 00036 00037 #include <tdelocale.h> 00038 #include <kdebug.h> 00039 #include "kmmimeparttree.h" 00040 #include <mimelib/utility.h> 00041 #include <tqregexp.h> 00042 #include <kasciistricmp.h> 00043 #include "util.h" 00044 00045 /* 00046 =========================================================================== 00047 00048 00049 S T A R T O F T E M P O R A R Y M I M E C O D E 00050 00051 00052 =========================================================================== 00053 N O T E : The partNode structure will most likely be replaced by KMime. 00054 It's purpose: Speed optimization for KDE 3. (khz, 28.11.01) 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; // this happens e.g. for the Root Node 00095 mSubType = explicitSubType; // representing the _whole_ message 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 // we don't want to treat the top-level part special. mimelib does 00120 // (Message vs. BodyPart, with common base class Entity). But we 00121 // used DwBodyPart, not DwEntiy everywhere. *shrug*. DwStrings are 00122 // subscrib-shared, so we just force mimelib to parse the whole mail 00123 // as just another DwBodyPart... 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 //root->dump(); 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<TQCString,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() << " " << TQString(TQString().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 TQCString & 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 //dive into multipart messages 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 // go up in the tree until reaching a node with next 00206 // (or the last top-level node) 00207 while( curNode 00208 && !( curNode->dwPart() 00209 && curNode->dwPart()->Next() ) ) { 00210 curNode = curNode->mRoot; 00211 } 00212 // we might have to leave when all children have been processed 00213 if( this == curNode && !processSiblings ) 00214 return; 00215 // store next node 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 TQCString partNode::typeString() const { 00226 DwString s; 00227 DwTypeEnumToStr( type(), s ); 00228 return s.c_str(); 00229 } 00230 00231 TQCString 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 TQString partNode::contentTypeParameter( const char * name ) const { 00261 if ( !mDwPart || !mDwPart->hasHeaders() ) 00262 return TQString(); 00263 DwHeaders & headers = mDwPart->Headers(); 00264 if ( !headers.HasContentType() ) 00265 return TQString(); 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(); // what a braindead design! 00271 if ( this_attr == attr ) 00272 return TQString::fromLatin1( param->Value().data(), param->Value().size() ); 00273 // warning: misses rfc2231 handling! 00274 } 00275 return TQString(); 00276 } 00277 00278 KMMsgEncryptionState partNode::overallEncryptionState() const 00279 { 00280 KMMsgEncryptionState myState = KMMsgEncryptionStateUnknown; 00281 if( mEncryptionState == KMMsgNotEncrypted ) { 00282 // NOTE: children are tested ONLY when parent is not encrypted 00283 if( mChild ) 00284 myState = mChild->overallEncryptionState(); 00285 else 00286 myState = KMMsgNotEncrypted; 00287 } 00288 else { // part is partially or fully encrypted 00289 myState = mEncryptionState; 00290 } 00291 // siblings are tested always 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 // children are tested ONLY when parent is not signed 00324 if( mChild ) 00325 myState = mChild->overallSignatureState(); 00326 else 00327 myState = KMMsgNotSigned; 00328 } 00329 else { // part is partially or fully signed 00330 myState = mSignatureState; 00331 } 00332 // siblings are tested always 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 TQCString partNode::path() const 00360 { 00361 if ( !parentNode() ) 00362 return ':'; 00363 const partNode * p = parentNode(); 00364 00365 // count number of siblings with the same type as us: 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() + TQCString().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 // We use the same algorithm to determine the id of a node and 00400 // to find the node when id is known. 00401 curId++; 00402 // check for node ? 00403 if( findNode && this == findNode ) 00404 return curId; 00405 // check for id ? 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 TQString labelDescr, 00469 TQString labelCntType, 00470 TQString labelEncoding, 00471 TDEIO::filesize_t size, 00472 bool revertOrder ) 00473 { 00474 if( parentItem || mimePartTree ) { 00475 00476 if( mNext ) 00477 mNext->fillMimePartTree( parentItem, mimePartTree, 00478 TQString(), TQString(), TQString(), 0, 00479 revertOrder ); 00480 00481 TQString cntDesc, cntType, cntEnc; 00482 TDEIO::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().name().stripWhiteSpace(); 00499 if( cntDesc.isEmpty() ) 00500 cntDesc = msgPart().fileName(); 00501 if( cntDesc.isEmpty() ) 00502 cntDesc = msgPart().contentDescription(); 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 // remove linebreak+whitespace from folded Content-Description 00519 cntDesc.replace( TQRegExp("\\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 TQString(), TQString(), TQString(), 0, 00540 revertOrder ); 00541 00542 } 00543 } 00544 00545 void partNode::adjustDefaultType( partNode* node ) 00546 { 00547 // Only bodies of 'Multipart/Digest' objects have 00548 // default type 'Message/RfC822'. All other bodies 00549 // have default type 'Text/Plain' (khz, 5.12.2001) 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 // Messages are always attachments. Normally message attachments created from KMail have a content 00576 // disposition, but some mail clients omit that. 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 // go up until we reach the root node of a message (of the actual message or 00609 // of an attached message) 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; // make comiler happy 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 TQString( library->FieldBody()->AsString().c_str() ) != TQString( "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 !TQString( 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 TQString& 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 TQCString & 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 TQCString & which ) const 00693 { 00694 assert( !reader() ); 00695 00696 const std::map<TQCString,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 TQCString & 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 TQCString & which, KMail::Interface::BodyPartMemento * memento ) 00709 { 00710 assert( !reader() ); 00711 00712 const std::map<TQCString,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 TQString partNode::asHREF( const TQString &place ) const 00748 { 00749 return TQString( "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( TDEIcon::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 }