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