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 {
00092 if ( explicitType != DwMime::kTypeUnknown ) {
00093 mType = explicitType;
00094 mSubType = explicitSubType;
00095 } else {
00096
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 #ifdef DEBUG
00106 {
00107 DwString type, subType;
00108 DwTypeEnumToStr( mType, type );
00109 DwSubtypeEnumToStr( mSubType, subType );
00110 kdDebug(5006) << "\npartNode::partNode() " << type.c_str() << "/" << subType.c_str() << "\n" << endl;
00111 }
00112 #endif
00113 }
00114
00115 partNode * partNode::fromMessage( const KMMessage * msg, KMReaderWin * win ) {
00116 if ( !msg )
00117 return 0;
00118
00119 int mainType = msg->type();
00120 int mainSubType = msg->subtype();
00121 if( (DwMime::kTypeNull == mainType)
00122 || (DwMime::kTypeUnknown == mainType) ){
00123 mainType = DwMime::kTypeText;
00124 mainSubType = DwMime::kSubtypePlain;
00125 }
00126
00127
00128
00129
00130
00131
00132 DwBodyPart * mainBody = new DwBodyPart( *msg->getTopLevelPart() );
00133
00134 partNode * root = new partNode( win, mainBody, mainType, mainSubType, true );
00135 root->buildObjectTree();
00136
00137 root->setFromAddress( msg->from() );
00138 root->dump();
00139 return root;
00140 }
00141
00142 partNode::partNode( bool deleteDwBodyPart, DwBodyPart* dwPart )
00143 : mRoot( 0 ), mNext( 0 ), mChild( 0 ),
00144 mWasProcessed( false ),
00145 mDwPart( dwPart ),
00146 mEncryptionState( KMMsgNotEncrypted ),
00147 mSignatureState( KMMsgNotSigned ),
00148 mMsgPartOk( false ),
00149 mEncodedOk( false ),
00150 mDeleteDwBodyPart( deleteDwBodyPart ),
00151 mMimePartTreeItem( 0 ),
00152 mBodyPartMementoMap(),
00153 mReader( 0 ),
00154 mDisplayedEmbedded( false )
00155 {
00156 if ( dwPart && dwPart->hasHeaders() && dwPart->Headers().HasContentType() ) {
00157 mType = (!dwPart->Headers().ContentType().Type())?DwMime::kTypeUnknown:dwPart->Headers().ContentType().Type();
00158 mSubType = dwPart->Headers().ContentType().Subtype();
00159 } else {
00160 mType = DwMime::kTypeUnknown;
00161 mSubType = DwMime::kSubtypeUnknown;
00162 }
00163 }
00164
00165 partNode::~partNode() {
00166 if( mDeleteDwBodyPart )
00167 delete mDwPart;
00168 mDwPart = 0;
00169 delete mChild; mChild = 0;
00170 delete mNext; mNext = 0;
00171 for ( std::map<QCString,KMail::Interface::BodyPartMemento*>::const_iterator it = mBodyPartMementoMap.begin(), end = mBodyPartMementoMap.end() ; it != end ; ++it )
00172 delete it->second;
00173 mBodyPartMementoMap.clear();
00174 }
00175
00176 #ifndef NDEBUG
00177 void partNode::dump( int chars ) const {
00178 kdDebug(5006) << nodeId() << " " << QString().fill( ' ', chars ) << "+ "
00179 << typeString() << '/' << subTypeString() << " embedded:" << mDisplayedEmbedded << endl;
00180 if ( mChild )
00181 mChild->dump( chars + 1 );
00182 if ( mNext )
00183 mNext->dump( chars );
00184 }
00185 #else
00186 void partNode::dump( int ) const {}
00187 #endif
00188
00189 const QCString & partNode::encodedBody() {
00190 if ( mEncodedOk )
00191 return mEncodedBody;
00192
00193 if ( mDwPart )
00194 mEncodedBody = KMail::Util::CString( mDwPart->Body().AsString() );
00195 else
00196 mEncodedBody = 0;
00197 mEncodedOk = true;
00198 return mEncodedBody;
00199 }
00200
00201
00202 void partNode::buildObjectTree( bool processSiblings )
00203 {
00204 partNode* curNode = this;
00205 while( curNode && curNode->dwPart() ) {
00206
00207 while( DwMime::kTypeMultipart == curNode->type() ) {
00208 partNode * newNode = new partNode( mReader, curNode->dwPart()->Body().FirstBodyPart() );
00209 curNode->setFirstChild( newNode );
00210 curNode = newNode;
00211 }
00212
00213
00214 while( curNode
00215 && !( curNode->dwPart()
00216 && curNode->dwPart()->Next() ) ) {
00217 curNode = curNode->mRoot;
00218 }
00219
00220 if( this == curNode && !processSiblings )
00221 return;
00222
00223 if( curNode && curNode->dwPart() && curNode->dwPart()->Next() ) {
00224 partNode* nextNode = new partNode( mReader, curNode->dwPart()->Next() );
00225 curNode->setNext( nextNode );
00226 curNode = nextNode;
00227 } else
00228 curNode = 0;
00229 }
00230 }
00231
00232 QCString partNode::typeString() const {
00233 DwString s;
00234 DwTypeEnumToStr( type(), s );
00235 return s.c_str();
00236 }
00237
00238 QCString partNode::subTypeString() const {
00239 DwString s;
00240 DwSubtypeEnumToStr( subType(), s );
00241 return s.c_str();
00242 }
00243
00244 const partNode* partNode::topLevelParent() const {
00245 const partNode *ret = this;
00246 while ( ret->parentNode() )
00247 ret = ret->parentNode();
00248 return ret;
00249 }
00250
00251 int partNode::childCount() const {
00252 int count = 0;
00253 for ( partNode * child = firstChild() ; child ; child = child->nextSibling() )
00254 ++ count;
00255 return count;
00256 }
00257
00258 int partNode::totalChildCount() const {
00259 int count = 0;
00260 for ( partNode * child = firstChild() ; child ; child = child->nextSibling() ) {
00261 ++count;
00262 count += child->totalChildCount();
00263 }
00264 return count;
00265 }
00266
00267 QString partNode::contentTypeParameter( const char * name ) const {
00268 if ( !mDwPart || !mDwPart->hasHeaders() )
00269 return QString::null;
00270 DwHeaders & headers = mDwPart->Headers();
00271 if ( !headers.HasContentType() )
00272 return QString::null;
00273 DwString attr = name;
00274 attr.ConvertToLowerCase();
00275 for ( DwParameter * param = headers.ContentType().FirstParameter() ; param ; param = param->Next() ) {
00276 DwString this_attr = param->Attribute();
00277 this_attr.ConvertToLowerCase();
00278 if ( this_attr == attr )
00279 return QString::fromLatin1( param->Value().data(), param->Value().size() );
00280
00281 }
00282 return QString::null;
00283 }
00284
00285 KMMsgEncryptionState partNode::overallEncryptionState() const
00286 {
00287 KMMsgEncryptionState myState = KMMsgEncryptionStateUnknown;
00288 if( mEncryptionState == KMMsgNotEncrypted ) {
00289
00290 if( mChild )
00291 myState = mChild->overallEncryptionState();
00292 else
00293 myState = KMMsgNotEncrypted;
00294 }
00295 else {
00296 myState = mEncryptionState;
00297 }
00298
00299 if( mNext ) {
00300 KMMsgEncryptionState otherState = mNext->overallEncryptionState();
00301 switch( otherState ) {
00302 case KMMsgEncryptionStateUnknown:
00303 break;
00304 case KMMsgNotEncrypted:
00305 if( myState == KMMsgFullyEncrypted )
00306 myState = KMMsgPartiallyEncrypted;
00307 else if( myState != KMMsgPartiallyEncrypted )
00308 myState = KMMsgNotEncrypted;
00309 break;
00310 case KMMsgPartiallyEncrypted:
00311 myState = KMMsgPartiallyEncrypted;
00312 break;
00313 case KMMsgFullyEncrypted:
00314 if( myState != KMMsgFullyEncrypted )
00315 myState = KMMsgPartiallyEncrypted;
00316 break;
00317 case KMMsgEncryptionProblematic:
00318 break;
00319 }
00320 }
00321
00322
00323
00324 return myState;
00325 }
00326
00327
00328 KMMsgSignatureState partNode::overallSignatureState() const
00329 {
00330 KMMsgSignatureState myState = KMMsgSignatureStateUnknown;
00331 if( mSignatureState == KMMsgNotSigned ) {
00332
00333 if( mChild )
00334 myState = mChild->overallSignatureState();
00335 else
00336 myState = KMMsgNotSigned;
00337 }
00338 else {
00339 myState = mSignatureState;
00340 }
00341
00342 if( mNext ) {
00343 KMMsgSignatureState otherState = mNext->overallSignatureState();
00344 switch( otherState ) {
00345 case KMMsgSignatureStateUnknown:
00346 break;
00347 case KMMsgNotSigned:
00348 if( myState == KMMsgFullySigned )
00349 myState = KMMsgPartiallySigned;
00350 else if( myState != KMMsgPartiallySigned )
00351 myState = KMMsgNotSigned;
00352 break;
00353 case KMMsgPartiallySigned:
00354 myState = KMMsgPartiallySigned;
00355 break;
00356 case KMMsgFullySigned:
00357 if( myState != KMMsgFullySigned )
00358 myState = KMMsgPartiallySigned;
00359 break;
00360 case KMMsgEncryptionProblematic:
00361 break;
00362 }
00363 }
00364
00365
00366
00367 return myState;
00368 }
00369
00370 QCString partNode::path() const
00371 {
00372 if ( !parentNode() )
00373 return ':';
00374 const partNode * p = parentNode();
00375
00376
00377 int nth = 0;
00378 for ( const partNode * c = p->firstChild() ; c != this ; c = c->nextSibling() )
00379 if ( c->type() == type() && c->subType() == subType() )
00380 ++nth;
00381
00382 return p->path() + QCString().sprintf( ":%X/%X[%X]", type(), subType(), nth );
00383 }
00384
00385
00386 int partNode::nodeId() const
00387 {
00388 int curId = 0;
00389 partNode* rootNode = const_cast<partNode*>( this );
00390 while( rootNode->mRoot )
00391 rootNode = rootNode->mRoot;
00392 return rootNode->calcNodeIdOrFindNode( curId, this, 0, 0 );
00393 }
00394
00395
00396 partNode* partNode::findId( int id )
00397 {
00398 int curId = 0;
00399 partNode* rootNode = this;
00400 while( rootNode->mRoot )
00401 rootNode = rootNode->mRoot;
00402 partNode* foundNode;
00403 rootNode->calcNodeIdOrFindNode( curId, 0, id, &foundNode );
00404 return foundNode;
00405 }
00406
00407
00408 int partNode::calcNodeIdOrFindNode( int &curId, const partNode* findNode, int findId, partNode** foundNode )
00409 {
00410
00411
00412 curId++;
00413
00414 if( findNode && this == findNode )
00415 return curId;
00416
00417 if( foundNode && curId == findId ) {
00418 *foundNode = this;
00419 return curId;
00420 }
00421 if( mChild )
00422 {
00423 int res = mChild->calcNodeIdOrFindNode( curId, findNode, findId, foundNode );
00424 if (res != -1) return res;
00425 }
00426 if( mNext )
00427 return mNext->calcNodeIdOrFindNode( curId, findNode, findId, foundNode );
00428
00429 if( foundNode )
00430 *foundNode = 0;
00431 return -1;
00432 }
00433
00434
00435 partNode* partNode::findType( int type, int subType, bool deep, bool wide )
00436 {
00437 #ifndef NDEBUG
00438 DwString typeStr, subTypeStr;
00439 DwTypeEnumToStr( mType, typeStr );
00440 DwSubtypeEnumToStr( mSubType, subTypeStr );
00441 kdDebug(5006) << "partNode::findType() is looking at " << typeStr.c_str()
00442 << "/" << subTypeStr.c_str() << endl;
00443 #endif
00444 if( (mType != DwMime::kTypeUnknown)
00445 && ( (type == DwMime::kTypeUnknown)
00446 || (type == mType) )
00447 && ( (subType == DwMime::kSubtypeUnknown)
00448 || (subType == mSubType) ) )
00449 return this;
00450 if ( mChild && deep )
00451 return mChild->findType( type, subType, deep, wide );
00452 if ( mNext && wide )
00453 return mNext->findType( type, subType, deep, wide );
00454 return 0;
00455 }
00456
00457 partNode* partNode::findNodeForDwPart( DwBodyPart* part )
00458 {
00459 partNode* found = 0;
00460 if( kasciistricmp( dwPart()->partId(), part->partId() ) == 0 )
00461 return this;
00462 if( mChild )
00463 found = mChild->findNodeForDwPart( part );
00464 if( mNext && !found )
00465 found = mNext->findNodeForDwPart( part );
00466 return found;
00467 }
00468
00469 partNode* partNode::findTypeNot( int type, int subType, bool deep, bool wide )
00470 {
00471 if( (mType != DwMime::kTypeUnknown)
00472 && ( (type == DwMime::kTypeUnknown)
00473 || (type != mType) )
00474 && ( (subType == DwMime::kSubtypeUnknown)
00475 || (subType != mSubType) ) )
00476 return this;
00477 if ( mChild && deep )
00478 return mChild->findTypeNot( type, subType, deep, wide );
00479 if ( mNext && wide )
00480 return mNext->findTypeNot( type, subType, deep, wide );
00481 return 0;
00482 }
00483
00484 void partNode::fillMimePartTree( KMMimePartTreeItem* parentItem,
00485 KMMimePartTree* mimePartTree,
00486 QString labelDescr,
00487 QString labelCntType,
00488 QString labelEncoding,
00489 KIO::filesize_t size,
00490 bool revertOrder )
00491 {
00492 if( parentItem || mimePartTree ) {
00493
00494 if( mNext )
00495 mNext->fillMimePartTree( parentItem, mimePartTree,
00496 QString::null, QString::null, QString::null, 0,
00497 revertOrder );
00498
00499 QString cntDesc, cntType, cntEnc;
00500 KIO::filesize_t cntSize = 0;
00501
00502 if( labelDescr.isEmpty() ) {
00503 DwHeaders* headers = 0;
00504 if( mDwPart && mDwPart->hasHeaders() )
00505 headers = &mDwPart->Headers();
00506 if( headers && headers->HasSubject() )
00507 cntDesc = KMMsgBase::decodeRFC2047String( headers->Subject().AsString().c_str() );
00508 if( headers && headers->HasContentType()) {
00509 cntType = headers->ContentType().TypeStr().c_str();
00510 cntType += '/';
00511 cntType += headers->ContentType().SubtypeStr().c_str();
00512 }
00513 else
00514 cntType = "text/plain";
00515 if( cntDesc.isEmpty() )
00516 cntDesc = msgPart().contentDescription();
00517 if( cntDesc.isEmpty() )
00518 cntDesc = msgPart().name().stripWhiteSpace();
00519 if( cntDesc.isEmpty() )
00520 cntDesc = msgPart().fileName();
00521 if( cntDesc.isEmpty() ) {
00522 if( mRoot && mRoot->mRoot )
00523 cntDesc = i18n("internal part");
00524 else
00525 cntDesc = i18n("body part");
00526 }
00527 cntEnc = msgPart().contentTransferEncodingStr();
00528 if( mDwPart )
00529 cntSize = mDwPart->BodySize();
00530 } else {
00531 cntDesc = labelDescr;
00532 cntType = labelCntType;
00533 cntEnc = labelEncoding;
00534 cntSize = size;
00535 }
00536
00537 cntDesc.replace( QRegExp("\\n\\s*"), " " );
00538
00539 kdDebug(5006) << " Inserting one item into MimePartTree" << endl;
00540 kdDebug(5006) << " Content-Type: " << cntType << endl;
00541 if( parentItem )
00542 mMimePartTreeItem = new KMMimePartTreeItem( parentItem,
00543 this,
00544 cntDesc,
00545 cntType,
00546 cntEnc,
00547 cntSize,
00548 revertOrder );
00549 else if( mimePartTree )
00550 mMimePartTreeItem = new KMMimePartTreeItem( mimePartTree,
00551 this,
00552 cntDesc,
00553 cntType,
00554 cntEnc,
00555 cntSize );
00556 mMimePartTreeItem->setOpen( true );
00557 if( mChild )
00558 mChild->fillMimePartTree( mMimePartTreeItem, 0,
00559 QString::null, QString::null, QString::null, 0,
00560 revertOrder );
00561
00562 }
00563 }
00564
00565 void partNode::adjustDefaultType( partNode* node )
00566 {
00567
00568
00569
00570 if( node && DwMime::kTypeUnknown == node->type() ) {
00571 if( node->mRoot
00572 && DwMime::kTypeMultipart == node->mRoot->type()
00573 && DwMime::kSubtypeDigest == node->mRoot->subType() ) {
00574 node->setType( DwMime::kTypeMessage );
00575 node->setSubType( DwMime::kSubtypeRfc822 );
00576 }
00577 else
00578 {
00579 node->setType( DwMime::kTypeText );
00580 node->setSubType( DwMime::kSubtypePlain );
00581 }
00582 }
00583 }
00584
00585 bool partNode::isAttachment() const
00586 {
00587 if( !dwPart() )
00588 return false;
00589 if ( !dwPart()->hasHeaders() )
00590 return false;
00591 DwHeaders& headers = dwPart()->Headers();
00592 if( !headers.HasContentDisposition() )
00593 return false;
00594 return ( headers.ContentDisposition().DispositionType()
00595 == DwMime::kDispTypeAttachment );
00596 }
00597
00598 bool partNode::isHeuristicalAttachment() const {
00599 if ( isAttachment() )
00600 return true;
00601 const KMMessagePart & p = msgPart();
00602 return !p.fileName().isEmpty() || !p.name().isEmpty() ;
00603 }
00604
00605 partNode * partNode::next( bool allowChildren ) const {
00606 if ( allowChildren )
00607 if ( partNode * c = firstChild() )
00608 return c;
00609 if ( partNode * s = nextSibling() )
00610 return s;
00611 for ( partNode * p = parentNode() ; p ; p = p->parentNode() )
00612 if ( partNode * s = p->nextSibling() )
00613 return s;
00614 return 0;
00615 }
00616
00617 bool partNode::isFirstTextPart() const {
00618 if ( type() != DwMime::kTypeText )
00619 return false;
00620 const partNode * root = this;
00621
00622
00623 while ( const partNode * p = root->parentNode() ) {
00624 if ( p->type() == DwMime::kTypeMessage )
00625 break;
00626 else
00627 root = p;
00628 }
00629 for ( const partNode * n = root ; n ; n = n->next() )
00630 if ( n->type() == DwMime::kTypeText )
00631 return n == this;
00632 kdFatal() << "partNode::isFirstTextPart(): Didn't expect to end up here..." << endl;
00633 return false;
00634 }
00635
00636 bool partNode::hasContentDispositionInline() const
00637 {
00638 if( !dwPart() )
00639 return false;
00640 DwHeaders& headers = dwPart()->Headers();
00641 if( headers.HasContentDisposition() )
00642 return ( headers.ContentDisposition().DispositionType()
00643 == DwMime::kDispTypeInline );
00644 else
00645 return false;
00646 }
00647
00648 const QString& partNode::trueFromAddress() const
00649 {
00650 const partNode* node = this;
00651 while( node->mFromAddress.isEmpty() && node->mRoot )
00652 node = node->mRoot;
00653 return node->mFromAddress;
00654 }
00655
00656 KMail::Interface::BodyPartMemento * partNode::bodyPartMemento( const QCString & which ) const
00657 {
00658 if ( const KMReaderWin * r = reader() )
00659 return r->bodyPartMemento( this, which );
00660 else
00661 return internalBodyPartMemento( which );
00662 }
00663
00664 KMail::Interface::BodyPartMemento * partNode::internalBodyPartMemento( const QCString & which ) const
00665 {
00666 assert( !reader() );
00667
00668 const std::map<QCString,KMail::Interface::BodyPartMemento*>::const_iterator it = mBodyPartMementoMap.find( which.lower() );
00669 return it != mBodyPartMementoMap.end() ? it->second : 0 ;
00670 }
00671
00672 void partNode::setBodyPartMemento( const QCString & which, KMail::Interface::BodyPartMemento * memento )
00673 {
00674 if ( KMReaderWin * r = reader() )
00675 r->setBodyPartMemento( this, which, memento );
00676 else
00677 internalSetBodyPartMemento( which, memento );
00678 }
00679
00680 void partNode::internalSetBodyPartMemento( const QCString & which, KMail::Interface::BodyPartMemento * memento )
00681 {
00682 assert( !reader() );
00683
00684 const std::map<QCString,KMail::Interface::BodyPartMemento*>::iterator it = mBodyPartMementoMap.lower_bound( which.lower() );
00685 if ( it != mBodyPartMementoMap.end() && it->first == which.lower() ) {
00686 delete it->second;
00687 if ( memento )
00688 it->second = memento;
00689 else
00690 mBodyPartMementoMap.erase( it );
00691 } else {
00692 mBodyPartMementoMap.insert( it, std::make_pair( which.lower(), memento ) );
00693 }
00694 }
00695
00696 bool partNode::isDisplayedEmbedded() const
00697 {
00698 return mDisplayedEmbedded;
00699 }
00700
00701 void partNode::setDisplayedEmbedded( bool displayedEmbedded )
00702 {
00703 mDisplayedEmbedded = displayedEmbedded;
00704 }
00705
00706 QString partNode::asHREF( const QString &place ) const
00707 {
00708 return QString( "attachment:%1?place=%2" ).arg( nodeId() ).arg( place );
00709 }