00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
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 #include <kasciistricmp.h>
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054 partNode::partNode()
00055 : mRoot( 0 ), mNext( 0 ), mChild( 0 ),
00056 mWasProcessed( false ),
00057 mDwPart( 0 ),
00058 mType( DwMime::kTypeUnknown ),
00059 mSubType( DwMime::kSubtypeUnknown ),
00060 mEncryptionState( KMMsgNotEncrypted ),
00061 mSignatureState( KMMsgNotSigned ),
00062 mMsgPartOk( false ),
00063 mEncodedOk( false ),
00064 mDeleteDwBodyPart( false ),
00065 mMimePartTreeItem( 0 ),
00066 mBodyPartMemento( 0 )
00067 {
00068 adjustDefaultType( this );
00069 }
00070
00071 partNode::partNode( DwBodyPart* dwPart, int explicitType, int explicitSubType,
00072 bool deleteDwBodyPart )
00073 : mRoot( 0 ), mNext( 0 ), mChild( 0 ),
00074 mWasProcessed( false ),
00075 mDwPart( dwPart ),
00076 mEncryptionState( KMMsgNotEncrypted ),
00077 mSignatureState( KMMsgNotSigned ),
00078 mMsgPartOk( false ),
00079 mEncodedOk( false ),
00080 mDeleteDwBodyPart( deleteDwBodyPart ),
00081 mMimePartTreeItem( 0 ),
00082 mBodyPartMemento( 0 )
00083 {
00084 if ( explicitType != DwMime::kTypeUnknown ) {
00085 mType = explicitType;
00086 mSubType = explicitSubType;
00087 } else {
00088
00089 if(dwPart && dwPart->hasHeaders() && dwPart->Headers().HasContentType()) {
00090 mType = (!dwPart->Headers().ContentType().Type())?DwMime::kTypeUnknown:dwPart->Headers().ContentType().Type();
00091 mSubType = dwPart->Headers().ContentType().Subtype();
00092 } else {
00093 mType = DwMime::kTypeUnknown;
00094 mSubType = DwMime::kSubtypeUnknown;
00095 }
00096 }
00097 #ifdef DEBUG
00098 {
00099 DwString type, subType;
00100 DwTypeEnumToStr( mType, type );
00101 DwSubtypeEnumToStr( mSubType, subType );
00102 kdDebug(5006) << "\npartNode::partNode() " << type.c_str() << "/" << subType.c_str() << "\n" << endl;
00103 }
00104 #endif
00105 }
00106
00107 partNode * partNode::fromMessage( const KMMessage * msg ) {
00108 if ( !msg )
00109 return 0;
00110
00111 int mainType = msg->type();
00112 int mainSubType = msg->subtype();
00113 if( (DwMime::kTypeNull == mainType)
00114 || (DwMime::kTypeUnknown == mainType) ){
00115 mainType = DwMime::kTypeText;
00116 mainSubType = DwMime::kSubtypePlain;
00117 }
00118
00119
00120
00121
00122
00123
00124 DwBodyPart * mainBody = new DwBodyPart( *msg->getTopLevelPart() );
00125
00126 partNode * root = new partNode( mainBody, mainType, mainSubType, true );
00127 root->buildObjectTree();
00128
00129 root->setFromAddress( msg->from() );
00130 root->dump();
00131 return root;
00132 }
00133
00134 partNode::partNode( bool deleteDwBodyPart, DwBodyPart* dwPart )
00135 : mRoot( 0 ), mNext( 0 ), mChild( 0 ),
00136 mWasProcessed( false ),
00137 mDwPart( dwPart ),
00138 mEncryptionState( KMMsgNotEncrypted ),
00139 mSignatureState( KMMsgNotSigned ),
00140 mMsgPartOk( false ),
00141 mEncodedOk( false ),
00142 mDeleteDwBodyPart( deleteDwBodyPart ),
00143 mMimePartTreeItem( 0 ),
00144 mBodyPartMemento( 0 )
00145 {
00146 if ( dwPart && dwPart->hasHeaders() && dwPart->Headers().HasContentType() ) {
00147 mType = (!dwPart->Headers().ContentType().Type())?DwMime::kTypeUnknown:dwPart->Headers().ContentType().Type();
00148 mSubType = dwPart->Headers().ContentType().Subtype();
00149 } else {
00150 mType = DwMime::kTypeUnknown;
00151 mSubType = DwMime::kSubtypeUnknown;
00152 }
00153 }
00154
00155 partNode::~partNode() {
00156 if( mDeleteDwBodyPart )
00157 delete mDwPart;
00158 mDwPart = 0;
00159 delete mChild; mChild = 0;
00160 delete mNext; mNext = 0;
00161 delete mBodyPartMemento; mBodyPartMemento = 0;
00162 }
00163
00164 #ifndef NDEBUG
00165 void partNode::dump( int chars ) const {
00166 kdDebug(5006) << QString().fill( ' ', chars ) << "+ "
00167 << typeString() << '/' << subTypeString() << endl;
00168 if ( mChild )
00169 mChild->dump( chars + 1 );
00170 if ( mNext )
00171 mNext->dump( chars );
00172 }
00173 #else
00174 void partNode::dump( int ) const {}
00175 #endif
00176
00177 const QCString & partNode::encodedBody() {
00178 if ( mEncodedOk )
00179 return mEncodedBody;
00180
00181 if ( mDwPart )
00182 mEncodedBody = mDwPart->AsString().c_str();
00183 else
00184 mEncodedBody = 0;
00185 mEncodedOk = true;
00186 return mEncodedBody;
00187 }
00188
00189
00190 void partNode::buildObjectTree( bool processSiblings )
00191 {
00192 partNode* curNode = this;
00193 while( curNode && curNode->dwPart() ) {
00194
00195 while( DwMime::kTypeMultipart == curNode->type() ) {
00196 partNode * newNode = new partNode( curNode->dwPart()->Body().FirstBodyPart() );
00197 curNode->setFirstChild( newNode );
00198 curNode = newNode;
00199 }
00200
00201
00202 while( curNode
00203 && !( curNode->dwPart()
00204 && curNode->dwPart()->Next() ) ) {
00205 curNode = curNode->mRoot;
00206 }
00207
00208 if( this == curNode && !processSiblings )
00209 return;
00210
00211 if( curNode && curNode->dwPart() && curNode->dwPart()->Next() ) {
00212 partNode* nextNode = new partNode( curNode->dwPart()->Next() );
00213 curNode->setNext( nextNode );
00214 curNode = nextNode;
00215 } else
00216 curNode = 0;
00217 }
00218 }
00219
00220 QCString partNode::typeString() const {
00221 DwString s;
00222 DwTypeEnumToStr( type(), s );
00223 return s.c_str();
00224 }
00225
00226 QCString partNode::subTypeString() const {
00227 DwString s;
00228 DwSubtypeEnumToStr( subType(), s );
00229 return s.c_str();
00230 }
00231
00232 int partNode::childCount() const {
00233 int count = 0;
00234 for ( partNode * child = firstChild() ; child ; child = child->nextSibling() )
00235 ++ count;
00236 return count;
00237 }
00238
00239 QString partNode::contentTypeParameter( const char * name ) const {
00240 if ( !mDwPart || !mDwPart->hasHeaders() )
00241 return QString::null;
00242 DwHeaders & headers = mDwPart->Headers();
00243 if ( !headers.HasContentType() )
00244 return QString::null;
00245 DwString attr = name;
00246 attr.ConvertToLowerCase();
00247 for ( DwParameter * param = headers.ContentType().FirstParameter() ; param ; param = param->Next() ) {
00248 DwString this_attr = param->Attribute();
00249 this_attr.ConvertToLowerCase();
00250 if ( this_attr == attr )
00251 return QString::fromLatin1( param->Value().data(), param->Value().size() );
00252
00253 }
00254 return QString::null;
00255 }
00256
00257 KMMsgEncryptionState partNode::overallEncryptionState() const
00258 {
00259 KMMsgEncryptionState myState = KMMsgEncryptionStateUnknown;
00260 if( mEncryptionState == KMMsgNotEncrypted ) {
00261
00262 if( mChild )
00263 myState = mChild->overallEncryptionState();
00264 else
00265 myState = KMMsgNotEncrypted;
00266 }
00267 else {
00268 myState = mEncryptionState;
00269 }
00270
00271 if( mNext ) {
00272 KMMsgEncryptionState otherState = mNext->overallEncryptionState();
00273 switch( otherState ) {
00274 case KMMsgEncryptionStateUnknown:
00275 break;
00276 case KMMsgNotEncrypted:
00277 if( myState == KMMsgFullyEncrypted )
00278 myState = KMMsgPartiallyEncrypted;
00279 else if( myState != KMMsgPartiallyEncrypted )
00280 myState = KMMsgNotEncrypted;
00281 break;
00282 case KMMsgPartiallyEncrypted:
00283 myState = KMMsgPartiallyEncrypted;
00284 break;
00285 case KMMsgFullyEncrypted:
00286 if( myState != KMMsgFullyEncrypted )
00287 myState = KMMsgPartiallyEncrypted;
00288 break;
00289 case KMMsgEncryptionProblematic:
00290 break;
00291 }
00292 }
00293
00294
00295
00296 return myState;
00297 }
00298
00299
00300 KMMsgSignatureState partNode::overallSignatureState() const
00301 {
00302 KMMsgSignatureState myState = KMMsgSignatureStateUnknown;
00303 if( mSignatureState == KMMsgNotSigned ) {
00304
00305 if( mChild )
00306 myState = mChild->overallSignatureState();
00307 else
00308 myState = KMMsgNotSigned;
00309 }
00310 else {
00311 myState = mSignatureState;
00312 }
00313
00314 if( mNext ) {
00315 KMMsgSignatureState otherState = mNext->overallSignatureState();
00316 switch( otherState ) {
00317 case KMMsgSignatureStateUnknown:
00318 break;
00319 case KMMsgNotSigned:
00320 if( myState == KMMsgFullySigned )
00321 myState = KMMsgPartiallySigned;
00322 else if( myState != KMMsgPartiallySigned )
00323 myState = KMMsgNotSigned;
00324 break;
00325 case KMMsgPartiallySigned:
00326 myState = KMMsgPartiallySigned;
00327 break;
00328 case KMMsgFullySigned:
00329 if( myState != KMMsgFullySigned )
00330 myState = KMMsgPartiallySigned;
00331 break;
00332 case KMMsgEncryptionProblematic:
00333 break;
00334 }
00335 }
00336
00337
00338
00339 return myState;
00340 }
00341
00342
00343 int partNode::nodeId()
00344 {
00345 int curId = 0;
00346 partNode* rootNode = this;
00347 while( rootNode->mRoot )
00348 rootNode = rootNode->mRoot;
00349 return rootNode->calcNodeIdOrFindNode( curId, this, 0, 0 );
00350 }
00351
00352
00353 partNode* partNode::findId( int id )
00354 {
00355 int curId = 0;
00356 partNode* rootNode = this;
00357 while( rootNode->mRoot )
00358 rootNode = rootNode->mRoot;
00359 partNode* foundNode;
00360 rootNode->calcNodeIdOrFindNode( curId, 0, id, &foundNode );
00361 return foundNode;
00362 }
00363
00364
00365 int partNode::calcNodeIdOrFindNode( int &curId, const partNode* findNode, int findId, partNode** foundNode )
00366 {
00367
00368
00369 curId++;
00370
00371 if( findNode && this == findNode )
00372 return curId;
00373
00374 if( foundNode && curId == findId ) {
00375 *foundNode = this;
00376 return curId;
00377 }
00378 if( mChild )
00379 {
00380 int res = mChild->calcNodeIdOrFindNode( curId, findNode, findId, foundNode );
00381 if (res != -1) return res;
00382 }
00383 if( mNext )
00384 return mNext->calcNodeIdOrFindNode( curId, findNode, findId, foundNode );
00385
00386 if( foundNode )
00387 *foundNode = 0;
00388 return -1;
00389 }
00390
00391
00392 partNode* partNode::findType( int type, int subType, bool deep, bool wide )
00393 {
00394 #ifndef NDEBUG
00395 DwString typeStr, subTypeStr;
00396 DwTypeEnumToStr( mType, typeStr );
00397 DwSubtypeEnumToStr( mSubType, subTypeStr );
00398 kdDebug(5006) << "partNode::findType() is looking at " << typeStr.c_str()
00399 << "/" << subTypeStr.c_str() << endl;
00400 #endif
00401 if( (mType != DwMime::kTypeUnknown)
00402 && ( (type == DwMime::kTypeUnknown)
00403 || (type == mType) )
00404 && ( (subType == DwMime::kSubtypeUnknown)
00405 || (subType == mSubType) ) )
00406 return this;
00407 if ( mChild && deep )
00408 return mChild->findType( type, subType, deep, wide );
00409 if ( mNext && wide )
00410 return mNext->findType( type, subType, deep, wide );
00411 return 0;
00412 }
00413
00414 partNode* partNode::findNodeForDwPart( DwBodyPart* part )
00415 {
00416 partNode* found = 0;
00417 if( kasciistricmp( dwPart()->partId(), part->partId() ) == 0 )
00418 return this;
00419 if( mChild )
00420 found = mChild->findNodeForDwPart( part );
00421 if( mNext && !found )
00422 found = mNext->findNodeForDwPart( part );
00423 return found;
00424 }
00425
00426 partNode* partNode::findTypeNot( int type, int subType, bool deep, bool wide )
00427 {
00428 if( (mType != DwMime::kTypeUnknown)
00429 && ( (type == DwMime::kTypeUnknown)
00430 || (type != mType) )
00431 && ( (subType == DwMime::kSubtypeUnknown)
00432 || (subType != mSubType) ) )
00433 return this;
00434 if ( mChild && deep )
00435 return mChild->findTypeNot( type, subType, deep, wide );
00436 if ( mNext && wide )
00437 return mNext->findTypeNot( type, subType, deep, wide );
00438 return 0;
00439 }
00440
00441 void partNode::fillMimePartTree( KMMimePartTreeItem* parentItem,
00442 KMMimePartTree* mimePartTree,
00443 QString labelDescr,
00444 QString labelCntType,
00445 QString labelEncoding,
00446 KIO::filesize_t size,
00447 bool revertOrder )
00448 {
00449 if( parentItem || mimePartTree ) {
00450
00451 if( mNext )
00452 mNext->fillMimePartTree( parentItem, mimePartTree,
00453 QString::null, QString::null, QString::null, 0,
00454 revertOrder );
00455
00456 QString cntDesc, cntType, cntEnc;
00457 KIO::filesize_t cntSize = 0;
00458
00459 if( labelDescr.isEmpty() ) {
00460 DwHeaders* headers = 0;
00461 if( mDwPart && mDwPart->hasHeaders() )
00462 headers = &mDwPart->Headers();
00463 if( headers && headers->HasSubject() )
00464 cntDesc = KMMsgBase::decodeRFC2047String( headers->Subject().AsString().c_str() );
00465 if( headers && headers->HasContentType()) {
00466 cntType = headers->ContentType().TypeStr().c_str();
00467 cntType += '/';
00468 cntType += headers->ContentType().SubtypeStr().c_str();
00469 }
00470 else
00471 cntType = "text/plain";
00472 if( cntDesc.isEmpty() )
00473 cntDesc = msgPart().contentDescription();
00474 if( cntDesc.isEmpty() )
00475 cntDesc = msgPart().name().stripWhiteSpace();
00476 if( cntDesc.isEmpty() )
00477 cntDesc = msgPart().fileName();
00478 if( cntDesc.isEmpty() ) {
00479 if( mRoot && mRoot->mRoot )
00480 cntDesc = i18n("internal part");
00481 else
00482 cntDesc = i18n("body part");
00483 }
00484 cntEnc = msgPart().contentTransferEncodingStr();
00485 if( mDwPart )
00486 cntSize = mDwPart->BodySize();
00487 } else {
00488 cntDesc = labelDescr;
00489 cntType = labelCntType;
00490 cntEnc = labelEncoding;
00491 cntSize = size;
00492 }
00493
00494 cntDesc.replace( QRegExp("\\n\\s*"), " " );
00495
00496 kdDebug(5006) << " Inserting one item into MimePartTree" << endl;
00497 kdDebug(5006) << " Content-Type: " << cntType << endl;
00498 if( parentItem )
00499 mMimePartTreeItem = new KMMimePartTreeItem( parentItem,
00500 this,
00501 cntDesc,
00502 cntType,
00503 cntEnc,
00504 cntSize,
00505 revertOrder );
00506 else if( mimePartTree )
00507 mMimePartTreeItem = new KMMimePartTreeItem( mimePartTree,
00508 this,
00509 cntDesc,
00510 cntType,
00511 cntEnc,
00512 cntSize );
00513 mMimePartTreeItem->setOpen( true );
00514 if( mChild )
00515 mChild->fillMimePartTree( mMimePartTreeItem, 0,
00516 QString::null, QString::null, QString::null, 0,
00517 revertOrder );
00518
00519 }
00520 }
00521
00522 void partNode::adjustDefaultType( partNode* node )
00523 {
00524
00525
00526
00527 if( node && DwMime::kTypeUnknown == node->type() ) {
00528 if( node->mRoot
00529 && DwMime::kTypeMultipart == node->mRoot->type()
00530 && DwMime::kSubtypeDigest == node->mRoot->subType() ) {
00531 node->setType( DwMime::kTypeMessage );
00532 node->setSubType( DwMime::kSubtypeRfc822 );
00533 }
00534 else
00535 {
00536 node->setType( DwMime::kTypeText );
00537 node->setSubType( DwMime::kSubtypePlain );
00538 }
00539 }
00540 }
00541
00542 bool partNode::isAttachment() const
00543 {
00544 if( !dwPart() )
00545 return false;
00546 if ( !dwPart()->hasHeaders() )
00547 return false;
00548 DwHeaders& headers = dwPart()->Headers();
00549 if( !headers.HasContentDisposition() )
00550 return false;
00551 return ( headers.ContentDisposition().DispositionType()
00552 == DwMime::kDispTypeAttachment );
00553 }
00554
00555 bool partNode::isHeuristicalAttachment() const {
00556 if ( isAttachment() )
00557 return true;
00558 const KMMessagePart & p = msgPart();
00559 return !p.fileName().isEmpty() || !p.name().isEmpty() ;
00560 }
00561
00562 partNode * partNode::next( bool allowChildren ) const {
00563 if ( allowChildren )
00564 if ( partNode * c = firstChild() )
00565 return c;
00566 if ( partNode * s = nextSibling() )
00567 return s;
00568 for ( partNode * p = parentNode() ; p ; p = p->parentNode() )
00569 if ( partNode * s = p->nextSibling() )
00570 return s;
00571 return 0;
00572 }
00573
00574 bool partNode::isFirstTextPart() const {
00575 if ( type() != DwMime::kTypeText )
00576 return false;
00577 const partNode * root = this;
00578
00579
00580 while ( const partNode * p = root->parentNode() ) {
00581 if ( p->type() == DwMime::kTypeMessage )
00582 break;
00583 else
00584 root = p;
00585 }
00586 for ( const partNode * n = root ; n ; n = n->next() )
00587 if ( n->type() == DwMime::kTypeText )
00588 return n == this;
00589 kdFatal() << "partNode::isFirstTextPart(): Didn't expect to end up here..." << endl;
00590 return false;
00591 }
00592
00593 bool partNode::hasContentDispositionInline() const
00594 {
00595 if( !dwPart() )
00596 return false;
00597 DwHeaders& headers = dwPart()->Headers();
00598 if( headers.HasContentDisposition() )
00599 return ( headers.ContentDisposition().DispositionType()
00600 == DwMime::kDispTypeInline );
00601 else
00602 return false;
00603 }
00604
00605 const QString& partNode::trueFromAddress() const
00606 {
00607 const partNode* node = this;
00608 while( node->mFromAddress.isEmpty() && node->mRoot )
00609 node = node->mRoot;
00610 return node->mFromAddress;
00611 }