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
while (
const partNode * p = root->parentNode() )
00568 root = p;
00569
for (
const partNode * n = root ; n ; n = n->next() )
00570
if ( n->type() == DwMime::kTypeText )
00571
return n ==
this;
00572 kdFatal() <<
"partNode::isFirstTextPart(): Didn't expect to end up here..." << endl;
00573
return false;
00574 }
00575
00576
bool partNode::hasContentDispositionInline()
const
00577
{
00578
if( !dwPart() )
00579
return false;
00580 DwHeaders& headers = dwPart()->Headers();
00581
if( headers.HasContentDisposition() )
00582
return ( headers.ContentDisposition().DispositionType()
00583 == DwMime::kDispTypeInline );
00584
else
00585
return false;
00586 }
00587
00588
const QString& partNode::trueFromAddress()
const
00589
{
00590
const partNode* node =
this;
00591
while( node->mFromAddress.isEmpty() && node->mRoot )
00592 node = node->mRoot;
00593
return node->mFromAddress;
00594 }