kmail

partNode.cpp
1 /* -*- c++ -*-
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 
58 partNode::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 
77 partNode::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 
107 partNode * 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 
134 partNode::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 
157 partNode::~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
169 void 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
179 void partNode::dump( int ) const {}
180 #endif
181 
182 const 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 
195 void 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 
225 TQCString partNode::typeString() const {
226  DwString s;
227  DwTypeEnumToStr( type(), s );
228  return s.c_str();
229 }
230 
231 TQCString partNode::subTypeString() const {
232  DwString s;
233  DwSubtypeEnumToStr( subType(), s );
234  return s.c_str();
235 }
236 
237 const partNode* partNode::topLevelParent() const {
238  const partNode *ret = this;
239  while ( ret->parentNode() )
240  ret = ret->parentNode();
241  return ret;
242 }
243 
244 int partNode::childCount() const {
245  int count = 0;
246  for ( partNode * child = firstChild() ; child ; child = child->nextSibling() )
247  ++ count;
248  return count;
249 }
250 
251 int 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 
260 TQString 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 
278 KMMsgEncryptionState 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 
319 KMMsgSignatureState 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 
359 TQCString 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 
375 int 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 
385 partNode* 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 
397 int 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 
424 partNode* 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 
439 partNode* 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 
451 partNode* 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 
466 void 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 
545 void 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 
565 bool 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 
585 bool partNode::isHeuristicalAttachment() const {
586  if ( isAttachment() )
587  return true;
588  const KMMessagePart & p = msgPart();
589  return !p.fileName().isEmpty() || !p.name().isEmpty() ;
590 }
591 
592 partNode * 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 
604 bool 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 
623 bool 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 
650 bool 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 
664 bool 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 
676 const 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 
684 KMail::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 
692 KMail::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 
700 void 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 
708 void 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 
726 bool partNode::isDisplayedEmbedded() const
727 {
728  return mDisplayedEmbedded;
729 }
730 
731 void partNode::setDisplayedEmbedded( bool displayedEmbedded )
732 {
733  mDisplayedEmbedded = displayedEmbedded;
734 }
735 
736 bool partNode::isDisplayedHidden() const
737 {
738  return mDisplayedHidden;
739 }
740 
741 void partNode::setDisplayedHidden( bool displayedHidden )
742 {
743  mDisplayedHidden = displayedHidden;
744 }
745 
746 
747 TQString partNode::asHREF( const TQString &place ) const
748 {
749  return TQString( "attachment:%1?place=%2" ).arg( nodeId() ).arg( place );
750 }
751 
752 partNode::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 class implements a "reader window", that is a window used for reading or viewing messages...
Definition: kmreaderwin.h:76
TQString from() const
Get or set the &#39;From&#39; header field.
Definition: kmmessage.cpp:2018
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
This is a Mime Message.
Definition: kmmessage.h:68