kmail Library API Documentation

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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 #include "partNode.h"
00034 #include <klocale.h>
00035 #include <kdebug.h>
00036 #include "kmmimeparttree.h"
00037 #include <mimelib/utility.h>
00038 #include <qregexp.h>
00039 
00040 /*
00041   ===========================================================================
00042 
00043 
00044   S T A R T    O F     T E M P O R A R Y     M I M E     C O D E
00045 
00046 
00047   ===========================================================================
00048   N O T E :   The partNode structure will most likely be replaced by KMime.
00049   It's purpose: Speed optimization for KDE 3.   (khz, 28.11.01)
00050   ===========================================================================
00051 */
00052 
00053 partNode::partNode()
00054   : mRoot( 0 ), mNext( 0 ), mChild( 0 ),
00055     mWasProcessed( false ),
00056     mDwPart( 0 ),
00057     mType( DwMime::kTypeUnknown ),
00058     mSubType( DwMime::kSubtypeUnknown ),
00059     mCryptoType( CryptoTypeUnknown ),
00060     mEncryptionState( KMMsgNotEncrypted ),
00061     mSignatureState( KMMsgNotSigned ),
00062     mMsgPartOk( false ),
00063     mEncodedOk( false ),
00064     mDeleteDwBodyPart( false ),
00065     mMimePartTreeItem( 0 )
00066 {
00067   adjustDefaultType( this );
00068 }
00069 
00070 partNode::partNode( DwBodyPart* dwPart, int explicitType, int explicitSubType,
00071             bool deleteDwBodyPart )
00072   : mRoot( 0 ), mNext( 0 ), mChild( 0 ),
00073     mWasProcessed( false ),
00074     mDwPart( dwPart ),
00075     mCryptoType( CryptoTypeUnknown ),
00076     mEncryptionState( KMMsgNotEncrypted ),
00077     mSignatureState( KMMsgNotSigned ),
00078     mMsgPartOk( false ),
00079     mEncodedOk( false ),
00080     mDeleteDwBodyPart( deleteDwBodyPart ),
00081     mMimePartTreeItem( 0 )
00082 {
00083   if ( explicitType != DwMime::kTypeUnknown ) {
00084     mType    = explicitType;     // this happens e.g. for the Root Node
00085     mSubType = explicitSubType;  // representing the _whole_ message
00086   } else {
00087     kdDebug(5006) << "\n        partNode::partNode()      explicitType == DwMime::kTypeUnknown\n" << endl;
00088     if(dwPart && dwPart->hasHeaders() && dwPart->Headers().HasContentType()) {
00089       mType    = (!dwPart->Headers().ContentType().Type())?DwMime::kTypeUnknown:dwPart->Headers().ContentType().Type();
00090       mSubType = dwPart->Headers().ContentType().Subtype();
00091     } else {
00092       mType    = DwMime::kTypeUnknown;
00093       mSubType = DwMime::kSubtypeUnknown;
00094     }
00095   }
00096 #ifdef DEBUG
00097   {
00098     DwString type, subType;
00099     DwTypeEnumToStr( mType, type );
00100     DwSubtypeEnumToStr( mSubType, subType );
00101     kdDebug(5006) << "\npartNode::partNode()   " << type.c_str() << "/" << subType.c_str() << "\n" << endl;
00102   }
00103 #endif
00104 }
00105 
00106 partNode::partNode( bool deleteDwBodyPart, DwBodyPart* dwPart )
00107   : mRoot( 0 ), mNext( 0 ), mChild( 0 ),
00108     mWasProcessed( false ),
00109     mDwPart( dwPart ),
00110     mCryptoType( CryptoTypeUnknown ),
00111     mEncryptionState( KMMsgNotEncrypted ),
00112     mSignatureState( KMMsgNotSigned ),
00113     mMsgPartOk( false ),
00114     mEncodedOk( false ),
00115     mDeleteDwBodyPart( deleteDwBodyPart ),
00116     mMimePartTreeItem( 0 )
00117 {
00118   if ( dwPart && dwPart->hasHeaders() && dwPart->Headers().HasContentType() ) {
00119     mType    = (!dwPart->Headers().ContentType().Type())?DwMime::kTypeUnknown:dwPart->Headers().ContentType().Type();
00120     mSubType = dwPart->Headers().ContentType().Subtype();
00121   } else {
00122     mType    = DwMime::kTypeUnknown;
00123     mSubType = DwMime::kSubtypeUnknown;
00124   }
00125 }
00126 
00127 partNode::~partNode() {
00128   if( mDeleteDwBodyPart )
00129     delete mDwPart;
00130   delete mChild;
00131   delete mNext;
00132 }
00133 
00134 #ifndef NDEBUG
00135 void partNode::dump( int chars ) const {
00136   kdDebug(5006) << QString().fill( ' ', chars ) << "+ "
00137         << typeString() << '/' << subTypeString() << endl;
00138   if ( mChild )
00139     mChild->dump( chars + 1 );
00140   if ( mNext )
00141     mNext->dump( chars );
00142 }
00143 #else
00144 void partNode::dump( int ) const {}
00145 #endif
00146 
00147 const QCString & partNode::encodedBody() {
00148   if ( mEncodedOk )
00149     return mEncodedBody;
00150 
00151   if ( mDwPart )
00152     mEncodedBody = mDwPart->AsString().c_str();
00153   else
00154     mEncodedBody = 0;
00155   mEncodedOk = true;
00156   return mEncodedBody;
00157 }
00158 
00159 
00160 void partNode::buildObjectTree( bool processSiblings )
00161 {
00162     partNode* curNode = this;
00163     while( curNode && curNode->dwPart() ) {
00164         //dive into multipart messages
00165         while( DwMime::kTypeMultipart == curNode->type() ) {
00166             partNode * newNode = new partNode( curNode->dwPart()->Body().FirstBodyPart() );
00167         curNode->setFirstChild( newNode );
00168             curNode = newNode;
00169         }
00170         // go up in the tree until reaching a node with next
00171         // (or the last top-level node)
00172         while(     curNode
00173                && !(    curNode->dwPart()
00174                      && curNode->dwPart()->Next() ) ) {
00175             curNode = curNode->mRoot;
00176         }
00177         // we might have to leave when all children have been processed
00178         if( this == curNode && !processSiblings )
00179             return;
00180         // store next node
00181         if( curNode && curNode->dwPart() && curNode->dwPart()->Next() ) {
00182             partNode* nextNode = new partNode( curNode->dwPart()->Next() );
00183             curNode->setNext( nextNode );
00184         curNode = nextNode;
00185         } else
00186             curNode = 0;
00187     }
00188 }
00189 
00190 QCString partNode::typeString() const {
00191   DwString s;
00192   DwTypeEnumToStr( type(), s );
00193   return s.c_str();
00194 }
00195 
00196 QCString partNode::subTypeString() const {
00197   DwString s;
00198   DwSubtypeEnumToStr( subType(), s );
00199   return s.c_str();
00200 }
00201 
00202 partNode::CryptoType partNode::firstCryptoType() const
00203 {
00204     CryptoType ret = cryptoType();
00205     if(    (CryptoTypeUnknown == ret || CryptoTypeNone == ret)
00206         && mChild )
00207         ret = mChild->firstCryptoType();
00208     if(    (CryptoTypeUnknown == ret || CryptoTypeNone == ret)
00209         && mNext )
00210         ret = mNext->firstCryptoType();
00211     return ret;
00212 }
00213 
00214 
00215 KMMsgEncryptionState partNode::overallEncryptionState() const
00216 {
00217     KMMsgEncryptionState myState = KMMsgEncryptionStateUnknown;
00218     if( mEncryptionState == KMMsgNotEncrypted ) {
00219         // NOTE: children are tested ONLY when parent is not encrypted
00220         if( mChild )
00221             myState = mChild->overallEncryptionState();
00222         else
00223             myState = KMMsgNotEncrypted;
00224     }
00225     else { // part is partially or fully encrypted
00226         myState = mEncryptionState;
00227     }
00228     // siblings are tested always
00229     if( mNext ) {
00230         KMMsgEncryptionState otherState = mNext->overallEncryptionState();
00231         switch( otherState ) {
00232         case KMMsgEncryptionStateUnknown:
00233             break;
00234         case KMMsgNotEncrypted:
00235             if( myState == KMMsgFullyEncrypted )
00236                 myState = KMMsgPartiallyEncrypted;
00237             else if( myState != KMMsgPartiallyEncrypted )
00238                 myState = KMMsgNotEncrypted;
00239             break;
00240         case KMMsgPartiallyEncrypted:
00241             myState = KMMsgPartiallyEncrypted;
00242             break;
00243         case KMMsgFullyEncrypted:
00244             if( myState != KMMsgFullyEncrypted )
00245                 myState = KMMsgPartiallyEncrypted;
00246             break;
00247         case KMMsgEncryptionProblematic:
00248             break;
00249         }
00250     }
00251 
00252 //kdDebug(5006) << "\n\n  KMMsgEncryptionState: " << myState << endl;
00253 
00254     return myState;
00255 }
00256 
00257 
00258 KMMsgSignatureState  partNode::overallSignatureState() const
00259 {
00260     KMMsgSignatureState myState = KMMsgSignatureStateUnknown;
00261     if( mSignatureState == KMMsgNotSigned ) {
00262         // children are tested ONLY when parent is not signed
00263         if( mChild )
00264             myState = mChild->overallSignatureState();
00265         else
00266             myState = KMMsgNotSigned;
00267     }
00268     else { // part is partially or fully signed
00269         myState = mSignatureState;
00270     }
00271     // siblings are tested always
00272     if( mNext ) {
00273         KMMsgSignatureState otherState = mNext->overallSignatureState();
00274         switch( otherState ) {
00275         case KMMsgSignatureStateUnknown:
00276             break;
00277         case KMMsgNotSigned:
00278             if( myState == KMMsgFullySigned )
00279                 myState = KMMsgPartiallySigned;
00280             else if( myState != KMMsgPartiallySigned )
00281                 myState = KMMsgNotSigned;
00282             break;
00283         case KMMsgPartiallySigned:
00284             myState = KMMsgPartiallySigned;
00285             break;
00286         case KMMsgFullySigned:
00287             if( myState != KMMsgFullySigned )
00288                 myState = KMMsgPartiallySigned;
00289             break;
00290         case KMMsgEncryptionProblematic:
00291             break;
00292         }
00293     }
00294 
00295 //kdDebug(5006) << "\n\n  KMMsgSignatureState: " << myState << endl;
00296 
00297     return myState;
00298 }
00299 
00300 
00301 int partNode::nodeId()
00302 {
00303     int curId = 0;
00304     partNode* rootNode = this;
00305     while( rootNode->mRoot )
00306         rootNode = rootNode->mRoot;
00307     return rootNode->calcNodeIdOrFindNode( curId, this, 0, 0 );
00308 }
00309 
00310 
00311 partNode* partNode::findId( int id )
00312 {
00313     int curId = 0;
00314     partNode* rootNode = this;
00315     while( rootNode->mRoot )
00316         rootNode = rootNode->mRoot;
00317     partNode* foundNode;
00318     rootNode->calcNodeIdOrFindNode( curId, 0, id, &foundNode );
00319     return foundNode;
00320 }
00321 
00322 
00323 int partNode::calcNodeIdOrFindNode( int &curId, const partNode* findNode, int findId, partNode** foundNode )
00324 {
00325     // We use the same algorithm to determine the id of a node and
00326     //                           to find the node when id is known.
00327     curId++;
00328     // check for node ?
00329     if( findNode && this == findNode )
00330         return curId;
00331     // check for id ?
00332     if(  foundNode && curId == findId ) {
00333         *foundNode = this;
00334         return curId;
00335     }
00336     if( mChild )
00337     {
00338         int res = mChild->calcNodeIdOrFindNode( curId, findNode, findId, foundNode );
00339         if (res != -1) return res;
00340     }
00341     if( mNext )
00342         return mNext->calcNodeIdOrFindNode( curId, findNode, findId, foundNode );
00343 
00344     if(  foundNode )
00345         *foundNode = 0;
00346     return -1;
00347 }
00348 
00349 
00350 partNode* partNode::findType( int type, int subType, bool deep, bool wide )
00351 {
00352 #ifndef NDEBUG
00353   DwString typeStr, subTypeStr;
00354   DwTypeEnumToStr( mType, typeStr );
00355   DwSubtypeEnumToStr( mSubType, subTypeStr );
00356   kdDebug(5006) << "partNode::findType() is looking at " << typeStr.c_str()
00357                 << "/" << subTypeStr.c_str() << endl;
00358 #endif
00359     if(    (mType != DwMime::kTypeUnknown)
00360            && (    (type == DwMime::kTypeUnknown)
00361                    || (type == mType) )
00362            && (    (subType == DwMime::kSubtypeUnknown)
00363                    || (subType == mSubType) ) )
00364         return this;
00365     else if( mChild && deep )
00366         return mChild->findType( type, subType, deep, wide );
00367     else if( mNext && wide )
00368         return mNext->findType(  type, subType, deep, wide );
00369     else
00370         return 0;
00371 }
00372 
00373 partNode* partNode::findTypeNot( int type, int subType, bool deep, bool wide )
00374 {
00375     if(    (mType != DwMime::kTypeUnknown)
00376            && (    (type == DwMime::kTypeUnknown)
00377                    || (type != mType) )
00378            && (    (subType == DwMime::kSubtypeUnknown)
00379                    || (subType != mSubType) ) )
00380         return this;
00381     else if( mChild && deep )
00382         return mChild->findTypeNot( type, subType, deep, wide );
00383     else if( mNext && wide )
00384         return mNext->findTypeNot(  type, subType, deep, wide );
00385     else
00386         return 0;
00387 }
00388 
00389 void partNode::fillMimePartTree( KMMimePartTreeItem* parentItem,
00390                                  KMMimePartTree*     mimePartTree,
00391                                  QString labelDescr,
00392                                  QString labelCntType,
00393                                  QString labelEncoding,
00394                                  KIO::filesize_t size,
00395                                  bool revertOrder )
00396 {
00397   if( parentItem || mimePartTree ) {
00398 
00399     if( mNext )
00400         mNext->fillMimePartTree( parentItem, mimePartTree,
00401                                  QString::null, QString::null, QString::null, 0,
00402                                  revertOrder );
00403 
00404     QString cntDesc, cntType, cntEnc;
00405     KIO::filesize_t cntSize = 0;
00406 
00407     if( labelDescr.isEmpty() ) {
00408         DwHeaders* headers = 0;
00409         if( mDwPart && mDwPart->hasHeaders() )
00410           headers = &mDwPart->Headers();
00411         if( headers && headers->HasSubject() )
00412             cntDesc = KMMsgBase::decodeRFC2047String( headers->Subject().AsString().c_str() );
00413         if( headers && headers->HasContentType()) {
00414             cntType = headers->ContentType().TypeStr().c_str();
00415             cntType += '/';
00416             cntType += headers->ContentType().SubtypeStr().c_str();
00417         }
00418         else
00419             cntType = "text/plain";
00420         if( cntDesc.isEmpty() )
00421             cntDesc = msgPart().contentDescription();
00422         if( cntDesc.isEmpty() )
00423             cntDesc = msgPart().name().stripWhiteSpace();
00424         if( cntDesc.isEmpty() )
00425             cntDesc = msgPart().fileName();
00426         if( cntDesc.isEmpty() ) {
00427             if( mRoot && mRoot->mRoot )
00428                 cntDesc = i18n("internal part");
00429             else
00430                 cntDesc = i18n("body part");
00431         }
00432         cntEnc = msgPart().contentTransferEncodingStr();
00433         if( mDwPart )
00434             cntSize = mDwPart->BodySize();
00435     } else {
00436         cntDesc = labelDescr;
00437         cntType = labelCntType;
00438         cntEnc  = labelEncoding;
00439         cntSize = size;
00440     }
00441     // remove linebreak+whitespace from folded Content-Description
00442     cntDesc.replace( QRegExp("\\n\\s*"), " " );
00443 
00444 kdDebug(5006) << "      Inserting one item into MimePartTree" << endl;
00445 kdDebug(5006) << "                Content-Type: " << cntType << endl;
00446     if( parentItem )
00447       mMimePartTreeItem = new KMMimePartTreeItem( parentItem,
00448                                                   this,
00449                                                   cntDesc,
00450                                                   cntType,
00451                                                   cntEnc,
00452                                                   cntSize,
00453                                                   revertOrder );
00454     else if( mimePartTree )
00455       mMimePartTreeItem = new KMMimePartTreeItem( mimePartTree,
00456                                                   this,
00457                                                   cntDesc,
00458                                                   cntType,
00459                                                   cntEnc,
00460                                                   cntSize );
00461     mMimePartTreeItem->setOpen( true );
00462     if( mChild )
00463         mChild->fillMimePartTree( mMimePartTreeItem, 0,
00464                                   QString::null, QString::null, QString::null, 0,
00465                                   revertOrder );
00466 
00467   }
00468 }
00469 
00470 void partNode::adjustDefaultType( partNode* node )
00471 {
00472     // Only bodies of  'Multipart/Digest'  objects have
00473     // default type 'Message/RfC822'.  All other bodies
00474     // have default type 'Text/Plain'  (khz, 5.12.2001)
00475     if( node && DwMime::kTypeUnknown == node->type() ) {
00476         if(    node->mRoot
00477                && DwMime::kTypeMultipart == node->mRoot->type()
00478                && DwMime::kSubtypeDigest == node->mRoot->subType() ) {
00479             node->setType(    DwMime::kTypeMessage   );
00480             node->setSubType( DwMime::kSubtypeRfc822 );
00481         }
00482         else
00483             {
00484                 node->setType(    DwMime::kTypeText     );
00485                 node->setSubType( DwMime::kSubtypePlain );
00486             }
00487     }
00488 }
00489 
00490 bool partNode::isAttachment() const
00491 {
00492   if( !dwPart() )
00493     return false;
00494   DwHeaders& headers = dwPart()->Headers();
00495   if( headers.HasContentDisposition() )
00496     return ( headers.ContentDisposition().DispositionType()
00497              == DwMime::kDispTypeAttachment );
00498   else
00499     return false;
00500 }
00501 
00502 bool partNode::hasContentDispositionInline() const
00503 {
00504   if( !dwPart() )
00505     return false;
00506   DwHeaders& headers = dwPart()->Headers();
00507   if( headers.HasContentDisposition() )
00508     return ( headers.ContentDisposition().DispositionType()
00509              == DwMime::kDispTypeInline );
00510   else
00511     return false;
00512 }
00513 
00514 const QString& partNode::trueFromAddress() const
00515 {
00516   const partNode* node = this;
00517   while( node->mFromAddress.isEmpty() && node->mRoot )
00518     node = node->mRoot;
00519   return node->mFromAddress;
00520 }
KDE Logo
This file is part of the documentation for kmail Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat May 1 11:37:35 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003