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