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 {
00073 adjustDefaultType( this );
00074 }
00075
00076 partNode::partNode( KMReaderWin * win, DwBodyPart* dwPart, int explicitType, int explicitSubType,
00077 bool deleteDwBodyPart )
00078 : mRoot( 0 ), mNext( 0 ), mChild( 0 ),
00079 mWasProcessed( false ),
00080 mDwPart( dwPart ),
00081 mEncryptionState( KMMsgNotEncrypted ),
00082 mSignatureState( KMMsgNotSigned ),
00083 mMsgPartOk( false ),
00084 mEncodedOk( false ),
00085 mDeleteDwBodyPart( deleteDwBodyPart ),
00086 mMimePartTreeItem( 0 ),
00087 mBodyPartMementoMap(),
00088 mReader( win )
00089 {
00090 if ( explicitType != DwMime::kTypeUnknown ) {
00091 mType = explicitType;
00092 mSubType = explicitSubType;
00093 } else {
00094
00095 if(dwPart && dwPart->hasHeaders() && dwPart->Headers().HasContentType()) {
00096 mType = (!dwPart->Headers().ContentType().Type())?DwMime::kTypeUnknown:dwPart->Headers().ContentType().Type();
00097 mSubType = dwPart->Headers().ContentType().Subtype();
00098 } else {
00099 mType = DwMime::kTypeUnknown;
00100 mSubType = DwMime::kSubtypeUnknown;
00101 }
00102 }
00103 #ifdef DEBUG
00104 {
00105 DwString type, subType;
00106 DwTypeEnumToStr( mType, type );
00107 DwSubtypeEnumToStr( mSubType, subType );
00108 kdDebug(5006) << "\npartNode::partNode() " << type.c_str() << "/" << subType.c_str() << "\n" << endl;
00109 }
00110 #endif
00111 }
00112
00113 partNode * partNode::fromMessage( const KMMessage * msg, KMReaderWin * win ) {
00114 if ( !msg )
00115 return 0;
00116
00117 int mainType = msg->type();
00118 int mainSubType = msg->subtype();
00119 if( (DwMime::kTypeNull == mainType)
00120 || (DwMime::kTypeUnknown == mainType) ){
00121 mainType = DwMime::kTypeText;
00122 mainSubType = DwMime::kSubtypePlain;
00123 }
00124
00125
00126
00127
00128
00129
00130 DwBodyPart * mainBody = new DwBodyPart( *msg->getTopLevelPart() );
00131
00132 partNode * root = new partNode( win, mainBody, mainType, mainSubType, true );
00133 root->buildObjectTree();
00134
00135 root->setFromAddress( msg->from() );
00136 root->dump();
00137 return root;
00138 }
00139
00140 partNode::partNode( bool deleteDwBodyPart, DwBodyPart* dwPart )
00141 : mRoot( 0 ), mNext( 0 ), mChild( 0 ),
00142 mWasProcessed( false ),
00143 mDwPart( dwPart ),
00144 mEncryptionState( KMMsgNotEncrypted ),
00145 mSignatureState( KMMsgNotSigned ),
00146 mMsgPartOk( false ),
00147 mEncodedOk( false ),
00148 mDeleteDwBodyPart( deleteDwBodyPart ),
00149 mMimePartTreeItem( 0 ),
00150 mBodyPartMementoMap(),
00151 mReader( 0 )
00152 {
00153 if ( dwPart && dwPart->hasHeaders() && dwPart->Headers().HasContentType() ) {
00154 mType = (!dwPart->Headers().ContentType().Type())?DwMime::kTypeUnknown:dwPart->Headers().ContentType().Type();
00155 mSubType = dwPart->Headers().ContentType().Subtype();
00156 } else {
00157 mType = DwMime::kTypeUnknown;
00158 mSubType = DwMime::kSubtypeUnknown;
00159 }
00160 }
00161
00162 partNode::~partNode() {
00163 if( mDeleteDwBodyPart )
00164 delete mDwPart;
00165 mDwPart = 0;
00166 delete mChild; mChild = 0;
00167 delete mNext; mNext = 0;
00168 for ( std::map<QCString,KMail::Interface::BodyPartMemento*>::const_iterator it = mBodyPartMementoMap.begin(), end = mBodyPartMementoMap.end() ; it != end ; ++it )
00169 delete it->second;
00170 mBodyPartMementoMap.clear();
00171 }
00172
00173 #ifndef NDEBUG
00174 void partNode::dump( int chars ) const {
00175 kdDebug(5006) << QString().fill( ' ', chars ) << "+ "
00176 << typeString() << '/' << subTypeString() << endl;
00177 if ( mChild )
00178 mChild->dump( chars + 1 );
00179 if ( mNext )
00180 mNext->dump( chars );
00181 }
00182 #else
00183 void partNode::dump( int ) const {}
00184 #endif
00185
00186 const QCString & partNode::encodedBody() {
00187 if ( mEncodedOk )
00188 return mEncodedBody;
00189
00190 if ( mDwPart )
00191 mEncodedBody = KMail::Util::CString( mDwPart->Body().AsString() );
00192 else
00193 mEncodedBody = 0;
00194 mEncodedOk = true;
00195 return mEncodedBody;
00196 }
00197
00198
00199 void partNode::buildObjectTree( bool processSiblings )
00200 {
00201 partNode* curNode = this;
00202 while( curNode && curNode->dwPart() ) {
00203
00204 while( DwMime::kTypeMultipart == curNode->type() ) {
00205 partNode * newNode = new partNode( mReader, curNode->dwPart()->Body().FirstBodyPart() );
00206 curNode->setFirstChild( newNode );
00207 curNode = newNode;
00208 }
00209
00210
00211 while( curNode
00212 && !( curNode->dwPart()
00213 && curNode->dwPart()->Next() ) ) {
00214 curNode = curNode->mRoot;
00215 }
00216
00217 if( this == curNode && !processSiblings )
00218 return;
00219
00220 if( curNode && curNode->dwPart() && curNode->dwPart()->Next() ) {
00221 partNode* nextNode = new partNode( mReader, curNode->dwPart()->Next() );
00222 curNode->setNext( nextNode );
00223 curNode = nextNode;
00224 } else
00225 curNode = 0;
00226 }
00227 }
00228
00229 QCString partNode::typeString() const {
00230 DwString s;
00231 DwTypeEnumToStr( type(), s );
00232 return s.c_str();
00233 }
00234
00235 QCString partNode::subTypeString() const {
00236 DwString s;
00237 DwSubtypeEnumToStr( subType(), s );
00238 return s.c_str();
00239 }
00240
00241 int partNode::childCount() const {
00242 int count = 0;
00243 for ( partNode * child = firstChild() ; child ; child = child->nextSibling() )
00244 ++ count;
00245 return count;
00246 }
00247
00248 QString partNode::contentTypeParameter( const char * name ) const {
00249 if ( !mDwPart || !mDwPart->hasHeaders() )
00250 return QString::null;
00251 DwHeaders & headers = mDwPart->Headers();
00252 if ( !headers.HasContentType() )
00253 return QString::null;
00254 DwString attr = name;
00255 attr.ConvertToLowerCase();
00256 for ( DwParameter * param = headers.ContentType().FirstParameter() ; param ; param = param->Next() ) {
00257 DwString this_attr = param->Attribute();
00258 this_attr.ConvertToLowerCase();
00259 if ( this_attr == attr )
00260 return QString::fromLatin1( param->Value().data(), param->Value().size() );
00261
00262 }
00263 return QString::null;
00264 }
00265
00266 KMMsgEncryptionState partNode::overallEncryptionState() const
00267 {
00268 KMMsgEncryptionState myState = KMMsgEncryptionStateUnknown;
00269 if( mEncryptionState == KMMsgNotEncrypted ) {
00270
00271 if( mChild )
00272 myState = mChild->overallEncryptionState();
00273 else
00274 myState = KMMsgNotEncrypted;
00275 }
00276 else {
00277 myState = mEncryptionState;
00278 }
00279
00280 if( mNext ) {
00281 KMMsgEncryptionState otherState = mNext->overallEncryptionState();
00282 switch( otherState ) {
00283 case KMMsgEncryptionStateUnknown:
00284 break;
00285 case KMMsgNotEncrypted:
00286 if( myState == KMMsgFullyEncrypted )
00287 myState = KMMsgPartiallyEncrypted;
00288 else if( myState != KMMsgPartiallyEncrypted )
00289 myState = KMMsgNotEncrypted;
00290 break;
00291 case KMMsgPartiallyEncrypted:
00292 myState = KMMsgPartiallyEncrypted;
00293 break;
00294 case KMMsgFullyEncrypted:
00295 if( myState != KMMsgFullyEncrypted )
00296 myState = KMMsgPartiallyEncrypted;
00297 break;
00298 case KMMsgEncryptionProblematic:
00299 break;
00300 }
00301 }
00302
00303
00304
00305 return myState;
00306 }
00307
00308
00309 KMMsgSignatureState partNode::overallSignatureState() const
00310 {
00311 KMMsgSignatureState myState = KMMsgSignatureStateUnknown;
00312 if( mSignatureState == KMMsgNotSigned ) {
00313
00314 if( mChild )
00315 myState = mChild->overallSignatureState();
00316 else
00317 myState = KMMsgNotSigned;
00318 }
00319 else {
00320 myState = mSignatureState;
00321 }
00322
00323 if( mNext ) {
00324 KMMsgSignatureState otherState = mNext->overallSignatureState();
00325 switch( otherState ) {
00326 case KMMsgSignatureStateUnknown:
00327 break;
00328 case KMMsgNotSigned:
00329 if( myState == KMMsgFullySigned )
00330 myState = KMMsgPartiallySigned;
00331 else if( myState != KMMsgPartiallySigned )
00332 myState = KMMsgNotSigned;
00333 break;
00334 case KMMsgPartiallySigned:
00335 myState = KMMsgPartiallySigned;
00336 break;
00337 case KMMsgFullySigned:
00338 if( myState != KMMsgFullySigned )
00339 myState = KMMsgPartiallySigned;
00340 break;
00341 case KMMsgEncryptionProblematic:
00342 break;
00343 }
00344 }
00345
00346
00347
00348 return myState;
00349 }
00350
00351 QCString partNode::path() const
00352 {
00353 if ( !parentNode() )
00354 return ':';
00355 const partNode * p = parentNode();
00356
00357
00358 int nth = 0;
00359 for ( const partNode * c = p->firstChild() ; c != this ; c = c->nextSibling() )
00360 if ( c->type() == type() && c->subType() == subType() )
00361 ++nth;
00362
00363 return p->path() + QCString().sprintf( ":%X/%X[%X]", type(), subType(), nth );
00364 }
00365
00366
00367 int partNode::nodeId() const
00368 {
00369 int curId = 0;
00370 partNode* rootNode = const_cast<partNode*>( this );
00371 while( rootNode->mRoot )
00372 rootNode = rootNode->mRoot;
00373 return rootNode->calcNodeIdOrFindNode( curId, this, 0, 0 );
00374 }
00375
00376
00377 partNode* partNode::findId( int id )
00378 {
00379 int curId = 0;
00380 partNode* rootNode = this;
00381 while( rootNode->mRoot )
00382 rootNode = rootNode->mRoot;
00383 partNode* foundNode;
00384 rootNode->calcNodeIdOrFindNode( curId, 0, id, &foundNode );
00385 return foundNode;
00386 }
00387
00388
00389 int partNode::calcNodeIdOrFindNode( int &curId, const partNode* findNode, int findId, partNode** foundNode )
00390 {
00391
00392
00393 curId++;
00394
00395 if( findNode && this == findNode )
00396 return curId;
00397
00398 if( foundNode && curId == findId ) {
00399 *foundNode = this;
00400 return curId;
00401 }
00402 if( mChild )
00403 {
00404 int res = mChild->calcNodeIdOrFindNode( curId, findNode, findId, foundNode );
00405 if (res != -1) return res;
00406 }
00407 if( mNext )
00408 return mNext->calcNodeIdOrFindNode( curId, findNode, findId, foundNode );
00409
00410 if( foundNode )
00411 *foundNode = 0;
00412 return -1;
00413 }
00414
00415
00416 partNode* partNode::findType( int type, int subType, bool deep, bool wide )
00417 {
00418 #ifndef NDEBUG
00419 DwString typeStr, subTypeStr;
00420 DwTypeEnumToStr( mType, typeStr );
00421 DwSubtypeEnumToStr( mSubType, subTypeStr );
00422 kdDebug(5006) << "partNode::findType() is looking at " << typeStr.c_str()
00423 << "/" << subTypeStr.c_str() << endl;
00424 #endif
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 kdDebug(5006) << " Inserting one item into MimePartTree" << endl;
00521 kdDebug(5006) << " Content-Type: " << cntType << endl;
00522 if( parentItem )
00523 mMimePartTreeItem = new KMMimePartTreeItem( parentItem,
00524 this,
00525 cntDesc,
00526 cntType,
00527 cntEnc,
00528 cntSize,
00529 revertOrder );
00530 else if( mimePartTree )
00531 mMimePartTreeItem = new KMMimePartTreeItem( mimePartTree,
00532 this,
00533 cntDesc,
00534 cntType,
00535 cntEnc,
00536 cntSize );
00537 mMimePartTreeItem->setOpen( true );
00538 if( mChild )
00539 mChild->fillMimePartTree( mMimePartTreeItem, 0,
00540 QString::null, QString::null, QString::null, 0,
00541 revertOrder );
00542
00543 }
00544 }
00545
00546 void partNode::adjustDefaultType( partNode* node )
00547 {
00548
00549
00550
00551 if( node && DwMime::kTypeUnknown == node->type() ) {
00552 if( node->mRoot
00553 && DwMime::kTypeMultipart == node->mRoot->type()
00554 && DwMime::kSubtypeDigest == node->mRoot->subType() ) {
00555 node->setType( DwMime::kTypeMessage );
00556 node->setSubType( DwMime::kSubtypeRfc822 );
00557 }
00558 else
00559 {
00560 node->setType( DwMime::kTypeText );
00561 node->setSubType( DwMime::kSubtypePlain );
00562 }
00563 }
00564 }
00565
00566 bool partNode::isAttachment() const
00567 {
00568 if( !dwPart() )
00569 return false;
00570 if ( !dwPart()->hasHeaders() )
00571 return false;
00572 DwHeaders& headers = dwPart()->Headers();
00573 if( !headers.HasContentDisposition() )
00574 return false;
00575 return ( headers.ContentDisposition().DispositionType()
00576 == DwMime::kDispTypeAttachment );
00577 }
00578
00579 bool partNode::isHeuristicalAttachment() const {
00580 if ( isAttachment() )
00581 return true;
00582 const KMMessagePart & p = msgPart();
00583 return !p.fileName().isEmpty() || !p.name().isEmpty() ;
00584 }
00585
00586 partNode * partNode::next( bool allowChildren ) const {
00587 if ( allowChildren )
00588 if ( partNode * c = firstChild() )
00589 return c;
00590 if ( partNode * s = nextSibling() )
00591 return s;
00592 for ( partNode * p = parentNode() ; p ; p = p->parentNode() )
00593 if ( partNode * s = p->nextSibling() )
00594 return s;
00595 return 0;
00596 }
00597
00598 bool partNode::isFirstTextPart() const {
00599 if ( type() != DwMime::kTypeText )
00600 return false;
00601 const partNode * root = this;
00602
00603
00604 while ( const partNode * p = root->parentNode() ) {
00605 if ( p->type() == DwMime::kTypeMessage )
00606 break;
00607 else
00608 root = p;
00609 }
00610 for ( const partNode * n = root ; n ; n = n->next() )
00611 if ( n->type() == DwMime::kTypeText )
00612 return n == this;
00613 kdFatal() << "partNode::isFirstTextPart(): Didn't expect to end up here..." << endl;
00614 return false;
00615 }
00616
00617 bool partNode::hasContentDispositionInline() const
00618 {
00619 if( !dwPart() )
00620 return false;
00621 DwHeaders& headers = dwPart()->Headers();
00622 if( headers.HasContentDisposition() )
00623 return ( headers.ContentDisposition().DispositionType()
00624 == DwMime::kDispTypeInline );
00625 else
00626 return false;
00627 }
00628
00629 const QString& partNode::trueFromAddress() const
00630 {
00631 const partNode* node = this;
00632 while( node->mFromAddress.isEmpty() && node->mRoot )
00633 node = node->mRoot;
00634 return node->mFromAddress;
00635 }
00636
00637 KMail::Interface::BodyPartMemento * partNode::bodyPartMemento( const QCString & which ) const
00638 {
00639 if ( const KMReaderWin * r = reader() )
00640 return r->bodyPartMemento( this, which );
00641 else
00642 return internalBodyPartMemento( which );
00643 }
00644
00645 KMail::Interface::BodyPartMemento * partNode::internalBodyPartMemento( const QCString & which ) const
00646 {
00647 assert( !reader() );
00648
00649 const std::map<QCString,KMail::Interface::BodyPartMemento*>::const_iterator it = mBodyPartMementoMap.find( which.lower() );
00650 return it != mBodyPartMementoMap.end() ? it->second : 0 ;
00651 }
00652
00653 void partNode::setBodyPartMemento( const QCString & which, KMail::Interface::BodyPartMemento * memento )
00654 {
00655 if ( KMReaderWin * r = reader() )
00656 r->setBodyPartMemento( this, which, memento );
00657 else
00658 internalSetBodyPartMemento( which, memento );
00659 }
00660
00661 void partNode::internalSetBodyPartMemento( const QCString & which, KMail::Interface::BodyPartMemento * memento )
00662 {
00663 assert( !reader() );
00664
00665 const std::map<QCString,KMail::Interface::BodyPartMemento*>::iterator it = mBodyPartMementoMap.lower_bound( which.lower() );
00666 if ( it != mBodyPartMementoMap.end() && it->first == which.lower() ) {
00667 delete it->second;
00668 if ( memento )
00669 it->second = memento;
00670 else
00671 mBodyPartMementoMap.erase( it );
00672 } else {
00673 mBodyPartMementoMap.insert( it, std::make_pair( which.lower(), memento ) );
00674 }
00675 }