kmail

partNode.cpp

00001 /* -*- c++ -*-
00002     partNode.cpp A node in a MIME tree.
00003 
00004     This file is part of KMail, the KDE mail client.
00005     Copyright (c) 2002 Klar�lvdalens Datakonsult AB
00006 
00007     KMail is free software; you can redistribute it and/or modify it
00008     under the terms of the GNU General Public License, version 2, as
00009     published by the Free Software Foundation.
00010 
00011     KMail is distributed in the hope that it will be useful, but
00012     WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00019 
00020     In addition, as a special exception, the copyright holders give
00021     permission to link the code of this program with any edition of
00022     the Qt library by Trolltech AS, Norway (or with modified versions
00023     of Qt that use the same license as Qt), and distribute linked
00024     combinations including the two.  You must obey the GNU General
00025     Public License in all respects for all of the code used other than
00026     Qt.  If you modify this file, you may extend this exception to
00027     your version of the file, but you are not obligated to do so.  If
00028     you do not wish to do so, delete this exception statement from
00029     your version.
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   S T A R T    O F     T E M P O R A R Y     M I M E     C O D E
00050 
00051 
00052   ===========================================================================
00053   N O T E :   The partNode structure will most likely be replaced by KMime.
00054   It's purpose: Speed optimization for KDE 3.   (khz, 28.11.01)
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;     // this happens e.g. for the Root Node
00092     mSubType = explicitSubType;  // representing the _whole_ message
00093   } else {
00094 //    kdDebug(5006) << "\n        partNode::partNode()      explicitType == DwMime::kTypeUnknown\n" << endl;
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   // we don't want to treat the top-level part special. mimelib does
00126   // (Message vs. BodyPart, with common base class Entity). But we
00127   // used DwBodyPart, not DwEntiy everywhere. *shrug*. DwStrings are
00128   // subscrib-shared, so we just force mimelib to parse the whole mail
00129   // as just another DwBodyPart...
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         //dive into multipart messages
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         // go up in the tree until reaching a node with next
00210         // (or the last top-level node)
00211         while(     curNode
00212                && !(    curNode->dwPart()
00213                      && curNode->dwPart()->Next() ) ) {
00214             curNode = curNode->mRoot;
00215         }
00216         // we might have to leave when all children have been processed
00217         if( this == curNode && !processSiblings )
00218             return;
00219         // store next node
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(); // what a braindead design!
00275     if ( this_attr == attr )
00276       return QString::fromLatin1( param->Value().data(), param->Value().size() );
00277     // warning: misses rfc2231 handling!
00278   }
00279   return QString::null;
00280 }
00281 
00282 KMMsgEncryptionState partNode::overallEncryptionState() const
00283 {
00284     KMMsgEncryptionState myState = KMMsgEncryptionStateUnknown;
00285     if( mEncryptionState == KMMsgNotEncrypted ) {
00286         // NOTE: children are tested ONLY when parent is not encrypted
00287         if( mChild )
00288             myState = mChild->overallEncryptionState();
00289         else
00290             myState = KMMsgNotEncrypted;
00291     }
00292     else { // part is partially or fully encrypted
00293         myState = mEncryptionState;
00294     }
00295     // siblings are tested always
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 //kdDebug(5006) << "\n\n  KMMsgEncryptionState: " << myState << endl;
00320 
00321     return myState;
00322 }
00323 
00324 
00325 KMMsgSignatureState  partNode::overallSignatureState() const
00326 {
00327     KMMsgSignatureState myState = KMMsgSignatureStateUnknown;
00328     if( mSignatureState == KMMsgNotSigned ) {
00329         // children are tested ONLY when parent is not signed
00330         if( mChild )
00331             myState = mChild->overallSignatureState();
00332         else
00333             myState = KMMsgNotSigned;
00334     }
00335     else { // part is partially or fully signed
00336         myState = mSignatureState;
00337     }
00338     // siblings are tested always
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 //kdDebug(5006) << "\n\n  KMMsgSignatureState: " << myState << endl;
00363 
00364     return myState;
00365 }
00366 
00367 QCString partNode::path() const
00368 {
00369     if ( !parentNode() )
00370         return ':';
00371     const partNode * p = parentNode();
00372 
00373     // count number of siblings with the same type as us:
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     // We use the same algorithm to determine the id of a node and
00408     //                           to find the node when id is known.
00409     curId++;
00410     // check for node ?
00411     if( findNode && this == findNode )
00412         return curId;
00413     // check for id ?
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     // remove linebreak+whitespace from folded Content-Description
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     // Only bodies of  'Multipart/Digest'  objects have
00565     // default type 'Message/RfC822'.  All other bodies
00566     // have default type 'Text/Plain'  (khz, 5.12.2001)
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   // go up until we reach the root node of a message (of the actual message or
00619   // of an attached message)
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; // make comiler happy
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 }
KDE Home | KDE Accessibility Home | Description of Access Keys