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