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' ) )
163 return d_ptr->preamble;
174 return d_ptr->epilogue;
189 h_eaders = HeaderParsing::parseHeaders( d->head );
197 d->frozenBody = d->body;
201 qDeleteAll( d->multipartContents );
202 d->multipartContents.clear();
203 d->clearBodyMessage();
208 if( d->parseUuencoded() ) {
210 }
else if( d->parseYenc() ) {
218 if( d->parseMultipart() ) {
230 d->bodyAsMessage->setContent( d->body );
231 d->bodyAsMessage->setFrozen( d->frozen );
232 d->bodyAsMessage->parse();
233 d->bodyAsMessage->d_ptr->parent =
this;
244 return d_ptr->frozen;
249 d_ptr->frozen = frozen;
291 qDeleteAll( d->multipartContents );
293 d->multipartContents.clear();
294 d->clearBodyMessage();
321 if( d->frozenBody.isEmpty() ) {
332 e += d->bodyAsMessage->encodedContent();
333 }
else if( !d->body.isEmpty() ) {
338 if ( enc->
encoding() == Headers::CEquPr ) {
339 e += KCodecs::quotedPrintableEncode( d->body,
false );
341 e += KCodecs::base64Encode( d->body,
true );
349 if ( !d->frozen && !d->multipartContents.isEmpty() ) {
352 QByteArray boundary =
"\n--" + ct->
boundary();
354 if ( !d->preamble.isEmpty() )
358 foreach (
Content *c, d->multipartContents ) {
363 e += boundary+
"--\n";
365 if ( !d->epilogue.isEmpty() )
375 bool removeTrailingNewline=
false;
377 if ( d_ptr->body.length() == 0 ) {
383 removeTrailingNewline =
true;
386 case Headers::CEbase64 :
392 QByteArray::const_iterator inputIt = d_ptr->body.constBegin();
393 QByteArray::iterator resultIt = ret.begin();
394 decoder->
decode( inputIt, d_ptr->body.constEnd(), resultIt, ret.end() );
395 ret.truncate( resultIt - ret.begin() );
398 case Headers::CEquPr :
399 ret = KCodecs::quotedPrintableDecode( d_ptr->body );
400 removeTrailingNewline =
true;
402 case Headers::CEuuenc :
403 KCodecs::uudecode( d_ptr->body, ret );
405 case Headers::CEbinary :
407 removeTrailingNewline =
false;
411 removeTrailingNewline =
true;
415 if ( removeTrailingNewline && ( ret.size() > 0 ) && ( ret[ret.size()-1] ==
'\n') ) {
416 ret.resize( ret.size() - 1 );
430 KGlobal::charsets()->codecForName( QLatin1String(
contentType()->charset() ), ok );
431 if ( !ok || codec == NULL ) {
432 codec = KGlobal::locale()->codecForEncoding();
433 QByteArray chset = KGlobal::locale()->encoding();
437 QString s = codec->toUnicode( d_ptr->body.data(), d_ptr->body.length() );
439 if ( trimText || removeTrailingNewlines ) {
441 for ( i = s.length() - 1; i >= 0; --i ) {
443 if ( !s[i].isSpace() ) {
448 if ( s[i] != QLatin1Char(
'\n' ) ) {
455 if ( s.right( 1 ) == QLatin1String(
"\n" ) ) {
456 s.truncate( s.length() - 1 );
467 KGlobal::charsets()->codecForName( QLatin1String(
contentType()->charset() ), ok );
470 codec = KGlobal::locale()->codecForEncoding();
471 QByteArray chset = KGlobal::locale()->encoding();
475 d_ptr->body = codec->fromUnicode( s );
499 if ( d_ptr->contents().isEmpty() ) {
500 attachments.append(
this );
503 if ( !incAlternatives &&
504 c->
contentType()->category() == Headers::CCalternativePart ) {
515 attachments.removeAll( text );
523 return d_ptr->contents();
541 for ( Headers::Base::List::iterator it =
h_eaders.begin();
543 if ( (*it)->isMimeHeader() ) {
554 main->
contentType()->setCategory( Headers::CCmixedPart );
561 d->multipartContents.append( main );
567 ct->setCategory( Headers::CCcontainer );
573 d->multipartContents.prepend( c );
575 d->multipartContents.append( c );
578 if( c->
parent() != this ) {
587 if ( d->multipartContents.isEmpty() || !d->multipartContents.contains( c ) ) {
595 d->multipartContents.removeAll( c );
603 if( d->multipartContents.count() == 1 ) {
604 Content *main = d->multipartContents.first();
614 d->body = main->
body();
618 d->multipartContents.
clear();
640 if( e == Headers::CEbase64 ) {
642 d_ptr->body.append(
"\n" );
656 if ( scrambleFromLines ) {
660 ret.replace(
"\n\nFrom ",
"\n\n>From ");
667 return d_ptr->nextHeader( head );
672 return d_ptr->nextHeader( head );
677 Headers::Base *header = HeaderParsing::extractFirstHeader( _head );
694 Q_ASSERT( type && *type );
697 if( h->
is( type ) ) {
707 Q_ASSERT( type && *type );
712 if( h->
is( type ) ) {
741 for ( Headers::Base::List::iterator it =
h_eaders.begin();
743 if ( (*it)->is(type) ) {
759 int ret = d_ptr->body.length();
776 int s = d->head.size();
778 if ( d->contents().isEmpty() ) {
797 ret += d->head.count(
'\n' );
799 ret += d->body.count(
'\n' );
832 case Headers::CEbase64 :
833 d->body = KCodecs::base64Decode( d->body );
834 d->body.append(
"\n" );
836 case Headers::CEquPr :
837 d->body = KCodecs::quotedPrintableDecode( d->body );
839 case Headers::CEuuenc :
840 d->body = KCodecs::uudecode( d->body );
841 d->body.append(
"\n" );
843 case Headers::CEbinary :
845 d->body.append(
"\n" );
856 return d_ptr->defaultCS;
874 return d_ptr->forceDefaultCS;
879 d_ptr->forceDefaultCS = b;
896 unsigned int i = idx.
pop() - 1;
897 if ( i < (
unsigned int)d_ptr->contents().size() ) {
898 return d_ptr->contents()[i]->content( idx );
906 int i = d_ptr->contents().indexOf( content );
913 for (
int i = 0; i < d_ptr->contents().size(); ++i ) {
914 ContentIndex ci = d_ptr->contents()[i]->indexForContent( content );
926 return d_ptr->parent == 0;
934 if ( !oldParent->
contents().isEmpty() && oldParent->
contents().contains(
this ) ) {
941 if ( !parent->
contents().isEmpty() && !parent->
contents().contains(
this ) ) {
977 return d_ptr->bodyAsMessage;
987 return const_cast<Content*
>( this )->header<Headers::ContentType>(
false ) &&
988 const_cast<Content*
>( this )->header<Headers::ContentType>(
true )
989 ->mimeType().toLower() ==
"message/rfc822";
993 #define kmime_mk_header_accessor( type, method ) \
994 Headers::type *Content::method( bool create ) { \
995 return header<Headers::type>( create ); \
998 kmime_mk_header_accessor( ContentType, contentType )
999 kmime_mk_header_accessor( ContentTransferEncoding, contentTransferEncoding )
1000 kmime_mk_header_accessor( ContentDisposition, contentDisposition )
1001 kmime_mk_header_accessor( ContentDescription, contentDescription )
1002 kmime_mk_header_accessor( ContentLocation, contentLocation )
1003 kmime_mk_header_accessor( ContentID, contentID )
1005 #undef kmime_mk_header_accessor
1009 void ContentPrivate::clearBodyMessage()
1011 bodyAsMessage.reset();
1016 Q_ASSERT( multipartContents.isEmpty() || !bodyAsMessage );
1017 if ( bodyAsMessage )
1020 return multipartContents;
1023 bool ContentPrivate::parseUuencoded()
1027 if( !uup.parse() ) {
1034 if( uup.isPartial() ) {
1039 q->contentTransferEncoding()->setEncoding( Headers::CE7Bit );
1045 ct->setCategory( Headers::CCcontainer );
1046 q->contentTransferEncoding()->clear();
1049 Q_ASSERT( multipartContents.count() == 0 );
1055 multipartContents.append( c );
1059 for(
int i = 0; i < uup.binaryParts().count(); ++i ) {
1062 c->
contentType()->
setName( QLatin1String( uup.filenames().at( i ) ), QByteArray( ) );
1067 c->
setBody( uup.binaryParts().at( i ) );
1069 multipartContents.append( c );
1076 bool ContentPrivate::parseYenc()
1080 if( !yenc.parse() ) {
1087 if( yenc.isPartial() ) {
1092 q->contentTransferEncoding()->setEncoding( Headers::CEbinary );
1093 q->changeEncoding( Headers::CEbase64 );
1099 ct->setCategory( Headers::CCcontainer );
1100 q->contentTransferEncoding()->clear();
1103 Q_ASSERT( multipartContents.count() == 0 );
1108 c->
setBody( yenc.textPart() );
1109 multipartContents.append( c );
1113 for (
int i=0; i<yenc.binaryParts().count(); i++ ) {
1116 c->
contentType()->
setName( QLatin1String( yenc.filenames().at( i ) ), QByteArray( ) );
1120 c->
setBody( yenc.binaryParts().at( i ) );
1122 multipartContents.append( c );
1129 bool ContentPrivate::parseMultipart()
1133 const QByteArray boundary = ct->
boundary();
1134 if( boundary.isEmpty() ) {
1138 if( !mpp.parse() ) {
1142 preamble = mpp.preamble();
1143 epilogue = mpp.epilouge();
1146 Headers::contentCategory cat;
1148 cat = Headers::CCalternativePart;
1150 cat = Headers::CCmixedPart;
1154 Q_ASSERT( multipartContents.isEmpty() );
1156 QList<QByteArray> parts = mpp.parts();
1157 foreach(
const QByteArray &part, mpp.parts() ) {
1163 multipartContents.append( c );