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