38 #include "kmime_content_p.h"
40 #include "kmime_message.h"
41 #include "kmime_header_parsing.h"
42 #include "kmime_header_parsing_p.h"
43 #include "kmime_parsers.h"
44 #include "kmime_util_p.h"
46 #include <kcharsets.h>
52 #include <QtCore/QTextCodec>
53 #include <QtCore/QTextStream>
54 #include <QtCore/QByteArray>
56 using namespace KMime;
61 : d_ptr( new ContentPrivate( this ) )
66 : d_ptr( new ContentPrivate( this ) )
72 : d_ptr( new ContentPrivate( this ) )
79 : d_ptr( new ContentPrivate( this ) )
101 return !d_ptr->head.isEmpty() || !d_ptr->body.isEmpty() || !d_ptr->contents().isEmpty();
112 QTextStream hts( &( d->head ), QIODevice::WriteOnly );
113 QTextStream bts( &( d->body ), QIODevice::WriteOnly );
114 hts.setCodec(
"ISO 8859-1" );
115 bts.setCodec(
"ISO 8859-1" );
118 foreach (
const QByteArray& line, l ) {
119 if ( isHead && line.isEmpty() ) {
136 KMime::HeaderParsing::extractHeaderAndBody( s, d->head, d->body );
147 if ( !head.endsWith(
'\n' ) ) {
164 return d_ptr->preamble;
175 return d_ptr->epilogue;
190 h_eaders = HeaderParsing::parseHeaders( d->head );
198 d->frozenBody = d->body;
202 qDeleteAll( d->multipartContents );
203 d->multipartContents.clear();
204 d->clearBodyMessage();
209 if ( d->parseUuencoded() ) {
211 }
else if ( d->parseYenc() ) {
219 if ( d->parseMultipart() ) {
231 d->bodyAsMessage->setContent( d->body );
232 d->bodyAsMessage->setFrozen( d->frozen );
233 d->bodyAsMessage->parse();
234 d->bodyAsMessage->d_ptr->parent =
this;
245 return d_ptr->frozen;
250 d_ptr->frozen = frozen;
292 qDeleteAll( d->multipartContents );
294 d->multipartContents.clear();
295 d->clearBodyMessage();
322 if ( d->frozenBody.isEmpty() ) {
333 e += d->bodyAsMessage->encodedContent();
334 }
else if ( !d->body.isEmpty() ) {
339 if ( enc->
encoding() == Headers::CEquPr ) {
340 e += KCodecs::quotedPrintableEncode( d->body,
false );
342 e += KCodecs::base64Encode( d->body,
true );
350 if ( !d->frozen && !d->multipartContents.isEmpty() ) {
353 QByteArray boundary =
"\n--" + ct->
boundary();
355 if ( !d->preamble.isEmpty() ) {
360 foreach (
Content *c, d->multipartContents ) {
361 e += boundary +
'\n';
365 e += boundary+
"--\n";
367 if ( !d->epilogue.isEmpty() ) {
378 bool removeTrailingNewline=
false;
380 if ( d_ptr->body.length() == 0 ) {
390 case Headers::CEbase64 :
396 QByteArray::const_iterator inputIt = d_ptr->body.constBegin();
397 QByteArray::iterator resultIt = ret.begin();
398 decoder->
decode( inputIt, d_ptr->body.constEnd(), resultIt, ret.end() );
399 ret.truncate( resultIt - ret.begin() );
402 case Headers::CEquPr :
403 ret = KCodecs::quotedPrintableDecode( d_ptr->body );
404 removeTrailingNewline =
true;
406 case Headers::CEuuenc :
407 KCodecs::uudecode( d_ptr->body, ret );
409 case Headers::CEbinary :
411 removeTrailingNewline =
false;
415 removeTrailingNewline =
true;
419 if ( removeTrailingNewline && ( ret.size() > 0 ) && ( ret[ret.size() - 1] ==
'\n' ) ) {
420 ret.resize( ret.size() - 1 );
434 KGlobal::charsets()->codecForName( QLatin1String(
contentType()->charset() ), ok );
435 if ( !ok || codec == NULL ) {
436 codec = KGlobal::locale()->codecForEncoding();
437 QByteArray chset = KGlobal::locale()->encoding();
441 QString s = codec->toUnicode( d_ptr->body.data(), d_ptr->body.length() );
443 if ( trimText || removeTrailingNewlines ) {
445 for ( i = s.length() - 1; i >= 0; --i ) {
447 if ( !s[i].isSpace() ) {
452 if ( s[i] != QLatin1Char(
'\n' ) ) {
459 if ( s.right( 1 ) == QLatin1String(
"\n" ) ) {
460 s.truncate( s.length() - 1 );
471 KGlobal::charsets()->codecForName( QLatin1String(
contentType()->charset() ), ok );
474 codec = KGlobal::locale()->codecForEncoding();
475 QByteArray chset = KGlobal::locale()->encoding();
479 d_ptr->body = codec->fromUnicode( s );
503 if ( d_ptr->contents().isEmpty() ) {
504 attachments.append(
this );
507 if ( !incAlternatives &&
508 c->
contentType()->category() == Headers::CCalternativePart ) {
519 attachments.removeAll( text );
527 return d_ptr->contents();
545 for ( Headers::Base::List::iterator it =
h_eaders.begin();
547 if ( (*it)->isMimeHeader() ) {
558 main->
contentType()->setCategory( Headers::CCmixedPart );
565 d->multipartContents.append( main );
571 ct->setCategory( Headers::CCcontainer );
577 d->multipartContents.prepend( c );
579 d->multipartContents.append( c );
582 if( c->
parent() != this ) {
591 if ( d->multipartContents.isEmpty() || !d->multipartContents.contains( c ) ) {
599 d->multipartContents.removeAll( c );
607 if( d->multipartContents.count() == 1 ) {
608 Content *main = d->multipartContents.first();
618 d->body = main->
body();
622 d->multipartContents.
clear();
644 if( e == Headers::CEbase64 ) {
646 d_ptr->body.append(
"\n" );
660 if ( scrambleFromLines ) {
664 ret.replace(
"\n\nFrom ",
"\n\n>From ");
671 return d_ptr->nextHeader( head );
676 return d_ptr->nextHeader( head );
681 Headers::Base *header = HeaderParsing::extractFirstHeader( _head );
698 Q_ASSERT( type && *type );
701 if( h->
is( type ) ) {
711 Q_ASSERT( type && *type );
716 if( h->
is( type ) ) {
745 for ( Headers::Base::List::iterator it =
h_eaders.begin();
747 if ( (*it)->is(type) ) {
763 int ret = d_ptr->body.length();
780 int s = d->head.size();
782 if ( d->contents().isEmpty() ) {
801 ret += d->head.count(
'\n' );
803 ret += d->body.count(
'\n' );
836 case Headers::CEbase64 :
837 d->body = KCodecs::base64Decode( d->body );
838 d->body.append(
"\n" );
840 case Headers::CEquPr :
841 d->body = KCodecs::quotedPrintableDecode( d->body );
843 case Headers::CEuuenc :
844 d->body = KCodecs::uudecode( d->body );
845 d->body.append(
"\n" );
847 case Headers::CEbinary :
849 d->body.append(
"\n" );
859 return d_ptr->defaultCS;
877 return d_ptr->forceDefaultCS;
882 d_ptr->forceDefaultCS = b;
899 unsigned int i = idx.
pop() - 1;
900 if ( i < (
unsigned int)d_ptr->contents().size() ) {
901 return d_ptr->contents()[i]->content( idx );
909 int i = d_ptr->contents().indexOf( content );
916 for (
int i = 0; i < d_ptr->contents().size(); ++i ) {
917 ContentIndex ci = d_ptr->contents()[i]->indexForContent( content );
929 return d_ptr->parent == 0;
937 if ( !oldParent->
contents().isEmpty() && oldParent->
contents().contains(
this ) ) {
944 if ( !parent->
contents().isEmpty() && !parent->
contents().contains(
this ) ) {
980 return d_ptr->bodyAsMessage;
990 return const_cast<Content*
>( this )->header<Headers::ContentType>(
false ) &&
991 const_cast<Content*
>( this )->header<Headers::ContentType>(
true )
992 ->mimeType().toLower() ==
"message/rfc822";
996 #define kmime_mk_header_accessor( type, method ) \
997 Headers::type *Content::method( bool create ) { \
998 return header<Headers::type>( create ); \
1001 kmime_mk_header_accessor( ContentType, contentType )
1002 kmime_mk_header_accessor( ContentTransferEncoding, contentTransferEncoding )
1003 kmime_mk_header_accessor( ContentDisposition, contentDisposition )
1004 kmime_mk_header_accessor( ContentDescription, contentDescription )
1005 kmime_mk_header_accessor( ContentLocation, contentLocation )
1006 kmime_mk_header_accessor( ContentID, contentID )
1008 #undef kmime_mk_header_accessor
1012 void ContentPrivate::clearBodyMessage()
1014 bodyAsMessage.reset();
1019 Q_ASSERT( multipartContents.isEmpty() || !bodyAsMessage );
1020 if ( bodyAsMessage )
1023 return multipartContents;
1026 bool ContentPrivate::parseUuencoded()
1030 if( !uup.parse() ) {
1037 if( uup.isPartial() ) {
1042 q->contentTransferEncoding()->setEncoding( Headers::CE7Bit );
1048 ct->setCategory( Headers::CCcontainer );
1049 q->contentTransferEncoding()->clear();
1052 Q_ASSERT( multipartContents.count() == 0 );
1058 multipartContents.append( c );
1062 for(
int i = 0; i < uup.binaryParts().count(); ++i ) {
1065 c->
contentType()->
setName( QLatin1String( uup.filenames().at( i ) ), QByteArray( ) );
1070 c->
setBody( uup.binaryParts().at( i ) );
1072 multipartContents.append( c );
1079 bool ContentPrivate::parseYenc()
1083 if ( !yenc.parse() ) {
1090 if ( yenc.isPartial() ) {
1095 q->contentTransferEncoding()->setEncoding( Headers::CEbinary );
1096 q->changeEncoding( Headers::CEbase64 );
1102 ct->setCategory( Headers::CCcontainer );
1103 q->contentTransferEncoding()->clear();
1106 Q_ASSERT( multipartContents.count() == 0 );
1111 c->
setBody( yenc.textPart() );
1112 multipartContents.append( c );
1116 for (
int i=0; i<yenc.binaryParts().count(); i++ ) {
1119 c->
contentType()->
setName( QLatin1String( yenc.filenames().at( i ) ), QByteArray( ) );
1123 c->
setBody( yenc.binaryParts().at( i ) );
1125 multipartContents.append( c );
1132 bool ContentPrivate::parseMultipart()
1136 const QByteArray boundary = ct->
boundary();
1137 if ( boundary.isEmpty() ) {
1141 if ( !mpp.parse() ) {
1145 preamble = mpp.preamble();
1146 epilogue = mpp.epilouge();
1149 Headers::contentCategory cat;
1151 cat = Headers::CCalternativePart;
1153 cat = Headers::CCmixedPart;
1157 Q_ASSERT( multipartContents.isEmpty() );
1159 QList<QByteArray> parts = mpp.parts();
1160 foreach (
const QByteArray &part, mpp.parts() ) {
1166 multipartContents.append( c );