00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00037 #include "kmime_content.h"
00038 #include "kmime_content_p.h"
00039 #include "kmime_codecs.h"
00040 #include "kmime_message.h"
00041 #include "kmime_header_parsing.h"
00042 #include "kmime_header_parsing_p.h"
00043 #include "kmime_parsers.h"
00044 #include "kmime_util_p.h"
00045
00046 #include <kcharsets.h>
00047 #include <kcodecs.h>
00048 #include <kglobal.h>
00049 #include <klocale.h>
00050 #include <kdebug.h>
00051
00052 #include <QtCore/QTextCodec>
00053 #include <QtCore/QTextStream>
00054 #include <QtCore/QByteArray>
00055
00056 using namespace KMime;
00057
00058 namespace KMime {
00059
00060 Content::Content()
00061 : d_ptr( new ContentPrivate( this ) )
00062 {
00063 }
00064
00065 Content::Content( Content *parent )
00066 : d_ptr( new ContentPrivate( this ) )
00067 {
00068 d_ptr->parent = parent;
00069 }
00070
00071 Content::Content( const QByteArray &h, const QByteArray &b )
00072 : d_ptr( new ContentPrivate( this ) )
00073 {
00074 d_ptr->head = h;
00075 d_ptr->body = b;
00076 }
00077
00078 Content::Content( const QByteArray &h, const QByteArray &b, Content *parent )
00079 : d_ptr( new ContentPrivate( this ) )
00080 {
00081 d_ptr->head = h;
00082 d_ptr->body = b;
00083 d_ptr->parent = parent;
00084 }
00085
00086 Content::Content( ContentPrivate *d )
00087 : d_ptr( d )
00088 {
00089 }
00090
00091 Content::~Content()
00092 {
00093 qDeleteAll( h_eaders );
00094 h_eaders.clear();
00095 delete d_ptr;
00096 d_ptr = 0;
00097 }
00098
00099 bool Content::hasContent() const
00100 {
00101 return !d_ptr->head.isEmpty() || !d_ptr->body.isEmpty() || !d_ptr->contents().isEmpty();
00102 }
00103
00104 void Content::setContent( const QList<QByteArray> &l )
00105 {
00106 Q_D(Content);
00107
00108 d->head.clear();
00109 d->body.clear();
00110
00111
00112 QTextStream hts( &( d->head ), QIODevice::WriteOnly );
00113 QTextStream bts( &( d->body ), QIODevice::WriteOnly );
00114 hts.setCodec( "ISO 8859-1" );
00115 bts.setCodec( "ISO 8859-1" );
00116
00117 bool isHead = true;
00118 foreach ( const QByteArray& line, l ) {
00119 if ( isHead && line.isEmpty() ) {
00120 isHead = false;
00121 continue;
00122 }
00123 if ( isHead ) {
00124 hts << line << "\n";
00125 } else {
00126 bts << line << "\n";
00127 }
00128 }
00129
00130
00131 }
00132
00133 void Content::setContent( const QByteArray &s )
00134 {
00135 Q_D(Content);
00136 KMime::HeaderParsing::extractHeaderAndBody( s, d->head, d->body );
00137 }
00138
00139 QByteArray Content::head() const
00140 {
00141 return d_ptr->head;
00142 }
00143
00144 void Content::setHead( const QByteArray &head )
00145 {
00146 d_ptr->head = head;
00147 if ( !head.endsWith( '\n' ) )
00148 d_ptr->head += '\n';
00149 }
00150
00151 QByteArray Content::body() const
00152 {
00153 return d_ptr->body;
00154 }
00155
00156 void Content::setBody( const QByteArray &body )
00157 {
00158 d_ptr->body = body;
00159 }
00160
00161 void Content::parse()
00162 {
00163 Q_D( Content );
00164
00165
00166 qDeleteAll( h_eaders );
00167 h_eaders.clear();
00168 h_eaders = HeaderParsing::parseHeaders( d->head );
00169 foreach( Headers::Base *h, h_eaders ) {
00170 h->setParent( this );
00171 }
00172
00173
00174
00175 if( d->frozen ) {
00176 d->frozenBody = d->body;
00177 }
00178
00179
00180 qDeleteAll( d->multipartContents );
00181 d->multipartContents.clear();
00182 d->clearBodyMessage();
00183 Headers::ContentType *ct = contentType();
00184 if( ct->isText() ) {
00185
00186
00187 if( d->parseUuencoded() ) {
00188
00189 } else if( d->parseYenc() ) {
00190
00191 } else {
00192
00193 }
00194 } else if( ct->isMultipart() ) {
00195
00196
00197 if( d->parseMultipart() ) {
00198
00199 } else {
00200
00201 ct->setMimeType( "text/plain" );
00202 ct->setCharset( "US-ASCII" );
00203 }
00204 } else {
00205
00206
00207 if ( bodyIsMessage() ) {
00208 d->bodyAsMessage = Message::Ptr( new Message );
00209 d->bodyAsMessage->setContent( d->body );
00210 d->bodyAsMessage->setFrozen( d->frozen );
00211 d->bodyAsMessage->parse();
00212 d->bodyAsMessage->d_ptr->parent = this;
00213
00214
00215
00216 d->body.clear();
00217 }
00218 }
00219 }
00220
00221 bool Content::isFrozen() const
00222 {
00223 return d_ptr->frozen;
00224 }
00225
00226 void Content::setFrozen( bool frozen )
00227 {
00228 d_ptr->frozen = frozen;
00229 }
00230
00231 void Content::assemble()
00232 {
00233 Q_D( Content );
00234 if( d->frozen ) {
00235 return;
00236 }
00237
00238 d->head = assembleHeaders();
00239 foreach( Content *c, contents() ) {
00240 c->assemble();
00241 }
00242 }
00243
00244 QByteArray Content::assembleHeaders()
00245 {
00246 QByteArray newHead;
00247 foreach( const Headers::Base *h, h_eaders ) {
00248 if( !h->isEmpty() ) {
00249 newHead += h->as7BitString() + '\n';
00250 }
00251 }
00252
00253 return newHead;
00254 }
00255
00256 void Content::clear()
00257 {
00258 Q_D(Content);
00259 qDeleteAll( h_eaders );
00260 h_eaders.clear();
00261 clearContents();
00262 d->head.clear();
00263 d->body.clear();
00264 }
00265
00266 void Content::clearContents( bool del )
00267 {
00268 Q_D(Content);
00269 if( del ) {
00270 qDeleteAll( d->multipartContents );
00271 }
00272 d->multipartContents.clear();
00273 d->clearBodyMessage();
00274 }
00275
00276 QByteArray Content::encodedContent( bool useCrLf )
00277 {
00278 Q_D(Content);
00279 QByteArray e;
00280
00281
00282 e = d->head;
00283 e += '\n';
00284 e += encodedBody();
00285
00286 if ( useCrLf ) {
00287 return LFtoCRLF( e );
00288 } else {
00289 return e;
00290 }
00291 }
00292
00293 QByteArray Content::encodedBody()
00294 {
00295 Q_D( Content );
00296 QByteArray e;
00297
00298 if( d->frozen ) {
00299
00300 if( d->frozenBody.isEmpty() ) {
00301
00302 e += d->body;
00303 } else {
00304
00305 e += d->frozenBody;
00306 }
00307 } else if( bodyIsMessage() && d->bodyAsMessage ) {
00308
00309
00310
00311 e += d->bodyAsMessage->encodedContent();
00312 } else if( !d->body.isEmpty() ) {
00313
00314 Headers::ContentTransferEncoding *enc = contentTransferEncoding();
00315
00316 if ( enc->needToEncode() ) {
00317 if ( enc->encoding() == Headers::CEquPr ) {
00318 e += KCodecs::quotedPrintableEncode( d->body, false );
00319 } else {
00320 e += KCodecs::base64Encode( d->body, true );
00321 e += '\n';
00322 }
00323 } else {
00324 e += d->body;
00325 }
00326 }
00327
00328 if ( !d->frozen && !d->multipartContents.isEmpty() ) {
00329
00330 Headers::ContentType *ct=contentType();
00331 QByteArray boundary = "\n--" + ct->boundary();
00332
00333 if ( !d->preamble.isEmpty() )
00334 e += d->preamble;
00335
00336
00337 foreach ( Content *c, d->multipartContents ) {
00338 e+=boundary + '\n';
00339 e += c->encodedContent( false );
00340 }
00341
00342 e += boundary+"--\n";
00343
00344 if ( !d->epilogue.isEmpty() )
00345 e += d->epilogue;
00346 };
00347 return e;
00348 }
00349
00350 QByteArray Content::decodedContent()
00351 {
00352 QByteArray ret;
00353 Headers::ContentTransferEncoding *ec=contentTransferEncoding();
00354 bool removeTrailingNewline=false;
00355
00356 if ( d_ptr->body.length() == 0 ) {
00357 return ret;
00358 }
00359
00360 if ( ec->decoded() ) {
00361 ret = d_ptr->body;
00362 removeTrailingNewline = true;
00363 } else {
00364 switch( ec->encoding() ) {
00365 case Headers::CEbase64 :
00366 {
00367 KMime::Codec *codec = KMime::Codec::codecForName( "base64" );
00368 Q_ASSERT( codec );
00369 ret.resize( codec->maxDecodedSizeFor( d_ptr->body.size() ) );
00370 KMime::Decoder* decoder = codec->makeDecoder();
00371 QByteArray::const_iterator inputIt = d_ptr->body.constBegin();
00372 QByteArray::iterator resultIt = ret.begin();
00373 decoder->decode( inputIt, d_ptr->body.constEnd(), resultIt, ret.end() );
00374 ret.truncate( resultIt - ret.begin() );
00375 break;
00376 }
00377 case Headers::CEquPr :
00378 ret = KCodecs::quotedPrintableDecode( d_ptr->body );
00379 removeTrailingNewline = true;
00380 break;
00381 case Headers::CEuuenc :
00382 KCodecs::uudecode( d_ptr->body, ret );
00383 break;
00384 case Headers::CEbinary :
00385 ret = d_ptr->body;
00386 removeTrailingNewline = false;
00387 break;
00388 default :
00389 ret = d_ptr->body;
00390 removeTrailingNewline = true;
00391 }
00392 }
00393
00394 if ( removeTrailingNewline && ( ret.size() > 0 ) && ( ret[ret.size()-1] == '\n') ) {
00395 ret.resize( ret.size() - 1 );
00396 }
00397
00398 return ret;
00399 }
00400
00401 QString Content::decodedText( bool trimText, bool removeTrailingNewlines )
00402 {
00403 if ( !decodeText() ) {
00404 return QString();
00405 }
00406
00407 bool ok = true;
00408 QTextCodec *codec =
00409 KGlobal::charsets()->codecForName( QLatin1String( contentType()->charset() ), ok );
00410
00411 QString s = codec->toUnicode( d_ptr->body.data(), d_ptr->body.length() );
00412
00413 if ( trimText || removeTrailingNewlines ) {
00414 int i;
00415 for ( i = s.length() - 1; i >= 0; --i ) {
00416 if ( trimText ) {
00417 if ( !s[i].isSpace() ) {
00418 break;
00419 }
00420 }
00421 else {
00422 if ( s[i] != QLatin1Char( '\n' ) ) {
00423 break;
00424 }
00425 }
00426 }
00427 s.truncate( i + 1 );
00428 } else {
00429 if ( s.right( 1 ) == QLatin1String( "\n" ) ) {
00430 s.truncate( s.length() - 1 );
00431 }
00432 }
00433
00434 return s;
00435 }
00436
00437 void Content::fromUnicodeString( const QString &s )
00438 {
00439 bool ok = true;
00440 QTextCodec *codec =
00441 KGlobal::charsets()->codecForName( QLatin1String( contentType()->charset() ), ok );
00442
00443 if ( !ok ) {
00444 codec = KGlobal::locale()->codecForEncoding();
00445 QByteArray chset = KGlobal::locale()->encoding();
00446 contentType()->setCharset( chset );
00447 }
00448
00449 d_ptr->body = codec->fromUnicode( s );
00450 contentTransferEncoding()->setDecoded( true );
00451 }
00452
00453 Content *Content::textContent()
00454 {
00455 Content *ret=0;
00456
00457
00458 if ( contentType()->isText() ) {
00459 ret = this;
00460 } else {
00461 foreach ( Content *c, d_ptr->contents() ) {
00462 if ( ( ret = c->textContent() ) != 0 ) {
00463 break;
00464 }
00465 }
00466 }
00467 return ret;
00468 }
00469
00470 Content::List Content::attachments( bool incAlternatives )
00471 {
00472 List attachments;
00473 if ( d_ptr->contents().isEmpty() ) {
00474 attachments.append( this );
00475 } else {
00476 foreach ( Content *c, d_ptr->contents() ) {
00477 if ( !incAlternatives &&
00478 c->contentType()->category() == Headers::CCalternativePart ) {
00479 continue;
00480 } else {
00481 attachments += c->attachments( incAlternatives );
00482 }
00483 }
00484 }
00485
00486 if ( isTopLevel() ) {
00487 Content *text = textContent();
00488 if ( text ) {
00489 attachments.removeAll( text );
00490 }
00491 }
00492 return attachments;
00493 }
00494
00495 Content::List Content::contents() const
00496 {
00497 return d_ptr->contents();
00498 }
00499
00500 void Content::addContent( Content *c, bool prepend )
00501 {
00502 Q_D( Content );
00503
00504
00505 Q_ASSERT( !bodyIsMessage() );
00506
00507
00508 if( d->multipartContents.isEmpty() && !contentType()->isMultipart() ) {
00509
00510 Content *main = new Content( this );
00511
00512
00513
00514
00515 for ( Headers::Base::List::iterator it = h_eaders.begin();
00516 it != h_eaders.end(); ) {
00517 if ( (*it)->isMimeHeader() ) {
00518
00519 main->setHeader( *it );
00520
00521 it = h_eaders.erase( it );
00522 } else {
00523 ++it;
00524 }
00525 }
00526
00527
00528 main->contentType()->setCategory( Headers::CCmixedPart );
00529
00530
00531 main->setBody( d->body );
00532 d->body.clear();
00533
00534
00535 d->multipartContents.append( main );
00536
00537
00538 Headers::ContentType *ct = contentType();
00539 ct->setMimeType( "multipart/mixed" );
00540 ct->setBoundary( multiPartBoundary() );
00541 ct->setCategory( Headers::CCcontainer );
00542 contentTransferEncoding()->clear();
00543 }
00544
00545
00546 if( prepend ) {
00547 d->multipartContents.prepend( c );
00548 } else {
00549 d->multipartContents.append( c );
00550 }
00551
00552 if( c->parent() != this ) {
00553
00554 c->setParent( this );
00555 }
00556 }
00557
00558 void Content::removeContent( Content *c, bool del )
00559 {
00560 Q_D( Content );
00561 Q_ASSERT( d->multipartContents.contains( c ) );
00562
00563
00564
00565 Q_ASSERT( !bodyIsMessage() );
00566
00567 d->multipartContents.removeAll( c );
00568 if ( del ) {
00569 delete c;
00570 } else {
00571 c->d_ptr->parent = 0;
00572 }
00573
00574
00575 if( d->multipartContents.count() == 1 ) {
00576 Content *main = d->multipartContents.first();
00577
00578
00579
00580 foreach( Headers::Base *h, main->h_eaders ) {
00581 setHeader( h );
00582 }
00583 main->h_eaders.clear();
00584
00585
00586 d->body = main->body();
00587
00588
00589 delete main;
00590 d->multipartContents.clear();
00591 }
00592 }
00593
00594 void Content::changeEncoding( Headers::contentEncoding e )
00595 {
00596
00597
00598 Q_ASSERT( !bodyIsMessage() );
00599
00600 Headers::ContentTransferEncoding *enc = contentTransferEncoding();
00601 if( enc->encoding() == e ) {
00602
00603 return;
00604 }
00605
00606 if( decodeText() ) {
00607
00608 Q_ASSERT( enc->decoded() );
00609 enc->setEncoding( e );
00610 } else {
00611
00612 if( e == Headers::CEbase64 ) {
00613 d_ptr->body = KCodecs::base64Encode( decodedContent(), true );
00614 d_ptr->body.append( "\n" );
00615 enc->setEncoding( e );
00616 enc->setDecoded( false );
00617 } else {
00618
00619 Q_ASSERT( false );
00620 }
00621 }
00622 }
00623
00624 void Content::toStream( QTextStream &ts, bool scrambleFromLines )
00625 {
00626 QByteArray ret = encodedContent( false );
00627
00628 if ( scrambleFromLines ) {
00629
00630
00631
00632 ret.replace( "\n\nFrom ", "\n\n>From ");
00633 }
00634 ts << ret;
00635 }
00636
00637 Headers::Generic *Content::getNextHeader( QByteArray &head )
00638 {
00639 return d_ptr->nextHeader( head );
00640 }
00641
00642 Headers::Generic *Content::nextHeader( QByteArray &head )
00643 {
00644 return d_ptr->nextHeader( head );
00645 }
00646
00647 Headers::Generic *ContentPrivate::nextHeader( QByteArray &_head )
00648 {
00649 Headers::Base *header = HeaderParsing::extractFirstHeader( _head );
00650 if ( !header ) {
00651 return 0;
00652 }
00653
00654 Headers::Generic *ret = new Headers::Generic( header->type(), q_ptr );
00655 ret->from7BitString( header->as7BitString() );
00656 return ret;
00657 }
00658
00659 Headers::Base *Content::getHeaderByType( const char *type )
00660 {
00661 return headerByType( type );
00662 }
00663
00664 Headers::Base *Content::headerByType( const char *type )
00665 {
00666 Q_ASSERT( type && *type );
00667
00668 foreach( Headers::Base *h, h_eaders ) {
00669 if( h->is( type ) ) {
00670 return h;
00671 }
00672 }
00673
00674 return 0;
00675 }
00676
00677 Headers::Base::List Content::headersByType( const char *type )
00678 {
00679 Q_ASSERT( type && *type );
00680
00681 Headers::Base::List result;
00682
00683 foreach( Headers::Base *h, h_eaders ) {
00684 if( h->is( type ) ) {
00685 result << h;
00686 }
00687 }
00688
00689 return result;
00690 }
00691
00692 void Content::setHeader( Headers::Base *h )
00693 {
00694 Q_ASSERT( h );
00695 removeHeader( h->type() );
00696 appendHeader( h );
00697 }
00698
00699 void Content::appendHeader( Headers::Base *h )
00700 {
00701 h_eaders.append( h );
00702 h->setParent( this );
00703 }
00704
00705 void Content::prependHeader( Headers::Base *h )
00706 {
00707 h_eaders.prepend( h );
00708 h->setParent( this );
00709 }
00710
00711 bool Content::removeHeader( const char *type )
00712 {
00713 for ( Headers::Base::List::iterator it = h_eaders.begin();
00714 it != h_eaders.end(); ++it )
00715 if ( (*it)->is(type) ) {
00716 delete (*it);
00717 h_eaders.erase( it );
00718 return true;
00719 }
00720
00721 return false;
00722 }
00723
00724 bool Content::hasHeader( const char *type )
00725 {
00726 return headerByType( type ) != 0;
00727 }
00728
00729 int Content::size()
00730 {
00731 int ret = d_ptr->body.length();
00732
00733 if ( contentTransferEncoding()->encoding() == Headers::CEbase64 ) {
00734 return ret * 3 / 4;
00735 }
00736
00737
00738
00739
00740
00741 return ret;
00742 }
00743
00744 int Content::storageSize() const
00745 {
00746 const Q_D(Content);
00747 int s = d->head.size();
00748
00749 if ( d->contents().isEmpty() ) {
00750 s += d->body.size();
00751 } else {
00752
00753
00754
00755 foreach ( Content *c, d->contents() ) {
00756 s += c->storageSize();
00757 }
00758 }
00759
00760 return s;
00761 }
00762
00763 int Content::lineCount() const
00764 {
00765 const Q_D(Content);
00766 int ret = 0;
00767 if ( !isTopLevel() ) {
00768 ret += d->head.count( '\n' );
00769 }
00770 ret += d->body.count( '\n' );
00771
00772 foreach ( Content *c, d->contents() ) {
00773 ret += c->lineCount();
00774 }
00775
00776 return ret;
00777 }
00778
00779 QByteArray Content::rawHeader( const char *name ) const
00780 {
00781 return KMime::extractHeader( d_ptr->head, name );
00782 }
00783
00784 QList<QByteArray> Content::rawHeaders( const char *name ) const
00785 {
00786 return KMime::extractHeaders( d_ptr->head, name );
00787 }
00788
00789 bool Content::decodeText()
00790 {
00791 Q_D(Content);
00792 Headers::ContentTransferEncoding *enc = contentTransferEncoding();
00793
00794 if ( !contentType()->isText() ) {
00795 return false;
00796 }
00797 if ( enc->decoded() ) {
00798 return true;
00799 }
00800
00801 switch( enc->encoding() )
00802 {
00803 case Headers::CEbase64 :
00804 d->body = KCodecs::base64Decode( d->body );
00805 d->body.append( "\n" );
00806 break;
00807 case Headers::CEquPr :
00808 d->body = KCodecs::quotedPrintableDecode( d->body );
00809 break;
00810 case Headers::CEuuenc :
00811 d->body = KCodecs::uudecode( d->body );
00812 d->body.append( "\n" );
00813 break;
00814 case Headers::CEbinary :
00815
00816 d->body.append( "\n" );
00817 default :
00818 break;
00819 }
00820
00821 enc->setDecoded( true );
00822 return true;
00823 }
00824
00825 QByteArray Content::defaultCharset() const
00826 {
00827 return d_ptr->defaultCS;
00828 }
00829
00830 void Content::setDefaultCharset( const QByteArray &cs )
00831 {
00832 d_ptr->defaultCS = KMime::cachedCharset( cs );
00833
00834 foreach ( Content *c, d_ptr->contents() ) {
00835 c->setDefaultCharset( cs );
00836 }
00837
00838
00839
00840 parse();
00841 }
00842
00843 bool Content::forceDefaultCharset() const
00844 {
00845 return d_ptr->forceDefaultCS;
00846 }
00847
00848 void Content::setForceDefaultCharset( bool b )
00849 {
00850 d_ptr->forceDefaultCS = b;
00851
00852 foreach ( Content *c, d_ptr->contents() ) {
00853 c->setForceDefaultCharset( b );
00854 }
00855
00856
00857
00858 parse();
00859 }
00860
00861 Content * KMime::Content::content( const ContentIndex &index ) const
00862 {
00863 if ( !index.isValid() ) {
00864 return const_cast<KMime::Content*>( this );
00865 }
00866 ContentIndex idx = index;
00867 unsigned int i = idx.pop() - 1;
00868 if ( i < (unsigned int)d_ptr->contents().size() ) {
00869 return d_ptr->contents()[i]->content( idx );
00870 } else {
00871 return 0;
00872 }
00873 }
00874
00875 ContentIndex KMime::Content::indexForContent( Content * content ) const
00876 {
00877 int i = d_ptr->contents().indexOf( content );
00878 if ( i >= 0 ) {
00879 ContentIndex ci;
00880 ci.push( i + 1 );
00881 return ci;
00882 }
00883
00884 for ( int i = 0; i < d_ptr->contents().size(); ++i ) {
00885 ContentIndex ci = d_ptr->contents()[i]->indexForContent( content );
00886 if ( ci.isValid() ) {
00887
00888 ci.push( i + 1 );
00889 return ci;
00890 }
00891 }
00892 return ContentIndex();
00893 }
00894
00895 bool Content::isTopLevel() const
00896 {
00897 return d_ptr->parent == 0;
00898 }
00899
00900 void Content::setParent( Content* parent )
00901 {
00902
00903 Content *oldParent = d_ptr->parent;
00904 if ( oldParent && oldParent->contents().contains( this ) ) {
00905 oldParent->removeContent( this );
00906 }
00907
00908 d_ptr->parent = parent;
00909 if ( parent && !parent->contents().contains( this ) ) {
00910 parent->addContent( this );
00911 }
00912 }
00913
00914 Content* Content::parent() const
00915 {
00916 return d_ptr->parent;
00917 }
00918
00919 Content* Content::topLevel() const
00920 {
00921 Content *top = const_cast<Content*>(this);
00922 Content *c = parent();
00923 while ( c ) {
00924 top = c;
00925 c = c->parent();
00926 }
00927
00928 return top;
00929 }
00930
00931 ContentIndex Content::index() const
00932 {
00933 Content* top = topLevel();
00934 if ( top ) {
00935 return top->indexForContent( const_cast<Content*>(this) );
00936 }
00937
00938 return indexForContent( const_cast<Content*>(this) );
00939 }
00940
00941 Message::Ptr Content::bodyAsMessage() const
00942 {
00943 if ( bodyIsMessage() && d_ptr->bodyAsMessage ) {
00944 return d_ptr->bodyAsMessage;
00945 } else {
00946 return Message::Ptr();
00947 }
00948 }
00949
00950 bool Content::bodyIsMessage() const
00951 {
00952
00953
00954 return const_cast<Content*>( this )->header<Headers::ContentType>( false ) &&
00955 const_cast<Content*>( this )->header<Headers::ContentType>( true )
00956 ->mimeType().toLower() == "message/rfc822";
00957 }
00958
00959
00960 #define kmime_mk_header_accessor( type, method ) \
00961 Headers::type *Content::method( bool create ) { \
00962 return header<Headers::type>( create ); \
00963 }
00964
00965 kmime_mk_header_accessor( ContentType, contentType )
00966 kmime_mk_header_accessor( ContentTransferEncoding, contentTransferEncoding )
00967 kmime_mk_header_accessor( ContentDisposition, contentDisposition )
00968 kmime_mk_header_accessor( ContentDescription, contentDescription )
00969 kmime_mk_header_accessor( ContentLocation, contentLocation )
00970 kmime_mk_header_accessor( ContentID, contentID )
00971
00972 #undef kmime_mk_header_accessor
00973
00974
00975
00976 void ContentPrivate::clearBodyMessage()
00977 {
00978 bodyAsMessage.reset();
00979 }
00980
00981 Content::List ContentPrivate::contents() const
00982 {
00983 Q_ASSERT( multipartContents.isEmpty() || !bodyAsMessage );
00984 if ( bodyAsMessage )
00985 return Content::List() << bodyAsMessage.get();
00986 else
00987 return multipartContents;
00988 }
00989
00990 bool ContentPrivate::parseUuencoded()
00991 {
00992 Q_Q( Content );
00993 Parser::UUEncoded uup( body, KMime::extractHeader( head, "Subject" ) );
00994 if( !uup.parse() ) {
00995 return false;
00996 }
00997
00998 Headers::ContentType *ct = q->contentType();
00999 ct->clear();
01000
01001 if( uup.isPartial() ) {
01002
01003 ct->setMimeType( "message/partial" );
01004
01005 ct->setPartialParams( uup.partialCount(), uup.partialNumber() );
01006 q->contentTransferEncoding()->setEncoding( Headers::CE7Bit );
01007 } else {
01008
01009 body.clear();
01010 ct->setMimeType( "multipart/mixed" );
01011 ct->setBoundary( multiPartBoundary() );
01012 ct->setCategory( Headers::CCcontainer );
01013 q->contentTransferEncoding()->clear();
01014
01015
01016 Q_ASSERT( multipartContents.count() == 0 );
01017 {
01018 Content *c = new Content( q );
01019 c->contentType()->setMimeType( "text/plain" );
01020 c->contentTransferEncoding()->setEncoding( Headers::CE7Bit );
01021 c->setBody( uup.textPart() );
01022 multipartContents.append( c );
01023 }
01024
01025
01026 for( int i = 0; i < uup.binaryParts().count(); ++i ) {
01027 Content *c = new Content( q );
01028 c->contentType()->setMimeType( uup.mimeTypes().at( i ) );
01029 c->contentType()->setName( QLatin1String( uup.filenames().at( i ) ), QByteArray( ) );
01030 c->contentTransferEncoding()->setEncoding( Headers::CEuuenc );
01031 c->contentTransferEncoding()->setDecoded( false );
01032 c->contentDisposition()->setDisposition( Headers::CDattachment );
01033 c->contentDisposition()->setFilename( QLatin1String( uup.filenames().at( i ) ) );
01034 c->setBody( uup.binaryParts().at( i ) );
01035 c->changeEncoding( Headers::CEbase64 );
01036 multipartContents.append( c );
01037 }
01038 }
01039
01040 return true;
01041 }
01042
01043 bool ContentPrivate::parseYenc()
01044 {
01045 Q_Q( Content );
01046 Parser::YENCEncoded yenc( body );
01047 if( !yenc.parse() ) {
01048 return false;
01049 }
01050
01051 Headers::ContentType *ct = q->contentType();
01052 ct->clear();
01053
01054 if( yenc.isPartial() ) {
01055
01056 ct->setMimeType( "message/partial" );
01057
01058 ct->setPartialParams( yenc.partialCount(), yenc.partialNumber() );
01059 q->contentTransferEncoding()->setEncoding( Headers::CEbinary );
01060 q->changeEncoding( Headers::CEbase64 );
01061 } else {
01062
01063 body.clear();
01064 ct->setMimeType( "multipart/mixed" );
01065 ct->setBoundary( multiPartBoundary() );
01066 ct->setCategory( Headers::CCcontainer );
01067 q->contentTransferEncoding()->clear();
01068
01069
01070 Q_ASSERT( multipartContents.count() == 0 );
01071 {
01072 Content *c = new Content( q );
01073 c->contentType()->setMimeType( "text/plain" );
01074 c->contentTransferEncoding()->setEncoding( Headers::CE7Bit );
01075 c->setBody( yenc.textPart() );
01076 multipartContents.append( c );
01077 }
01078
01079
01080 for ( int i=0; i<yenc.binaryParts().count(); i++ ) {
01081 Content *c = new Content( q );
01082 c->contentType()->setMimeType( yenc.mimeTypes().at( i ) );
01083 c->contentType()->setName( QLatin1String( yenc.filenames().at( i ) ), QByteArray( ) );
01084 c->contentTransferEncoding()->setEncoding( Headers::CEbinary );
01085 c->contentDisposition()->setDisposition( Headers::CDattachment );
01086 c->contentDisposition()->setFilename( QLatin1String( yenc.filenames().at( i ) ) );
01087 c->setBody( yenc.binaryParts().at( i ) );
01088 c->changeEncoding( Headers::CEbase64 );
01089 multipartContents.append( c );
01090 }
01091 }
01092
01093 return true;
01094 }
01095
01096 bool ContentPrivate::parseMultipart()
01097 {
01098 Q_Q( Content );
01099 const Headers::ContentType *ct = q->contentType();
01100 const QByteArray boundary = ct->boundary();
01101 if( boundary.isEmpty() ) {
01102 return false;
01103 }
01104 Parser::MultiPart mpp( body, boundary );
01105 if( !mpp.parse() ) {
01106 return false;
01107 }
01108
01109 preamble = mpp.preamble();
01110 epilogue = mpp.epilouge();
01111
01112
01113 Headers::contentCategory cat;
01114 if( ct->isSubtype( "alternative" ) ) {
01115 cat = Headers::CCalternativePart;
01116 } else {
01117 cat = Headers::CCmixedPart;
01118 }
01119
01120
01121 Q_ASSERT( multipartContents.isEmpty() );
01122 body.clear();
01123 QList<QByteArray> parts = mpp.parts();
01124 foreach( const QByteArray &part, mpp.parts() ) {
01125 Content *c = new Content( q );
01126 c->setContent( part );
01127 c->setFrozen( frozen );
01128 c->parse();
01129 c->contentType()->setCategory( cat );
01130 multipartContents.append( c );
01131 }
01132
01133 return true;
01134 }
01135
01136 }