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