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