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