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