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 Wed Jul 28 23:58:04 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003