35 #include "kmreaderwin.h"
37 #include <tdelocale.h>
39 #include "kmmimeparttree.h"
40 #include <mimelib/utility.h>
58 : mRoot( 0 ), mNext( 0 ), mChild( 0 ),
59 mWasProcessed( false ),
61 mType( DwMime::kTypeUnknown ),
62 mSubType( DwMime::kSubtypeUnknown ),
63 mEncryptionState( KMMsgNotEncrypted ),
64 mSignatureState( KMMsgNotSigned ),
67 mDeleteDwBodyPart( false ),
68 mMimePartTreeItem( 0 ),
69 mBodyPartMementoMap(),
71 mDisplayedEmbedded( false )
73 adjustDefaultType(
this );
76 partNode::partNode(
KMReaderWin * win, DwBodyPart* dwPart,
int explicitType,
int explicitSubType,
77 bool deleteDwBodyPart )
78 : mRoot( 0 ), mNext( 0 ), mChild( 0 ),
79 mWasProcessed( false ),
81 mEncryptionState( KMMsgNotEncrypted ),
82 mSignatureState( KMMsgNotSigned ),
85 mDeleteDwBodyPart( deleteDwBodyPart ),
86 mMimePartTreeItem( 0 ),
87 mBodyPartMementoMap(),
89 mDisplayedEmbedded( false ),
90 mDisplayedHidden( false )
92 if ( explicitType != DwMime::kTypeUnknown ) {
94 mSubType = explicitSubType;
96 if(dwPart && dwPart->hasHeaders() && dwPart->Headers().HasContentType()) {
97 mType = (!dwPart->Headers().ContentType().Type())?DwMime::kTypeUnknown:dwPart->Headers().ContentType().Type();
98 mSubType = dwPart->Headers().ContentType().Subtype();
100 mType = DwMime::kTypeUnknown;
101 mSubType = DwMime::kSubtypeUnknown;
110 int mainType = msg->type();
111 int mainSubType = msg->subtype();
112 if( (DwMime::kTypeNull == mainType)
113 || (DwMime::kTypeUnknown == mainType) ){
114 mainType = DwMime::kTypeText;
115 mainSubType = DwMime::kSubtypePlain;
123 DwBodyPart * mainBody =
new DwBodyPart( *msg->getTopLevelPart() );
125 partNode * root =
new partNode( win, mainBody, mainType, mainSubType,
true );
126 root->buildObjectTree();
128 root->setFromAddress( msg->
from() );
133 partNode::partNode(
bool deleteDwBodyPart, DwBodyPart* dwPart )
134 : mRoot( 0 ), mNext( 0 ), mChild( 0 ),
135 mWasProcessed( false ),
137 mEncryptionState( KMMsgNotEncrypted ),
138 mSignatureState( KMMsgNotSigned ),
141 mDeleteDwBodyPart( deleteDwBodyPart ),
142 mMimePartTreeItem( 0 ),
143 mBodyPartMementoMap(),
145 mDisplayedEmbedded( false )
147 if ( dwPart && dwPart->hasHeaders() && dwPart->Headers().HasContentType() ) {
148 mType = (!dwPart->Headers().ContentType().Type())?DwMime::kTypeUnknown:dwPart->Headers().ContentType().Type();
149 mSubType = dwPart->Headers().ContentType().Subtype();
151 mType = DwMime::kTypeUnknown;
152 mSubType = DwMime::kSubtypeUnknown;
156 partNode::~partNode() {
157 if( mDeleteDwBodyPart )
160 delete mChild; mChild = 0;
161 delete mNext; mNext = 0;
162 for ( std::map<TQCString,KMail::Interface::BodyPartMemento*>::const_iterator it = mBodyPartMementoMap.begin(), end = mBodyPartMementoMap.end() ; it != end ; ++it )
164 mBodyPartMementoMap.clear();
168 void partNode::dump(
int chars )
const {
169 kdDebug(5006) << nodeId() <<
" " << TQString(TQString().fill(
' ', chars )) <<
"+ "
170 << typeString() <<
'/' << subTypeString() <<
" embedded:" << mDisplayedEmbedded
171 <<
" address:" <<
this << endl;
173 mChild->dump( chars + 1 );
175 mNext->dump( chars );
178 void partNode::dump(
int )
const {}
181 const TQCString & partNode::encodedBody() {
194 void partNode::buildObjectTree(
bool processSiblings )
196 partNode* curNode =
this;
197 while( curNode && curNode->dwPart() ) {
199 while( DwMime::kTypeMultipart == curNode->type() ) {
200 partNode * newNode =
new partNode( mReader, curNode->dwPart()->Body().FirstBodyPart() );
201 curNode->setFirstChild( newNode );
207 && !( curNode->dwPart()
208 && curNode->dwPart()->Next() ) ) {
209 curNode = curNode->mRoot;
212 if(
this == curNode && !processSiblings )
215 if( curNode && curNode->dwPart() && curNode->dwPart()->Next() ) {
216 partNode* nextNode =
new partNode( mReader, curNode->dwPart()->Next() );
217 curNode->setNext( nextNode );
224 TQCString partNode::typeString()
const {
226 DwTypeEnumToStr( type(), s );
230 TQCString partNode::subTypeString()
const {
232 DwSubtypeEnumToStr( subType(), s );
236 const partNode* partNode::topLevelParent()
const {
237 const partNode *ret =
this;
238 while ( ret->parentNode() )
239 ret = ret->parentNode();
243 int partNode::childCount()
const {
245 for ( partNode * child = firstChild() ; child ; child = child->nextSibling() )
250 int partNode::totalChildCount()
const {
252 for ( partNode * child = firstChild() ; child ; child = child->nextSibling() ) {
254 count += child->totalChildCount();
259 TQString partNode::contentTypeParameter(
const char * name )
const {
260 if ( !mDwPart || !mDwPart->hasHeaders() )
262 DwHeaders & headers = mDwPart->Headers();
263 if ( !headers.HasContentType() )
265 DwString attr = name;
266 attr.ConvertToLowerCase();
267 for ( DwParameter * param = headers.ContentType().FirstParameter() ; param ; param = param->Next() ) {
268 DwString this_attr = param->Attribute();
269 this_attr.ConvertToLowerCase();
270 if ( this_attr == attr )
271 return TQString::fromLatin1( param->Value().data(), param->Value().size() );
277 KMMsgEncryptionState partNode::overallEncryptionState()
const
279 KMMsgEncryptionState myState = KMMsgEncryptionStateUnknown;
280 if( mEncryptionState == KMMsgNotEncrypted ) {
283 myState = mChild->overallEncryptionState();
285 myState = KMMsgNotEncrypted;
288 myState = mEncryptionState;
292 KMMsgEncryptionState otherState = mNext->overallEncryptionState();
293 switch( otherState ) {
294 case KMMsgEncryptionStateUnknown:
296 case KMMsgNotEncrypted:
297 if( myState == KMMsgFullyEncrypted )
298 myState = KMMsgPartiallyEncrypted;
299 else if( myState != KMMsgPartiallyEncrypted )
300 myState = KMMsgNotEncrypted;
302 case KMMsgPartiallyEncrypted:
303 myState = KMMsgPartiallyEncrypted;
305 case KMMsgFullyEncrypted:
306 if( myState != KMMsgFullyEncrypted )
307 myState = KMMsgPartiallyEncrypted;
309 case KMMsgEncryptionProblematic:
318 KMMsgSignatureState partNode::overallSignatureState()
const
320 KMMsgSignatureState myState = KMMsgSignatureStateUnknown;
321 if( mSignatureState == KMMsgNotSigned ) {
324 myState = mChild->overallSignatureState();
326 myState = KMMsgNotSigned;
329 myState = mSignatureState;
333 KMMsgSignatureState otherState = mNext->overallSignatureState();
334 switch( otherState ) {
335 case KMMsgSignatureStateUnknown:
338 if( myState == KMMsgFullySigned )
339 myState = KMMsgPartiallySigned;
340 else if( myState != KMMsgPartiallySigned )
341 myState = KMMsgNotSigned;
343 case KMMsgPartiallySigned:
344 myState = KMMsgPartiallySigned;
346 case KMMsgFullySigned:
347 if( myState != KMMsgFullySigned )
348 myState = KMMsgPartiallySigned;
350 case KMMsgEncryptionProblematic:
358 TQCString partNode::path()
const
362 const partNode * p = parentNode();
366 for (
const partNode * c = p->firstChild() ; c !=
this ; c = c->nextSibling() )
367 if ( c->type() == type() && c->subType() == subType() )
370 return p->path() + TQCString().sprintf(
":%X/%X[%X]", type(), subType(), nth );
374 int partNode::nodeId()
const
377 partNode* rootNode =
const_cast<partNode*
>( this );
378 while( rootNode->mRoot )
379 rootNode = rootNode->mRoot;
380 return rootNode->calcNodeIdOrFindNode( curId,
this, 0, 0 );
384 partNode* partNode::findId(
int id )
387 partNode* rootNode =
this;
388 while( rootNode->mRoot )
389 rootNode = rootNode->mRoot;
391 rootNode->calcNodeIdOrFindNode( curId, 0,
id, &foundNode );
396 int partNode::calcNodeIdOrFindNode(
int &curId,
const partNode* findNode,
int findId, partNode** foundNode )
402 if( findNode &&
this == findNode )
405 if( foundNode && curId == findId ) {
411 int res = mChild->calcNodeIdOrFindNode( curId, findNode, findId, foundNode );
412 if (res != -1)
return res;
415 return mNext->calcNodeIdOrFindNode( curId, findNode, findId, foundNode );
423 partNode* partNode::findType(
int type,
int subType,
bool deep,
bool wide )
425 if( (mType != DwMime::kTypeUnknown)
426 && ( (type == DwMime::kTypeUnknown)
428 && ( (subType == DwMime::kSubtypeUnknown)
429 || (subType == mSubType) ) )
431 if ( mChild && deep )
432 return mChild->findType( type, subType, deep, wide );
434 return mNext->findType( type, subType, deep, wide );
438 partNode* partNode::findNodeForDwPart( DwBodyPart* part )
441 if( kasciistricmp( dwPart()->partId(), part->partId() ) == 0 )
444 found = mChild->findNodeForDwPart( part );
445 if( mNext && !found )
446 found = mNext->findNodeForDwPart( part );
450 partNode* partNode::findTypeNot(
int type,
int subType,
bool deep,
bool wide )
452 if( (mType != DwMime::kTypeUnknown)
453 && ( (type == DwMime::kTypeUnknown)
455 && ( (subType == DwMime::kSubtypeUnknown)
456 || (subType != mSubType) ) )
458 if ( mChild && deep )
459 return mChild->findTypeNot( type, subType, deep, wide );
461 return mNext->findTypeNot( type, subType, deep, wide );
465 void partNode::fillMimePartTree( KMMimePartTreeItem* parentItem,
466 KMMimePartTree* mimePartTree,
468 TQString labelCntType,
469 TQString labelEncoding,
470 TDEIO::filesize_t size,
473 if( parentItem || mimePartTree ) {
476 mNext->fillMimePartTree( parentItem, mimePartTree,
477 TQString(), TQString(), TQString(), 0,
480 TQString cntDesc, cntType, cntEnc;
481 TDEIO::filesize_t cntSize = 0;
483 if( labelDescr.isEmpty() ) {
484 DwHeaders* headers = 0;
485 if( mDwPart && mDwPart->hasHeaders() )
486 headers = &mDwPart->Headers();
487 if( headers && headers->HasSubject() )
488 cntDesc = KMMsgBase::decodeRFC2047String( headers->Subject().AsString().c_str() );
489 if( headers && headers->HasContentType()) {
490 cntType = headers->ContentType().TypeStr().c_str();
492 cntType += headers->ContentType().SubtypeStr().c_str();
495 cntType =
"text/plain";
496 if( cntDesc.isEmpty() )
497 cntDesc = msgPart().name().stripWhiteSpace();
498 if( cntDesc.isEmpty() )
499 cntDesc = msgPart().fileName();
500 if( cntDesc.isEmpty() )
501 cntDesc = msgPart().contentDescription();
502 if( cntDesc.isEmpty() ) {
503 if( mRoot && mRoot->mRoot )
504 cntDesc = i18n(
"internal part");
506 cntDesc = i18n(
"body part");
508 cntEnc = msgPart().contentTransferEncodingStr();
510 cntSize = mDwPart->BodySize();
512 cntDesc = labelDescr;
513 cntType = labelCntType;
514 cntEnc = labelEncoding;
518 cntDesc.replace( TQRegExp(
"\\n\\s*"),
" " );
521 mMimePartTreeItem =
new KMMimePartTreeItem( parentItem,
528 else if( mimePartTree )
529 mMimePartTreeItem =
new KMMimePartTreeItem( mimePartTree,
535 mMimePartTreeItem->setOpen(
true );
537 mChild->fillMimePartTree( mMimePartTreeItem, 0,
538 TQString(), TQString(), TQString(), 0,
544 void partNode::adjustDefaultType( partNode* node )
549 if( node && DwMime::kTypeUnknown == node->type() ) {
551 && DwMime::kTypeMultipart == node->mRoot->type()
552 && DwMime::kSubtypeDigest == node->mRoot->subType() ) {
553 node->setType( DwMime::kTypeMessage );
554 node->setSubType( DwMime::kSubtypeRfc822 );
558 node->setType( DwMime::kTypeText );
559 node->setSubType( DwMime::kSubtypePlain );
564 bool partNode::isAttachment()
const
568 if ( !dwPart()->hasHeaders() )
570 DwHeaders& headers = dwPart()->Headers();
571 if ( headers.HasContentType() &&
572 headers.ContentType().Type() == DwMime::kTypeMessage &&
573 headers.ContentType().Subtype() == DwMime::kSubtypeRfc822 ) {
578 if( !headers.HasContentDisposition() )
580 return ( headers.ContentDisposition().DispositionType()
581 == DwMime::kDispTypeAttachment );
584 bool partNode::isHeuristicalAttachment()
const {
585 if ( isAttachment() )
587 const KMMessagePart & p = msgPart();
588 return !p.fileName().isEmpty() || !p.name().isEmpty() ;
591 partNode * partNode::next(
bool allowChildren )
const {
593 if ( partNode * c = firstChild() )
595 if ( partNode * s = nextSibling() )
597 for ( partNode * p = parentNode() ; p ; p = p->parentNode() )
598 if ( partNode * s = p->nextSibling() )
603 bool partNode::isFirstTextPart()
const {
604 if ( type() != DwMime::kTypeText )
606 const partNode * root =
this;
609 while (
const partNode * p = root->parentNode() ) {
610 if ( p->type() == DwMime::kTypeMessage )
615 for (
const partNode * n = root ; n ; n = n->next() )
616 if ( n->type() == DwMime::kTypeText )
618 kdFatal() <<
"partNode::isFirstTextPart(): Didn't expect to end up here..." << endl;
622 bool partNode::isToltecMessage()
const
624 if ( type() != DwMime::kTypeMultipart || subType() != DwMime::kSubtypeMixed )
627 if ( childCount() != 3 )
630 const DwField* library = dwPart()->Headers().FindField(
"X-Library" );
634 if ( !library->FieldBody() ||
635 TQString( library->FieldBody()->AsString().c_str() ) != TQString(
"Toltec" ) )
638 const DwField* kolabType = dwPart()->Headers().FindField(
"X-Kolab-Type" );
642 if ( !kolabType->FieldBody() ||
643 !TQString( kolabType->FieldBody()->AsString().c_str() ).startsWith(
"application/x-vnd.kolab" ) )
649 bool partNode::isInEncapsulatedMessage()
const
651 const partNode *
const topLevel = topLevelParent();
652 const partNode *cur =
this;
653 while ( cur && cur != topLevel ) {
654 const bool parentIsMessage = cur->parentNode() &&
655 cur->parentNode()->msgPart().typeStr().lower() ==
"message";
656 if ( parentIsMessage && cur->parentNode() != topLevel )
658 cur = cur->parentNode();
663 bool partNode::hasContentDispositionInline()
const
667 DwHeaders& headers = dwPart()->Headers();
668 if( headers.HasContentDisposition() )
669 return ( headers.ContentDisposition().DispositionType()
670 == DwMime::kDispTypeInline );
675 const TQString& partNode::trueFromAddress()
const
677 const partNode* node =
this;
678 while( node->mFromAddress.isEmpty() && node->mRoot )
680 return node->mFromAddress;
686 return r->bodyPartMemento(
this, which );
688 return internalBodyPartMemento( which );
695 const std::map<TQCString,KMail::Interface::BodyPartMemento*>::const_iterator it = mBodyPartMementoMap.find( which.lower() );
696 return it != mBodyPartMementoMap.end() ? it->second : 0 ;
702 r->setBodyPartMemento(
this, which, memento );
704 internalSetBodyPartMemento( which, memento );
711 const std::map<TQCString,KMail::Interface::BodyPartMemento*>::iterator it = mBodyPartMementoMap.lower_bound( which.lower() );
712 if ( it != mBodyPartMementoMap.end() && it->first == which.lower() ) {
715 it->second = memento;
718 mBodyPartMementoMap.erase( it );
721 mBodyPartMementoMap.insert( it, std::make_pair( which.lower(), memento ) );
725 bool partNode::isDisplayedEmbedded()
const
727 return mDisplayedEmbedded;
730 void partNode::setDisplayedEmbedded(
bool displayedEmbedded )
732 mDisplayedEmbedded = displayedEmbedded;
735 bool partNode::isDisplayedHidden()
const
737 return mDisplayedHidden;
740 void partNode::setDisplayedHidden(
bool displayedHidden )
742 mDisplayedHidden = displayedHidden;
746 TQString partNode::asHREF(
const TQString &place )
const
748 return TQString(
"attachment:%1?place=%2" ).arg( nodeId() ).arg( place );
751 partNode::AttachmentDisplayInfo partNode::attachmentDisplayInfo()
const
753 AttachmentDisplayInfo info;
754 info.icon = msgPart().iconName( TDEIcon::Small );
755 info.label = msgPart().name().stripWhiteSpace();
756 if ( info.label.isEmpty() )
757 info.label = msgPart().fileName();
758 if ( info.label.isEmpty() )
759 info.label = msgPart().contentDescription();
760 bool typeBlacklisted = msgPart().typeStr().lower() ==
"multipart";
761 if ( !typeBlacklisted && msgPart().typeStr().lower() ==
"application" ) {
762 typeBlacklisted = msgPart().subtypeStr() ==
"pgp-encrypted"
763 || msgPart().subtypeStr().lower() ==
"pgp-signature"
764 || msgPart().subtypeStr().lower() ==
"pkcs7-mime"
765 || msgPart().subtypeStr().lower() ==
"pkcs7-signature";
767 typeBlacklisted = typeBlacklisted ||
this == topLevelParent();
768 bool firstTextChildOfEncapsulatedMsg = msgPart().typeStr().lower() ==
"text" &&
769 msgPart().subtypeStr().lower() ==
"plain" &&
771 parentNode()->msgPart().typeStr().lower() ==
"message";
772 typeBlacklisted = typeBlacklisted || firstTextChildOfEncapsulatedMsg;
773 info.displayInHeader = !info.label.isEmpty() && !info.icon.isEmpty() && !typeBlacklisted;
TQString from() const
Get or set the 'From' header field.
This class implements a "reader window", that is a window used for reading or viewing messages.
interface of classes that implement status for BodyPartFormatters.
TQCString CString(const DwString &str)
Construct a TQCString from a DwString.