35 #include "kmreaderwin.h"
37 #include <tdelocale.h>
39 #include "kmmimeparttree.h"
40 #include <mimelib/utility.h>
42 #include <kasciistricmp.h>
59 : mRoot( 0 ), mNext( 0 ), mChild( 0 ),
60 mWasProcessed( false ),
62 mType( DwMime::kTypeUnknown ),
63 mSubType( DwMime::kSubtypeUnknown ),
64 mEncryptionState( KMMsgNotEncrypted ),
65 mSignatureState( KMMsgNotSigned ),
68 mDeleteDwBodyPart( false ),
69 mMimePartTreeItem( 0 ),
70 mBodyPartMementoMap(),
72 mDisplayedEmbedded( false )
74 adjustDefaultType(
this );
77 partNode::partNode(
KMReaderWin * win, DwBodyPart* dwPart,
int explicitType,
int explicitSubType,
78 bool deleteDwBodyPart )
79 : mRoot( 0 ), mNext( 0 ), mChild( 0 ),
80 mWasProcessed( false ),
82 mEncryptionState( KMMsgNotEncrypted ),
83 mSignatureState( KMMsgNotSigned ),
86 mDeleteDwBodyPart( deleteDwBodyPart ),
87 mMimePartTreeItem( 0 ),
88 mBodyPartMementoMap(),
90 mDisplayedEmbedded( false ),
91 mDisplayedHidden( false )
93 if ( explicitType != DwMime::kTypeUnknown ) {
95 mSubType = explicitSubType;
97 if(dwPart && dwPart->hasHeaders() && dwPart->Headers().HasContentType()) {
98 mType = (!dwPart->Headers().ContentType().Type())?DwMime::kTypeUnknown:dwPart->Headers().ContentType().Type();
99 mSubType = dwPart->Headers().ContentType().Subtype();
101 mType = DwMime::kTypeUnknown;
102 mSubType = DwMime::kSubtypeUnknown;
111 int mainType = msg->type();
112 int mainSubType = msg->subtype();
113 if( (DwMime::kTypeNull == mainType)
114 || (DwMime::kTypeUnknown == mainType) ){
115 mainType = DwMime::kTypeText;
116 mainSubType = DwMime::kSubtypePlain;
124 DwBodyPart * mainBody =
new DwBodyPart( *msg->getTopLevelPart() );
126 partNode * root =
new partNode( win, mainBody, mainType, mainSubType,
true );
127 root->buildObjectTree();
129 root->setFromAddress( msg->
from() );
134 partNode::partNode(
bool deleteDwBodyPart, DwBodyPart* dwPart )
135 : mRoot( 0 ), mNext( 0 ), mChild( 0 ),
136 mWasProcessed( false ),
138 mEncryptionState( KMMsgNotEncrypted ),
139 mSignatureState( KMMsgNotSigned ),
142 mDeleteDwBodyPart( deleteDwBodyPart ),
143 mMimePartTreeItem( 0 ),
144 mBodyPartMementoMap(),
146 mDisplayedEmbedded( false )
148 if ( dwPart && dwPart->hasHeaders() && dwPart->Headers().HasContentType() ) {
149 mType = (!dwPart->Headers().ContentType().Type())?DwMime::kTypeUnknown:dwPart->Headers().ContentType().Type();
150 mSubType = dwPart->Headers().ContentType().Subtype();
152 mType = DwMime::kTypeUnknown;
153 mSubType = DwMime::kSubtypeUnknown;
157 partNode::~partNode() {
158 if( mDeleteDwBodyPart )
161 delete mChild; mChild = 0;
162 delete mNext; mNext = 0;
163 for ( std::map<TQCString,KMail::Interface::BodyPartMemento*>::const_iterator it = mBodyPartMementoMap.begin(), end = mBodyPartMementoMap.end() ; it != end ; ++it )
165 mBodyPartMementoMap.clear();
169 void partNode::dump(
int chars )
const {
170 kdDebug(5006) << nodeId() <<
" " << TQString(TQString().fill(
' ', chars )) <<
"+ "
171 << typeString() <<
'/' << subTypeString() <<
" embedded:" << mDisplayedEmbedded
172 <<
" address:" <<
this << endl;
174 mChild->dump( chars + 1 );
176 mNext->dump( chars );
179 void partNode::dump(
int )
const {}
182 const TQCString & partNode::encodedBody() {
195 void partNode::buildObjectTree(
bool processSiblings )
197 partNode* curNode =
this;
198 while( curNode && curNode->dwPart() ) {
200 while( DwMime::kTypeMultipart == curNode->type() ) {
201 partNode * newNode =
new partNode( mReader, curNode->dwPart()->Body().FirstBodyPart() );
202 curNode->setFirstChild( newNode );
208 && !( curNode->dwPart()
209 && curNode->dwPart()->Next() ) ) {
210 curNode = curNode->mRoot;
213 if(
this == curNode && !processSiblings )
216 if( curNode && curNode->dwPart() && curNode->dwPart()->Next() ) {
217 partNode* nextNode =
new partNode( mReader, curNode->dwPart()->Next() );
218 curNode->setNext( nextNode );
225 TQCString partNode::typeString()
const {
227 DwTypeEnumToStr( type(), s );
231 TQCString partNode::subTypeString()
const {
233 DwSubtypeEnumToStr( subType(), s );
237 const partNode* partNode::topLevelParent()
const {
238 const partNode *ret =
this;
239 while ( ret->parentNode() )
240 ret = ret->parentNode();
244 int partNode::childCount()
const {
246 for ( partNode * child = firstChild() ; child ; child = child->nextSibling() )
251 int partNode::totalChildCount()
const {
253 for ( partNode * child = firstChild() ; child ; child = child->nextSibling() ) {
255 count += child->totalChildCount();
260 TQString partNode::contentTypeParameter(
const char * name )
const {
261 if ( !mDwPart || !mDwPart->hasHeaders() )
263 DwHeaders & headers = mDwPart->Headers();
264 if ( !headers.HasContentType() )
266 DwString attr = name;
267 attr.ConvertToLowerCase();
268 for ( DwParameter * param = headers.ContentType().FirstParameter() ; param ; param = param->Next() ) {
269 DwString this_attr = param->Attribute();
270 this_attr.ConvertToLowerCase();
271 if ( this_attr == attr )
272 return TQString::fromLatin1( param->Value().data(), param->Value().size() );
278 KMMsgEncryptionState partNode::overallEncryptionState()
const
280 KMMsgEncryptionState myState = KMMsgEncryptionStateUnknown;
281 if( mEncryptionState == KMMsgNotEncrypted ) {
284 myState = mChild->overallEncryptionState();
286 myState = KMMsgNotEncrypted;
289 myState = mEncryptionState;
293 KMMsgEncryptionState otherState = mNext->overallEncryptionState();
294 switch( otherState ) {
295 case KMMsgEncryptionStateUnknown:
297 case KMMsgNotEncrypted:
298 if( myState == KMMsgFullyEncrypted )
299 myState = KMMsgPartiallyEncrypted;
300 else if( myState != KMMsgPartiallyEncrypted )
301 myState = KMMsgNotEncrypted;
303 case KMMsgPartiallyEncrypted:
304 myState = KMMsgPartiallyEncrypted;
306 case KMMsgFullyEncrypted:
307 if( myState != KMMsgFullyEncrypted )
308 myState = KMMsgPartiallyEncrypted;
310 case KMMsgEncryptionProblematic:
319 KMMsgSignatureState partNode::overallSignatureState()
const
321 KMMsgSignatureState myState = KMMsgSignatureStateUnknown;
322 if( mSignatureState == KMMsgNotSigned ) {
325 myState = mChild->overallSignatureState();
327 myState = KMMsgNotSigned;
330 myState = mSignatureState;
334 KMMsgSignatureState otherState = mNext->overallSignatureState();
335 switch( otherState ) {
336 case KMMsgSignatureStateUnknown:
339 if( myState == KMMsgFullySigned )
340 myState = KMMsgPartiallySigned;
341 else if( myState != KMMsgPartiallySigned )
342 myState = KMMsgNotSigned;
344 case KMMsgPartiallySigned:
345 myState = KMMsgPartiallySigned;
347 case KMMsgFullySigned:
348 if( myState != KMMsgFullySigned )
349 myState = KMMsgPartiallySigned;
351 case KMMsgEncryptionProblematic:
359 TQCString partNode::path()
const
363 const partNode * p = parentNode();
367 for (
const partNode * c = p->firstChild() ; c !=
this ; c = c->nextSibling() )
368 if ( c->type() == type() && c->subType() == subType() )
371 return p->path() + TQCString().sprintf(
":%X/%X[%X]", type(), subType(), nth );
375 int partNode::nodeId()
const
378 partNode* rootNode =
const_cast<partNode*
>( this );
379 while( rootNode->mRoot )
380 rootNode = rootNode->mRoot;
381 return rootNode->calcNodeIdOrFindNode( curId,
this, 0, 0 );
385 partNode* partNode::findId(
int id )
388 partNode* rootNode =
this;
389 while( rootNode->mRoot )
390 rootNode = rootNode->mRoot;
392 rootNode->calcNodeIdOrFindNode( curId, 0,
id, &foundNode );
397 int partNode::calcNodeIdOrFindNode(
int &curId,
const partNode* findNode,
int findId, partNode** foundNode )
403 if( findNode &&
this == findNode )
406 if( foundNode && curId == findId ) {
412 int res = mChild->calcNodeIdOrFindNode( curId, findNode, findId, foundNode );
413 if (res != -1)
return res;
416 return mNext->calcNodeIdOrFindNode( curId, findNode, findId, foundNode );
424 partNode* partNode::findType(
int type,
int subType,
bool deep,
bool wide )
426 if( (mType != DwMime::kTypeUnknown)
427 && ( (type == DwMime::kTypeUnknown)
429 && ( (subType == DwMime::kSubtypeUnknown)
430 || (subType == mSubType) ) )
432 if ( mChild && deep )
433 return mChild->findType( type, subType, deep, wide );
435 return mNext->findType( type, subType, deep, wide );
439 partNode* partNode::findNodeForDwPart( DwBodyPart* part )
442 if( kasciistricmp( dwPart()->partId(), part->partId() ) == 0 )
445 found = mChild->findNodeForDwPart( part );
446 if( mNext && !found )
447 found = mNext->findNodeForDwPart( part );
451 partNode* partNode::findTypeNot(
int type,
int subType,
bool deep,
bool wide )
453 if( (mType != DwMime::kTypeUnknown)
454 && ( (type == DwMime::kTypeUnknown)
456 && ( (subType == DwMime::kSubtypeUnknown)
457 || (subType != mSubType) ) )
459 if ( mChild && deep )
460 return mChild->findTypeNot( type, subType, deep, wide );
462 return mNext->findTypeNot( type, subType, deep, wide );
466 void partNode::fillMimePartTree( KMMimePartTreeItem* parentItem,
467 KMMimePartTree* mimePartTree,
469 TQString labelCntType,
470 TQString labelEncoding,
471 TDEIO::filesize_t size,
474 if( parentItem || mimePartTree ) {
477 mNext->fillMimePartTree( parentItem, mimePartTree,
478 TQString(), TQString(), TQString(), 0,
481 TQString cntDesc, cntType, cntEnc;
482 TDEIO::filesize_t cntSize = 0;
484 if( labelDescr.isEmpty() ) {
485 DwHeaders* headers = 0;
486 if( mDwPart && mDwPart->hasHeaders() )
487 headers = &mDwPart->Headers();
488 if( headers && headers->HasSubject() )
489 cntDesc = KMMsgBase::decodeRFC2047String( headers->Subject().AsString().c_str() );
490 if( headers && headers->HasContentType()) {
491 cntType = headers->ContentType().TypeStr().c_str();
493 cntType += headers->ContentType().SubtypeStr().c_str();
496 cntType =
"text/plain";
497 if( cntDesc.isEmpty() )
498 cntDesc = msgPart().name().stripWhiteSpace();
499 if( cntDesc.isEmpty() )
500 cntDesc = msgPart().fileName();
501 if( cntDesc.isEmpty() )
502 cntDesc = msgPart().contentDescription();
503 if( cntDesc.isEmpty() ) {
504 if( mRoot && mRoot->mRoot )
505 cntDesc = i18n(
"internal part");
507 cntDesc = i18n(
"body part");
509 cntEnc = msgPart().contentTransferEncodingStr();
511 cntSize = mDwPart->BodySize();
513 cntDesc = labelDescr;
514 cntType = labelCntType;
515 cntEnc = labelEncoding;
519 cntDesc.replace( TQRegExp(
"\\n\\s*"),
" " );
522 mMimePartTreeItem =
new KMMimePartTreeItem( parentItem,
529 else if( mimePartTree )
530 mMimePartTreeItem =
new KMMimePartTreeItem( mimePartTree,
536 mMimePartTreeItem->setOpen(
true );
538 mChild->fillMimePartTree( mMimePartTreeItem, 0,
539 TQString(), TQString(), TQString(), 0,
545 void partNode::adjustDefaultType( partNode* node )
550 if( node && DwMime::kTypeUnknown == node->type() ) {
552 && DwMime::kTypeMultipart == node->mRoot->type()
553 && DwMime::kSubtypeDigest == node->mRoot->subType() ) {
554 node->setType( DwMime::kTypeMessage );
555 node->setSubType( DwMime::kSubtypeRfc822 );
559 node->setType( DwMime::kTypeText );
560 node->setSubType( DwMime::kSubtypePlain );
565 bool partNode::isAttachment()
const
569 if ( !dwPart()->hasHeaders() )
571 DwHeaders& headers = dwPart()->Headers();
572 if ( headers.HasContentType() &&
573 headers.ContentType().Type() == DwMime::kTypeMessage &&
574 headers.ContentType().Subtype() == DwMime::kSubtypeRfc822 ) {
579 if( !headers.HasContentDisposition() )
581 return ( headers.ContentDisposition().DispositionType()
582 == DwMime::kDispTypeAttachment );
585 bool partNode::isHeuristicalAttachment()
const {
586 if ( isAttachment() )
588 const KMMessagePart & p = msgPart();
589 return !p.fileName().isEmpty() || !p.name().isEmpty() ;
592 partNode * partNode::next(
bool allowChildren )
const {
594 if ( partNode * c = firstChild() )
596 if ( partNode * s = nextSibling() )
598 for ( partNode * p = parentNode() ; p ; p = p->parentNode() )
599 if ( partNode * s = p->nextSibling() )
604 bool partNode::isFirstTextPart()
const {
605 if ( type() != DwMime::kTypeText )
607 const partNode * root =
this;
610 while (
const partNode * p = root->parentNode() ) {
611 if ( p->type() == DwMime::kTypeMessage )
616 for (
const partNode * n = root ; n ; n = n->next() )
617 if ( n->type() == DwMime::kTypeText )
619 kdFatal() <<
"partNode::isFirstTextPart(): Didn't expect to end up here..." << endl;
623 bool partNode::isToltecMessage()
const
625 if ( type() != DwMime::kTypeMultipart || subType() != DwMime::kSubtypeMixed )
628 if ( childCount() != 3 )
631 const DwField* library = dwPart()->Headers().FindField(
"X-Library" );
635 if ( !library->FieldBody() ||
636 TQString( library->FieldBody()->AsString().c_str() ) != TQString(
"Toltec" ) )
639 const DwField* kolabType = dwPart()->Headers().FindField(
"X-Kolab-Type" );
643 if ( !kolabType->FieldBody() ||
644 !TQString( kolabType->FieldBody()->AsString().c_str() ).startsWith(
"application/x-vnd.kolab" ) )
650 bool partNode::isInEncapsulatedMessage()
const
652 const partNode *
const topLevel = topLevelParent();
653 const partNode *cur =
this;
654 while ( cur && cur != topLevel ) {
655 const bool parentIsMessage = cur->parentNode() &&
656 cur->parentNode()->msgPart().typeStr().lower() ==
"message";
657 if ( parentIsMessage && cur->parentNode() != topLevel )
659 cur = cur->parentNode();
664 bool partNode::hasContentDispositionInline()
const
668 DwHeaders& headers = dwPart()->Headers();
669 if( headers.HasContentDisposition() )
670 return ( headers.ContentDisposition().DispositionType()
671 == DwMime::kDispTypeInline );
676 const TQString& partNode::trueFromAddress()
const
678 const partNode* node =
this;
679 while( node->mFromAddress.isEmpty() && node->mRoot )
681 return node->mFromAddress;
687 return r->bodyPartMemento(
this, which );
689 return internalBodyPartMemento( which );
696 const std::map<TQCString,KMail::Interface::BodyPartMemento*>::const_iterator it = mBodyPartMementoMap.find( which.lower() );
697 return it != mBodyPartMementoMap.end() ? it->second : 0 ;
703 r->setBodyPartMemento(
this, which, memento );
705 internalSetBodyPartMemento( which, memento );
712 const std::map<TQCString,KMail::Interface::BodyPartMemento*>::iterator it = mBodyPartMementoMap.lower_bound( which.lower() );
713 if ( it != mBodyPartMementoMap.end() && it->first == which.lower() ) {
716 it->second = memento;
719 mBodyPartMementoMap.erase( it );
722 mBodyPartMementoMap.insert( it, std::make_pair( which.lower(), memento ) );
726 bool partNode::isDisplayedEmbedded()
const
728 return mDisplayedEmbedded;
731 void partNode::setDisplayedEmbedded(
bool displayedEmbedded )
733 mDisplayedEmbedded = displayedEmbedded;
736 bool partNode::isDisplayedHidden()
const
738 return mDisplayedHidden;
741 void partNode::setDisplayedHidden(
bool displayedHidden )
743 mDisplayedHidden = displayedHidden;
747 TQString partNode::asHREF(
const TQString &place )
const
749 return TQString(
"attachment:%1?place=%2" ).arg( nodeId() ).arg( place );
752 partNode::AttachmentDisplayInfo partNode::attachmentDisplayInfo()
const
754 AttachmentDisplayInfo info;
755 info.icon = msgPart().iconName( TDEIcon::Small );
756 info.label = msgPart().name().stripWhiteSpace();
757 if ( info.label.isEmpty() )
758 info.label = msgPart().fileName();
759 if ( info.label.isEmpty() )
760 info.label = msgPart().contentDescription();
761 bool typeBlacklisted = msgPart().typeStr().lower() ==
"multipart";
762 if ( !typeBlacklisted && msgPart().typeStr().lower() ==
"application" ) {
763 typeBlacklisted = msgPart().subtypeStr() ==
"pgp-encrypted"
764 || msgPart().subtypeStr().lower() ==
"pgp-signature"
765 || msgPart().subtypeStr().lower() ==
"pkcs7-mime"
766 || msgPart().subtypeStr().lower() ==
"pkcs7-signature";
768 typeBlacklisted = typeBlacklisted ||
this == topLevelParent();
769 bool firstTextChildOfEncapsulatedMsg = msgPart().typeStr().lower() ==
"text" &&
770 msgPart().subtypeStr().lower() ==
"plain" &&
772 parentNode()->msgPart().typeStr().lower() ==
"message";
773 typeBlacklisted = typeBlacklisted || firstTextChildOfEncapsulatedMsg;
774 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.