kmail

partNode.cpp
1/*
2 partNode.cpp A node in a MIME tree.
3
4 This file is part of KMail, the KDE mail client.
5 Copyright (c) 2002 Klarälvdalens Datakonsult AB
6
7 KMail is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License, version 2, as
9 published by the Free Software Foundation.
10
11 KMail is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
20 In addition, as a special exception, the copyright holders give
21 permission to link the code of this program with any edition of
22 the TQt library by Trolltech AS, Norway (or with modified versions
23 of TQt that use the same license as TQt), and distribute linked
24 combinations including the two. You must obey the GNU General
25 Public License in all respects for all of the code used other than
26 TQt. If you modify this file, you may extend this exception to
27 your version of the file, but you are not obligated to do so. If
28 you do not wish to do so, delete this exception statement from
29 your version.
30*/
31
32#include <config.h>
33
34#include "partNode.h"
35#include "kmreaderwin.h"
36
37#include <tdelocale.h>
38#include <kdebug.h>
39#include "kmmimeparttree.h"
40#include <mimelib/utility.h>
41#include <tqregexp.h>
42#include <kasciistricmp.h>
43#include "util.h"
44
45/*
46 ===========================================================================
47
48
49 S T A R T O F T E M P O R A R Y M I M E C O D E
50
51
52 ===========================================================================
53 N O T E : The partNode structure will most likely be replaced by KMime.
54 It's purpose: Speed optimization for KDE 3. (khz, 28.11.01)
55 ===========================================================================
56*/
57
58partNode::partNode()
59 : mRoot( 0 ), mNext( 0 ), mChild( 0 ),
60 mWasProcessed( false ),
61 mDwPart( 0 ),
62 mType( DwMime::kTypeUnknown ),
63 mSubType( DwMime::kSubtypeUnknown ),
64 mEncryptionState( KMMsgNotEncrypted ),
65 mSignatureState( KMMsgNotSigned ),
66 mMsgPartOk( false ),
67 mEncodedOk( false ),
68 mDeleteDwBodyPart( false ),
69 mMimePartTreeItem( 0 ),
70 mBodyPartMementoMap(),
71 mReader( 0 ),
72 mDisplayedEmbedded( false )
73{
74 adjustDefaultType( this );
75}
76
77partNode::partNode( KMReaderWin * win, DwBodyPart* dwPart, int explicitType, int explicitSubType,
78 bool deleteDwBodyPart )
79 : mRoot( 0 ), mNext( 0 ), mChild( 0 ),
80 mWasProcessed( false ),
81 mDwPart( dwPart ),
82 mEncryptionState( KMMsgNotEncrypted ),
83 mSignatureState( KMMsgNotSigned ),
84 mMsgPartOk( false ),
85 mEncodedOk( false ),
86 mDeleteDwBodyPart( deleteDwBodyPart ),
87 mMimePartTreeItem( 0 ),
88 mBodyPartMementoMap(),
89 mReader( win ),
90 mDisplayedEmbedded( false ),
91 mDisplayedHidden( false )
92{
93 if ( explicitType != DwMime::kTypeUnknown ) {
94 mType = explicitType; // this happens e.g. for the Root Node
95 mSubType = explicitSubType; // representing the _whole_ message
96 } else {
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();
100 } else {
101 mType = DwMime::kTypeUnknown;
102 mSubType = DwMime::kSubtypeUnknown;
103 }
104 }
105}
106
107partNode * partNode::fromMessage( const KMMessage * msg, KMReaderWin * win ) {
108 if ( !msg )
109 return 0;
110
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;
117 }
118
119 // we don't want to treat the top-level part special. mimelib does
120 // (Message vs. BodyPart, with common base class Entity). But we
121 // used DwBodyPart, not DwEntiy everywhere. *shrug*. DwStrings are
122 // subscrib-shared, so we just force mimelib to parse the whole mail
123 // as just another DwBodyPart...
124 DwBodyPart * mainBody = new DwBodyPart( *msg->getTopLevelPart() );
125
126 partNode * root = new partNode( win, mainBody, mainType, mainSubType, true );
127 root->buildObjectTree();
128
129 root->setFromAddress( msg->from() );
130 //root->dump();
131 return root;
132}
133
134partNode::partNode( bool deleteDwBodyPart, DwBodyPart* dwPart )
135 : mRoot( 0 ), mNext( 0 ), mChild( 0 ),
136 mWasProcessed( false ),
137 mDwPart( dwPart ),
138 mEncryptionState( KMMsgNotEncrypted ),
139 mSignatureState( KMMsgNotSigned ),
140 mMsgPartOk( false ),
141 mEncodedOk( false ),
142 mDeleteDwBodyPart( deleteDwBodyPart ),
143 mMimePartTreeItem( 0 ),
144 mBodyPartMementoMap(),
145 mReader( 0 ),
146 mDisplayedEmbedded( false )
147{
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();
151 } else {
152 mType = DwMime::kTypeUnknown;
153 mSubType = DwMime::kSubtypeUnknown;
154 }
155}
156
157partNode::~partNode() {
158 if( mDeleteDwBodyPart )
159 delete mDwPart;
160 mDwPart = 0;
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 )
164 delete it->second;
165 mBodyPartMementoMap.clear();
166}
167
168#ifndef NDEBUG
169void partNode::dump( int chars ) const {
170 kdDebug(5006) << nodeId() << " " << TQString(TQString().fill( ' ', chars )) << "+ "
171 << typeString() << '/' << subTypeString() << " embedded:" << mDisplayedEmbedded
172 << " address:" << this << endl;
173 if ( mChild )
174 mChild->dump( chars + 1 );
175 if ( mNext )
176 mNext->dump( chars );
177}
178#else
179void partNode::dump( int ) const {}
180#endif
181
182const TQCString & partNode::encodedBody() {
183 if ( mEncodedOk )
184 return mEncodedBody;
185
186 if ( mDwPart )
187 mEncodedBody = KMail::Util::CString( mDwPart->Body().AsString() );
188 else
189 mEncodedBody = 0;
190 mEncodedOk = true;
191 return mEncodedBody;
192}
193
194
195void partNode::buildObjectTree( bool processSiblings )
196{
197 partNode* curNode = this;
198 while( curNode && curNode->dwPart() ) {
199 //dive into multipart messages
200 while( DwMime::kTypeMultipart == curNode->type() ) {
201 partNode * newNode = new partNode( mReader, curNode->dwPart()->Body().FirstBodyPart() );
202 curNode->setFirstChild( newNode );
203 curNode = newNode;
204 }
205 // go up in the tree until reaching a node with next
206 // (or the last top-level node)
207 while( curNode
208 && !( curNode->dwPart()
209 && curNode->dwPart()->Next() ) ) {
210 curNode = curNode->mRoot;
211 }
212 // we might have to leave when all children have been processed
213 if( this == curNode && !processSiblings )
214 return;
215 // store next node
216 if( curNode && curNode->dwPart() && curNode->dwPart()->Next() ) {
217 partNode* nextNode = new partNode( mReader, curNode->dwPart()->Next() );
218 curNode->setNext( nextNode );
219 curNode = nextNode;
220 } else
221 curNode = 0;
222 }
223}
224
225TQCString partNode::typeString() const {
226 DwString s;
227 DwTypeEnumToStr( type(), s );
228 return s.c_str();
229}
230
231TQCString partNode::subTypeString() const {
232 DwString s;
233 DwSubtypeEnumToStr( subType(), s );
234 return s.c_str();
235}
236
237const partNode* partNode::topLevelParent() const {
238 const partNode *ret = this;
239 while ( ret->parentNode() )
240 ret = ret->parentNode();
241 return ret;
242}
243
244int partNode::childCount() const {
245 int count = 0;
246 for ( partNode * child = firstChild() ; child ; child = child->nextSibling() )
247 ++ count;
248 return count;
249}
250
251int partNode::totalChildCount() const {
252 int count = 0;
253 for ( partNode * child = firstChild() ; child ; child = child->nextSibling() ) {
254 ++count;
255 count += child->totalChildCount();
256 }
257 return count;
258}
259
260TQString partNode::contentTypeParameter( const char * name ) const {
261 if ( !mDwPart || !mDwPart->hasHeaders() )
262 return TQString();
263 DwHeaders & headers = mDwPart->Headers();
264 if ( !headers.HasContentType() )
265 return TQString();
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(); // what a braindead design!
271 if ( this_attr == attr )
272 return TQString::fromLatin1( param->Value().data(), param->Value().size() );
273 // warning: misses rfc2231 handling!
274 }
275 return TQString();
276}
277
278KMMsgEncryptionState partNode::overallEncryptionState() const
279{
280 KMMsgEncryptionState myState = KMMsgEncryptionStateUnknown;
281 if( mEncryptionState == KMMsgNotEncrypted ) {
282 // NOTE: children are tested ONLY when parent is not encrypted
283 if( mChild )
284 myState = mChild->overallEncryptionState();
285 else
286 myState = KMMsgNotEncrypted;
287 }
288 else { // part is partially or fully encrypted
289 myState = mEncryptionState;
290 }
291 // siblings are tested always
292 if( mNext ) {
293 KMMsgEncryptionState otherState = mNext->overallEncryptionState();
294 switch( otherState ) {
295 case KMMsgEncryptionStateUnknown:
296 break;
297 case KMMsgNotEncrypted:
298 if( myState == KMMsgFullyEncrypted )
299 myState = KMMsgPartiallyEncrypted;
300 else if( myState != KMMsgPartiallyEncrypted )
301 myState = KMMsgNotEncrypted;
302 break;
303 case KMMsgPartiallyEncrypted:
304 myState = KMMsgPartiallyEncrypted;
305 break;
306 case KMMsgFullyEncrypted:
307 if( myState != KMMsgFullyEncrypted )
308 myState = KMMsgPartiallyEncrypted;
309 break;
310 case KMMsgEncryptionProblematic:
311 break;
312 }
313 }
314
315 return myState;
316}
317
318
319KMMsgSignatureState partNode::overallSignatureState() const
320{
321 KMMsgSignatureState myState = KMMsgSignatureStateUnknown;
322 if( mSignatureState == KMMsgNotSigned ) {
323 // children are tested ONLY when parent is not signed
324 if( mChild )
325 myState = mChild->overallSignatureState();
326 else
327 myState = KMMsgNotSigned;
328 }
329 else { // part is partially or fully signed
330 myState = mSignatureState;
331 }
332 // siblings are tested always
333 if( mNext ) {
334 KMMsgSignatureState otherState = mNext->overallSignatureState();
335 switch( otherState ) {
336 case KMMsgSignatureStateUnknown:
337 break;
338 case KMMsgNotSigned:
339 if( myState == KMMsgFullySigned )
340 myState = KMMsgPartiallySigned;
341 else if( myState != KMMsgPartiallySigned )
342 myState = KMMsgNotSigned;
343 break;
344 case KMMsgPartiallySigned:
345 myState = KMMsgPartiallySigned;
346 break;
347 case KMMsgFullySigned:
348 if( myState != KMMsgFullySigned )
349 myState = KMMsgPartiallySigned;
350 break;
351 case KMMsgEncryptionProblematic:
352 break;
353 }
354 }
355
356 return myState;
357}
358
359TQCString partNode::path() const
360{
361 if ( !parentNode() )
362 return ':';
363 const partNode * p = parentNode();
364
365 // count number of siblings with the same type as us:
366 int nth = 0;
367 for ( const partNode * c = p->firstChild() ; c != this ; c = c->nextSibling() )
368 if ( c->type() == type() && c->subType() == subType() )
369 ++nth;
370
371 return p->path() + TQCString().sprintf( ":%X/%X[%X]", type(), subType(), nth );
372}
373
374
375int partNode::nodeId() const
376{
377 int curId = 0;
378 partNode* rootNode = const_cast<partNode*>( this );
379 while( rootNode->mRoot )
380 rootNode = rootNode->mRoot;
381 return rootNode->calcNodeIdOrFindNode( curId, this, 0, 0 );
382}
383
384
385partNode* partNode::findId( int id )
386{
387 int curId = 0;
388 partNode* rootNode = this;
389 while( rootNode->mRoot )
390 rootNode = rootNode->mRoot;
391 partNode* foundNode;
392 rootNode->calcNodeIdOrFindNode( curId, 0, id, &foundNode );
393 return foundNode;
394}
395
396
397int partNode::calcNodeIdOrFindNode( int &curId, const partNode* findNode, int findId, partNode** foundNode )
398{
399 // We use the same algorithm to determine the id of a node and
400 // to find the node when id is known.
401 curId++;
402 // check for node ?
403 if( findNode && this == findNode )
404 return curId;
405 // check for id ?
406 if( foundNode && curId == findId ) {
407 *foundNode = this;
408 return curId;
409 }
410 if( mChild )
411 {
412 int res = mChild->calcNodeIdOrFindNode( curId, findNode, findId, foundNode );
413 if (res != -1) return res;
414 }
415 if( mNext )
416 return mNext->calcNodeIdOrFindNode( curId, findNode, findId, foundNode );
417
418 if( foundNode )
419 *foundNode = 0;
420 return -1;
421}
422
423
424partNode* partNode::findType( int type, int subType, bool deep, bool wide )
425{
426 if( (mType != DwMime::kTypeUnknown)
427 && ( (type == DwMime::kTypeUnknown)
428 || (type == mType) )
429 && ( (subType == DwMime::kSubtypeUnknown)
430 || (subType == mSubType) ) )
431 return this;
432 if ( mChild && deep )
433 return mChild->findType( type, subType, deep, wide );
434 if ( mNext && wide )
435 return mNext->findType( type, subType, deep, wide );
436 return 0;
437}
438
439partNode* partNode::findNodeForDwPart( DwBodyPart* part )
440{
441 partNode* found = 0;
442 if( kasciistricmp( dwPart()->partId(), part->partId() ) == 0 )
443 return this;
444 if( mChild )
445 found = mChild->findNodeForDwPart( part );
446 if( mNext && !found )
447 found = mNext->findNodeForDwPart( part );
448 return found;
449}
450
451partNode* partNode::findTypeNot( int type, int subType, bool deep, bool wide )
452{
453 if( (mType != DwMime::kTypeUnknown)
454 && ( (type == DwMime::kTypeUnknown)
455 || (type != mType) )
456 && ( (subType == DwMime::kSubtypeUnknown)
457 || (subType != mSubType) ) )
458 return this;
459 if ( mChild && deep )
460 return mChild->findTypeNot( type, subType, deep, wide );
461 if ( mNext && wide )
462 return mNext->findTypeNot( type, subType, deep, wide );
463 return 0;
464}
465
466void partNode::fillMimePartTree( KMMimePartTreeItem* parentItem,
467 KMMimePartTree* mimePartTree,
468 TQString labelDescr,
469 TQString labelCntType,
470 TQString labelEncoding,
471 TDEIO::filesize_t size,
472 bool revertOrder )
473{
474 if( parentItem || mimePartTree ) {
475
476 if( mNext )
477 mNext->fillMimePartTree( parentItem, mimePartTree,
478 TQString(), TQString(), TQString(), 0,
479 revertOrder );
480
481 TQString cntDesc, cntType, cntEnc;
482 TDEIO::filesize_t cntSize = 0;
483
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();
492 cntType += '/';
493 cntType += headers->ContentType().SubtypeStr().c_str();
494 }
495 else
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");
506 else
507 cntDesc = i18n("body part");
508 }
509 cntEnc = msgPart().contentTransferEncodingStr();
510 if( mDwPart )
511 cntSize = mDwPart->BodySize();
512 } else {
513 cntDesc = labelDescr;
514 cntType = labelCntType;
515 cntEnc = labelEncoding;
516 cntSize = size;
517 }
518 // remove linebreak+whitespace from folded Content-Description
519 cntDesc.replace( TQRegExp("\\n\\s*"), " " );
520
521 if( parentItem )
522 mMimePartTreeItem = new KMMimePartTreeItem( parentItem,
523 this,
524 cntDesc,
525 cntType,
526 cntEnc,
527 cntSize,
528 revertOrder );
529 else if( mimePartTree )
530 mMimePartTreeItem = new KMMimePartTreeItem( mimePartTree,
531 this,
532 cntDesc,
533 cntType,
534 cntEnc,
535 cntSize );
536 mMimePartTreeItem->setOpen( true );
537 if( mChild )
538 mChild->fillMimePartTree( mMimePartTreeItem, 0,
539 TQString(), TQString(), TQString(), 0,
540 revertOrder );
541
542 }
543}
544
545void partNode::adjustDefaultType( partNode* node )
546{
547 // Only bodies of 'Multipart/Digest' objects have
548 // default type 'Message/RfC822'. All other bodies
549 // have default type 'Text/Plain' (khz, 5.12.2001)
550 if( node && DwMime::kTypeUnknown == node->type() ) {
551 if( node->mRoot
552 && DwMime::kTypeMultipart == node->mRoot->type()
553 && DwMime::kSubtypeDigest == node->mRoot->subType() ) {
554 node->setType( DwMime::kTypeMessage );
555 node->setSubType( DwMime::kSubtypeRfc822 );
556 }
557 else
558 {
559 node->setType( DwMime::kTypeText );
560 node->setSubType( DwMime::kSubtypePlain );
561 }
562 }
563}
564
565bool partNode::isAttachment() const
566{
567 if( !dwPart() )
568 return false;
569 if ( !dwPart()->hasHeaders() )
570 return false;
571 DwHeaders& headers = dwPart()->Headers();
572 if ( headers.HasContentType() &&
573 headers.ContentType().Type() == DwMime::kTypeMessage &&
574 headers.ContentType().Subtype() == DwMime::kSubtypeRfc822 ) {
575 // Messages are always attachments. Normally message attachments created from KMail have a content
576 // disposition, but some mail clients omit that.
577 return true;
578 }
579 if( !headers.HasContentDisposition() )
580 return false;
581 return ( headers.ContentDisposition().DispositionType()
582 == DwMime::kDispTypeAttachment );
583}
584
585bool partNode::isHeuristicalAttachment() const {
586 if ( isAttachment() )
587 return true;
588 const KMMessagePart & p = msgPart();
589 return !p.fileName().isEmpty() || !p.name().isEmpty() ;
590}
591
592partNode * partNode::next( bool allowChildren ) const {
593 if ( allowChildren )
594 if ( partNode * c = firstChild() )
595 return c;
596 if ( partNode * s = nextSibling() )
597 return s;
598 for ( partNode * p = parentNode() ; p ; p = p->parentNode() )
599 if ( partNode * s = p->nextSibling() )
600 return s;
601 return 0;
602}
603
604bool partNode::isFirstTextPart() const {
605 if ( type() != DwMime::kTypeText )
606 return false;
607 const partNode * root = this;
608 // go up until we reach the root node of a message (of the actual message or
609 // of an attached message)
610 while ( const partNode * p = root->parentNode() ) {
611 if ( p->type() == DwMime::kTypeMessage )
612 break;
613 else
614 root = p;
615 }
616 for ( const partNode * n = root ; n ; n = n->next() )
617 if ( n->type() == DwMime::kTypeText )
618 return n == this;
619 kdFatal() << "partNode::isFirstTextPart(): Didn't expect to end up here..." << endl;
620 return false; // make comiler happy
621}
622
623bool partNode::isToltecMessage() const
624{
625 if ( type() != DwMime::kTypeMultipart || subType() != DwMime::kSubtypeMixed )
626 return false;
627
628 if ( childCount() != 3 )
629 return false;
630
631 const DwField* library = dwPart()->Headers().FindField( "X-Library" );
632 if ( !library )
633 return false;
634
635 if ( !library->FieldBody() ||
636 TQString( library->FieldBody()->AsString().c_str() ) != TQString( "Toltec" ) )
637 return false;
638
639 const DwField* kolabType = dwPart()->Headers().FindField( "X-Kolab-Type" );
640 if ( !kolabType )
641 return false;
642
643 if ( !kolabType->FieldBody() ||
644 !TQString( kolabType->FieldBody()->AsString().c_str() ).startsWith( "application/x-vnd.kolab" ) )
645 return false;
646
647 return true;
648}
649
650bool partNode::isInEncapsulatedMessage() const
651{
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 )
658 return true;
659 cur = cur->parentNode();
660 }
661 return false;
662}
663
664bool partNode::hasContentDispositionInline() const
665{
666 if( !dwPart() )
667 return false;
668 DwHeaders& headers = dwPart()->Headers();
669 if( headers.HasContentDisposition() )
670 return ( headers.ContentDisposition().DispositionType()
671 == DwMime::kDispTypeInline );
672 else
673 return false;
674}
675
676const TQString& partNode::trueFromAddress() const
677{
678 const partNode* node = this;
679 while( node->mFromAddress.isEmpty() && node->mRoot )
680 node = node->mRoot;
681 return node->mFromAddress;
682}
683
684KMail::Interface::BodyPartMemento * partNode::bodyPartMemento( const TQCString & which ) const
685{
686 if ( const KMReaderWin * r = reader() )
687 return r->bodyPartMemento( this, which );
688 else
689 return internalBodyPartMemento( which );
690}
691
692KMail::Interface::BodyPartMemento * partNode::internalBodyPartMemento( const TQCString & which ) const
693{
694 assert( !reader() );
695
696 const std::map<TQCString,KMail::Interface::BodyPartMemento*>::const_iterator it = mBodyPartMementoMap.find( which.lower() );
697 return it != mBodyPartMementoMap.end() ? it->second : 0 ;
698}
699
700void partNode::setBodyPartMemento( const TQCString & which, KMail::Interface::BodyPartMemento * memento )
701{
702 if ( KMReaderWin * r = reader() )
703 r->setBodyPartMemento( this, which, memento );
704 else
705 internalSetBodyPartMemento( which, memento );
706}
707
708void partNode::internalSetBodyPartMemento( const TQCString & which, KMail::Interface::BodyPartMemento * memento )
709{
710 assert( !reader() );
711
712 const std::map<TQCString,KMail::Interface::BodyPartMemento*>::iterator it = mBodyPartMementoMap.lower_bound( which.lower() );
713 if ( it != mBodyPartMementoMap.end() && it->first == which.lower() ) {
714 delete it->second;
715 if ( memento ) {
716 it->second = memento;
717 }
718 else {
719 mBodyPartMementoMap.erase( it );
720 }
721 } else {
722 mBodyPartMementoMap.insert( it, std::make_pair( which.lower(), memento ) );
723 }
724}
725
726bool partNode::isDisplayedEmbedded() const
727{
728 return mDisplayedEmbedded;
729}
730
731void partNode::setDisplayedEmbedded( bool displayedEmbedded )
732{
733 mDisplayedEmbedded = displayedEmbedded;
734}
735
736bool partNode::isDisplayedHidden() const
737{
738 return mDisplayedHidden;
739}
740
741void partNode::setDisplayedHidden( bool displayedHidden )
742{
743 mDisplayedHidden = displayedHidden;
744}
745
746
747TQString partNode::asHREF( const TQString &place ) const
748{
749 return TQString( "attachment:%1?place=%2" ).arg( nodeId() ).arg( place );
750}
751
752partNode::AttachmentDisplayInfo partNode::attachmentDisplayInfo() const
753{
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";
767 }
768 typeBlacklisted = typeBlacklisted || this == topLevelParent();
769 bool firstTextChildOfEncapsulatedMsg = msgPart().typeStr().lower() == "text" &&
770 msgPart().subtypeStr().lower() == "plain" &&
771 parentNode() &&
772 parentNode()->msgPart().typeStr().lower() == "message";
773 typeBlacklisted = typeBlacklisted || firstTextChildOfEncapsulatedMsg;
774 info.displayInHeader = !info.label.isEmpty() && !info.icon.isEmpty() && !typeBlacklisted;
775 return info;
776}
This is a Mime Message.
Definition: kmmessage.h:68
TQString from() const
Get or set the 'From' header field.
Definition: kmmessage.cpp:2017
This class implements a "reader window", that is a window used for reading or viewing messages.
Definition: kmreaderwin.h:75
interface of classes that implement status for BodyPartFormatters.
Definition: bodypart.h:51
TQCString CString(const DwString &str)
Construct a TQCString from a DwString.
Definition: util.cpp:113