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