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