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