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 
57 partNode::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 
76 partNode::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 
106 partNode * 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 
133 partNode::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 
156 partNode::~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
168 void 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
178 void partNode::dump( int ) const {}
179 #endif
180 
181 const 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 
194 void 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 
224 TQCString partNode::typeString() const {
225  DwString s;
226  DwTypeEnumToStr( type(), s );
227  return s.c_str();
228 }
229 
230 TQCString partNode::subTypeString() const {
231  DwString s;
232  DwSubtypeEnumToStr( subType(), s );
233  return s.c_str();
234 }
235 
236 const partNode* partNode::topLevelParent() const {
237  const partNode *ret = this;
238  while ( ret->parentNode() )
239  ret = ret->parentNode();
240  return ret;
241 }
242 
243 int partNode::childCount() const {
244  int count = 0;
245  for ( partNode * child = firstChild() ; child ; child = child->nextSibling() )
246  ++ count;
247  return count;
248 }
249 
250 int 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 
259 TQString 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 
277 KMMsgEncryptionState 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 
318 KMMsgSignatureState 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 
358 TQCString 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 
374 int 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 
384 partNode* 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 
396 int 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 
423 partNode* 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 
438 partNode* 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 
450 partNode* 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 
465 void 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 
544 void 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 
564 bool 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 
584 bool partNode::isHeuristicalAttachment() const {
585  if ( isAttachment() )
586  return true;
587  const KMMessagePart & p = msgPart();
588  return !p.fileName().isEmpty() || !p.name().isEmpty() ;
589 }
590 
591 partNode * 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 
603 bool 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 
622 bool 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 
649 bool 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 
663 bool 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 
675 const 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 
683 KMail::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 
691 KMail::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 
699 void 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 
707 void 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 
725 bool partNode::isDisplayedEmbedded() const
726 {
727  return mDisplayedEmbedded;
728 }
729 
730 void partNode::setDisplayedEmbedded( bool displayedEmbedded )
731 {
732  mDisplayedEmbedded = displayedEmbedded;
733 }
734 
735 bool partNode::isDisplayedHidden() const
736 {
737  return mDisplayedHidden;
738 }
739 
740 void partNode::setDisplayedHidden( bool displayedHidden )
741 {
742  mDisplayedHidden = displayedHidden;
743 }
744 
745 
746 TQString partNode::asHREF( const TQString &place ) const
747 {
748  return TQString( "attachment:%1?place=%2" ).arg( nodeId() ).arg( place );
749 }
750 
751 partNode::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