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>
50 #include <klocalizedstring.h>
53 #include <QtCore/QTextCodec>
54 #include <QtCore/QTextStream>
55 #include <QtCore/QByteArray>
57 using namespace KMime;
62 : d_ptr( new ContentPrivate( this ) )
67 : d_ptr( new ContentPrivate( this ) )
73 : d_ptr( new ContentPrivate( this ) )
80 : d_ptr( new ContentPrivate( this ) )
102 return !d_ptr->head.isEmpty() || !d_ptr->body.isEmpty() || !d_ptr->contents().isEmpty();
113 QTextStream hts( &( d->head ), QIODevice::WriteOnly );
114 QTextStream bts( &( d->body ), QIODevice::WriteOnly );
115 hts.setCodec(
"ISO 8859-1" );
116 bts.setCodec(
"ISO 8859-1" );
119 foreach (
const QByteArray& line, l ) {
120 if ( isHead && line.isEmpty() ) {
137 KMime::HeaderParsing::extractHeaderAndBody( s, d->head, d->body );
148 if ( !head.endsWith(
'\n' ) ) {
165 return d_ptr->preamble;
176 return d_ptr->epilogue;
191 h_eaders = HeaderParsing::parseHeaders( d->head );
199 d->frozenBody = d->body;
203 qDeleteAll( d->multipartContents );
204 d->multipartContents.clear();
205 d->clearBodyMessage();
210 if ( d->parseUuencoded() ) {
212 }
else if ( d->parseYenc() ) {
220 if ( d->parseMultipart() ) {
232 d->bodyAsMessage->setContent( d->body );
233 d->bodyAsMessage->setFrozen( d->frozen );
234 d->bodyAsMessage->parse();
235 d->bodyAsMessage->d_ptr->parent =
this;
246 return d_ptr->frozen;
251 d_ptr->frozen = frozen;
293 qDeleteAll( d->multipartContents );
295 d->multipartContents.clear();
296 d->clearBodyMessage();
323 if ( d->frozenBody.isEmpty() ) {
334 e += d->bodyAsMessage->encodedContent();
335 }
else if ( !d->body.isEmpty() ) {
340 if ( enc->
encoding() == Headers::CEquPr ) {
341 e += KCodecs::quotedPrintableEncode( d->body,
false );
343 e += KCodecs::base64Encode( d->body,
true );
351 if ( !d->frozen && !d->multipartContents.isEmpty() ) {
354 QByteArray boundary =
"\n--" + ct->
boundary();
356 if ( !d->preamble.isEmpty() ) {
361 foreach (
Content *c, d->multipartContents ) {
362 e += boundary +
'\n';
366 e += boundary+
"--\n";
368 if ( !d->epilogue.isEmpty() ) {
379 bool removeTrailingNewline=
false;
381 if ( d_ptr->body.length() == 0 ) {
391 case Headers::CEbase64 :
397 QByteArray::const_iterator inputIt = d_ptr->body.constBegin();
398 QByteArray::iterator resultIt = ret.begin();
399 decoder->
decode( inputIt, d_ptr->body.constEnd(), resultIt, ret.end() );
400 ret.truncate( resultIt - ret.begin() );
403 case Headers::CEquPr :
404 ret = KCodecs::quotedPrintableDecode( d_ptr->body );
405 removeTrailingNewline =
true;
407 case Headers::CEuuenc :
408 KCodecs::uudecode( d_ptr->body, ret );
410 case Headers::CEbinary :
412 removeTrailingNewline =
false;
416 removeTrailingNewline =
true;
420 if ( removeTrailingNewline && ( ret.size() > 0 ) && ( ret[ret.size() - 1] ==
'\n' ) ) {
421 ret.resize( ret.size() - 1 );
435 KGlobal::charsets()->codecForName( QLatin1String(
contentType()->charset() ), ok );
436 if ( !ok || codec == NULL ) {
437 codec = KGlobal::locale()->codecForEncoding();
438 QByteArray chset = KGlobal::locale()->encoding();
442 QString s = codec->toUnicode( d_ptr->body.data(), d_ptr->body.length() );
444 if ( trimText || removeTrailingNewlines ) {
446 for ( i = s.length() - 1; i >= 0; --i ) {
448 if ( !s[i].isSpace() ) {
453 if ( s[i] != QLatin1Char(
'\n' ) ) {
460 if ( s.right( 1 ) == QLatin1String(
"\n" ) ) {
461 s.truncate( s.length() - 1 );
472 KGlobal::charsets()->codecForName( QLatin1String(
contentType()->charset() ), ok );
475 codec = KGlobal::locale()->codecForEncoding();
476 QByteArray chset = KGlobal::locale()->encoding();
480 d_ptr->body = codec->fromUnicode( s );
504 if ( d_ptr->contents().isEmpty() ) {
505 attachments.append(
this );
508 if ( !incAlternatives &&
509 c->
contentType()->category() == Headers::CCalternativePart ) {
520 attachments.removeAll( text );
528 return d_ptr->contents();
546 for ( Headers::Base::List::iterator it =
h_eaders.begin();
548 if ( (*it)->isMimeHeader() ) {
559 main->
contentType()->setCategory( Headers::CCmixedPart );
566 d->multipartContents.append( main );
572 ct->setCategory( Headers::CCcontainer );
578 d->multipartContents.prepend( c );
580 d->multipartContents.append( c );
583 if( c->
parent() != this ) {
592 if ( d->multipartContents.isEmpty() || !d->multipartContents.contains( c ) ) {
600 d->multipartContents.removeAll( c );
608 if( d->multipartContents.count() == 1 ) {
609 Content *main = d->multipartContents.first();
619 d->body = main->
body();
623 d->multipartContents.
clear();
645 if( e == Headers::CEbase64 ) {
647 d_ptr->body.append(
"\n" );
661 if ( scrambleFromLines ) {
665 ret.replace(
"\n\nFrom ",
"\n\n>From ");
672 return d_ptr->nextHeader( head );
677 return d_ptr->nextHeader( head );
682 Headers::Base *header = HeaderParsing::extractFirstHeader( _head );
699 Q_ASSERT( type && *type );
702 if( h->
is( type ) ) {
712 Q_ASSERT( type && *type );
717 if( h->
is( type ) ) {
746 for ( Headers::Base::List::iterator it =
h_eaders.begin();
748 if ( (*it)->is(type) ) {
764 int ret = d_ptr->body.length();
781 int s = d->head.size();
783 if ( d->contents().isEmpty() ) {
802 ret += d->head.count(
'\n' );
804 ret += d->body.count(
'\n' );
837 case Headers::CEbase64 :
838 d->body = KCodecs::base64Decode( d->body );
839 d->body.append(
"\n" );
841 case Headers::CEquPr :
842 d->body = KCodecs::quotedPrintableDecode( d->body );
844 case Headers::CEuuenc :
845 d->body = KCodecs::uudecode( d->body );
846 d->body.append(
"\n" );
848 case Headers::CEbinary :
850 d->body.append(
"\n" );
860 return d_ptr->defaultCS;
878 return d_ptr->forceDefaultCS;
883 d_ptr->forceDefaultCS = b;
900 unsigned int i = idx.
pop() - 1;
901 if ( i < (
unsigned int)d_ptr->contents().size() ) {
902 return d_ptr->contents()[i]->content( idx );
910 int i = d_ptr->contents().indexOf( content );
917 for (
int i = 0; i < d_ptr->contents().size(); ++i ) {
918 ContentIndex ci = d_ptr->contents()[i]->indexForContent( content );
930 return d_ptr->parent == 0;
938 if ( !oldParent->
contents().isEmpty() && oldParent->
contents().contains(
this ) ) {
945 if ( !parent->
contents().isEmpty() && !parent->
contents().contains(
this ) ) {
981 return d_ptr->bodyAsMessage;
991 return const_cast<Content*
>( this )->header<Headers::ContentType>(
false ) &&
992 const_cast<Content*
>( this )->header<Headers::ContentType>(
true )
993 ->mimeType().toLower() ==
"message/rfc822";
997 #define kmime_mk_header_accessor( type, method ) \
998 Headers::type *Content::method( bool create ) { \
999 return header<Headers::type>( create ); \
1002 kmime_mk_header_accessor( ContentType, contentType )
1003 kmime_mk_header_accessor( ContentTransferEncoding, contentTransferEncoding )
1004 kmime_mk_header_accessor( ContentDisposition, contentDisposition )
1005 kmime_mk_header_accessor( ContentDescription, contentDescription )
1006 kmime_mk_header_accessor( ContentLocation, contentLocation )
1007 kmime_mk_header_accessor( ContentID, contentID )
1009 #undef kmime_mk_header_accessor
1013 void ContentPrivate::clearBodyMessage()
1015 bodyAsMessage.reset();
1020 Q_ASSERT( multipartContents.isEmpty() || !bodyAsMessage );
1021 if ( bodyAsMessage )
1024 return multipartContents;
1027 bool ContentPrivate::parseUuencoded()
1031 if( !uup.parse() ) {
1038 if( uup.isPartial() ) {
1043 q->contentTransferEncoding()->setEncoding( Headers::CE7Bit );
1049 ct->setCategory( Headers::CCcontainer );
1050 q->contentTransferEncoding()->clear();
1053 Q_ASSERT( multipartContents.count() == 0 );
1059 multipartContents.append( c );
1063 for(
int i = 0; i < uup.binaryParts().count(); ++i ) {
1066 c->
contentType()->
setName( QLatin1String( uup.filenames().at( i ) ), QByteArray( ) );
1071 c->
setBody( uup.binaryParts().at( i ) );
1073 multipartContents.append( c );
1080 bool ContentPrivate::parseYenc()
1084 if ( !yenc.parse() ) {
1091 if ( yenc.isPartial() ) {
1096 q->contentTransferEncoding()->setEncoding( Headers::CEbinary );
1097 q->changeEncoding( Headers::CEbase64 );
1103 ct->setCategory( Headers::CCcontainer );
1104 q->contentTransferEncoding()->clear();
1107 Q_ASSERT( multipartContents.count() == 0 );
1112 c->
setBody( yenc.textPart() );
1113 multipartContents.append( c );
1117 for (
int i=0; i<yenc.binaryParts().count(); i++ ) {
1120 c->
contentType()->
setName( QLatin1String( yenc.filenames().at( i ) ), QByteArray( ) );
1124 c->
setBody( yenc.binaryParts().at( i ) );
1126 multipartContents.append( c );
1133 bool ContentPrivate::parseMultipart()
1137 const QByteArray boundary = ct->
boundary();
1138 if ( boundary.isEmpty() ) {
1142 if ( !mpp.parse() ) {
1146 preamble = mpp.preamble();
1147 epilogue = mpp.epilouge();
1150 Headers::contentCategory cat;
1152 cat = Headers::CCalternativePart;
1154 cat = Headers::CCmixedPart;
1158 Q_ASSERT( multipartContents.isEmpty() );
1160 QList<QByteArray> parts = mpp.parts();
1161 foreach (
const QByteArray &part, mpp.parts() ) {
1167 multipartContents.append( c );