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