00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00040 #include "kmime_headers.h"
00041 #include "kmime_headers_p.h"
00042
00043 #include "kmime_util.h"
00044 #include "kmime_util_p.h"
00045 #include "kmime_content.h"
00046 #include "kmime_codecs.h"
00047 #include "kmime_header_parsing.h"
00048 #include "kmime_headerfactory_p.h"
00049 #include "kmime_warning.h"
00050
00051 #include <QtCore/QTextCodec>
00052 #include <QtCore/QString>
00053 #include <QtCore/QStringList>
00054
00055 #include <kglobal.h>
00056 #include <kcharsets.h>
00057
00058 #include <assert.h>
00059 #include <ctype.h>
00060
00061 template <typename T>
00062 bool registerHeaderHelper()
00063 {
00064 const T dummy;
00065 if( QByteArray( dummy.type() ).isEmpty() ) {
00066
00067 return false;
00068 }
00069 return KMime::HeaderFactory::self()->registerHeader<T>();
00070 }
00071
00072
00073 #define kmime_register_header( subclass ) \
00074 namespace { const bool dummyForRegistering##subclass = registerHeaderHelper<subclass>(); }
00075
00076
00077 #define kmime_mk_trivial_ctor( subclass, baseclass ) \
00078 subclass::subclass( Content *parent ) : baseclass( parent ) \
00079 { \
00080 clear(); \
00081 } \
00082 \
00083 subclass::subclass( Content *parent, const QByteArray &s ) : baseclass( parent ) \
00084 { \
00085 from7BitString( s ); \
00086 } \
00087 \
00088 subclass::subclass( Content *parent, const QString &s, const QByteArray &charset ) : \
00089 baseclass( parent ) \
00090 { \
00091 fromUnicodeString( s, charset ); \
00092 } \
00093 \
00094 subclass::~subclass() {} \
00095 \
00096 kmime_register_header( subclass )
00097
00098
00099
00100 #define kmime_mk_trivial_ctor_with_dptr( subclass, baseclass ) \
00101 subclass::subclass( Content *parent ) : baseclass( new subclass##Private, parent ) \
00102 { \
00103 clear(); \
00104 } \
00105 \
00106 subclass::subclass( Content *parent, const QByteArray &s ) : baseclass( new subclass##Private, parent ) \
00107 { \
00108 from7BitString( s ); \
00109 } \
00110 \
00111 subclass::subclass( Content *parent, const QString &s, const QByteArray &charset ) : \
00112 baseclass( new subclass##Private, parent ) \
00113 { \
00114 fromUnicodeString( s, charset ); \
00115 } \
00116 \
00117 subclass::~subclass() {} \
00118 \
00119 kmime_register_header( subclass )
00120
00121
00122
00123 #define kmime_mk_trivial_ctor_with_name( subclass, baseclass, name ) \
00124 kmime_mk_trivial_ctor( subclass, baseclass ) \
00125 \
00126 const char *subclass::type() const \
00127 { \
00128 return staticType(); \
00129 } \
00130 const char *subclass::staticType() { return #name; }
00131
00132 #define kmime_mk_trivial_ctor_with_name_and_dptr( subclass, baseclass, name ) \
00133 kmime_mk_trivial_ctor_with_dptr( subclass, baseclass ) \
00134 const char *subclass::type() const { return staticType(); } \
00135 const char *subclass::staticType() { return #name; }
00136
00137 #define kmime_mk_dptr_ctor( subclass, baseclass ) \
00138 subclass::subclass( subclass##Private *d, KMime::Content *parent ) : baseclass( d, parent ) {}
00139
00140 using namespace KMime;
00141 using namespace KMime::Headers;
00142 using namespace KMime::Types;
00143 using namespace KMime::HeaderParsing;
00144
00145 namespace KMime {
00146 namespace Headers {
00147
00148 Base::Base( KMime::Content *parent ) :
00149 d_ptr( new BasePrivate )
00150 {
00151 Q_D(Base);
00152 d->parent = parent;
00153 }
00154
00155 Base::Base( BasePrivate *dd, KMime::Content *parent ) :
00156 d_ptr( dd )
00157 {
00158 Q_D(Base);
00159 d->parent = parent;
00160 }
00161
00162 Base::~Base()
00163 {
00164 delete d_ptr;
00165 d_ptr = 0;
00166 }
00167
00168 KMime::Content *Base::parent() const
00169 {
00170 return d_ptr->parent;
00171 }
00172
00173 void Base::setParent( KMime::Content *parent )
00174 {
00175 d_ptr->parent = parent;
00176 }
00177
00178 QByteArray Base::rfc2047Charset() const
00179 {
00180 if ( d_ptr->encCS.isEmpty() || forceDefaultCharset() ) {
00181 return defaultCharset();
00182 } else {
00183 return d_ptr->encCS;
00184 }
00185 }
00186
00187 void Base::setRFC2047Charset( const QByteArray &cs )
00188 {
00189 d_ptr->encCS = cachedCharset( cs );
00190 }
00191
00192 bool Base::forceDefaultCharset() const
00193 {
00194 return ( parent() != 0 ? parent()->forceDefaultCharset() : false );
00195 }
00196
00197 QByteArray Base::defaultCharset() const
00198 {
00199 return ( parent() != 0 ? parent()->defaultCharset() : Latin1 );
00200 }
00201
00202 const char *Base::type() const
00203 {
00204 return "";
00205 }
00206
00207 bool Base::is( const char *t ) const
00208 {
00209 return strcasecmp( t, type() ) == 0;
00210 }
00211
00212 bool Base::isMimeHeader() const
00213 {
00214 return strncasecmp( type(), "Content-", 8 ) == 0;
00215 }
00216
00217 bool Base::isXHeader() const
00218 {
00219 return strncmp( type(), "X-", 2 ) == 0;
00220 }
00221
00222 QByteArray Base::typeIntro() const
00223 {
00224 return QByteArray( type() ) + ": ";
00225 }
00226
00227
00228
00229 namespace Generics {
00230
00231
00232
00233
00234 kmime_mk_dptr_ctor( Unstructured, Base )
00235
00236
00237 Unstructured::Unstructured( Content *p ) : Base( new UnstructuredPrivate, p )
00238 {
00239 }
00240
00241 Unstructured::Unstructured( Content *p, const QByteArray &s ) : Base( new UnstructuredPrivate, p )
00242 {
00243 from7BitString( s );
00244 }
00245
00246 Unstructured::Unstructured( Content *p, const QString &s, const QByteArray &cs ) : Base( new UnstructuredPrivate, p )
00247 {
00248 fromUnicodeString( s, cs );
00249 }
00250
00251 Unstructured::~Unstructured()
00252 {
00253 }
00254
00255 void Unstructured::from7BitString( const QByteArray &s )
00256 {
00257 Q_D(Unstructured);
00258 d->decoded = decodeRFC2047String( s, d->encCS, defaultCharset(), forceDefaultCharset() );
00259 }
00260
00261 QByteArray Unstructured::as7BitString( bool withHeaderType ) const
00262 {
00263 const Q_D(Unstructured);
00264 QByteArray result;
00265 if ( withHeaderType ) {
00266 result = typeIntro();
00267 }
00268 result += encodeRFC2047String( d->decoded, d->encCS ) ;
00269
00270 return result;
00271 }
00272
00273 void Unstructured::fromUnicodeString( const QString &s, const QByteArray &b )
00274 {
00275 Q_D(Unstructured);
00276 d->decoded = s;
00277 d->encCS = cachedCharset( b );
00278 }
00279
00280 QString Unstructured::asUnicodeString() const
00281 {
00282 return d_func()->decoded;
00283 }
00284
00285 void Unstructured::clear()
00286 {
00287 Q_D(Unstructured);
00288 d->decoded.truncate( 0 );
00289 }
00290
00291 bool Unstructured::isEmpty() const
00292 {
00293 return d_func()->decoded.isEmpty();
00294 }
00295
00296
00297
00298
00299
00300 Structured::Structured( Content *p ) : Base( new StructuredPrivate, p )
00301 {
00302 }
00303
00304 Structured::Structured( Content *p, const QByteArray &s ) : Base( new StructuredPrivate, p )
00305 {
00306 from7BitString( s );
00307 }
00308
00309 Structured::Structured( Content *p, const QString &s, const QByteArray &cs ) : Base( new StructuredPrivate, p )
00310 {
00311 fromUnicodeString( s, cs );
00312 }
00313
00314 kmime_mk_dptr_ctor( Structured, Base )
00315
00316 Structured::~Structured()
00317 {
00318 }
00319
00320 void Structured::from7BitString( const QByteArray &s )
00321 {
00322 Q_D(Structured);
00323 if ( d->encCS.isEmpty() ) {
00324 d->encCS = defaultCharset();
00325 }
00326 const char *cursor = s.constData();
00327 parse( cursor, cursor + s.length() );
00328 }
00329
00330 QString Structured::asUnicodeString() const
00331 {
00332 return QString::fromLatin1( as7BitString( false ) );
00333 }
00334
00335 void Structured::fromUnicodeString( const QString &s, const QByteArray &b )
00336 {
00337 Q_D(Structured);
00338 d->encCS = cachedCharset( b );
00339 from7BitString( s.toLatin1() );
00340 }
00341
00342
00343
00344
00345
00346 Address::Address( Content *p ) : Structured( new AddressPrivate, p )
00347 {
00348 }
00349
00350 Address::Address( Content *p, const QByteArray &s ) : Structured( new AddressPrivate, p )
00351 {
00352 from7BitString( s );
00353 }
00354
00355 Address::Address( Content *p, const QString &s, const QByteArray &cs ) : Structured( new AddressPrivate, p )
00356 {
00357 fromUnicodeString( s, cs );
00358 }
00359
00360 kmime_mk_dptr_ctor( Address, Structured )
00361
00362 Address:: ~Address()
00363 {
00364 }
00365
00366
00367 static bool stringToMailbox( const QByteArray &address,
00368 const QString &displayName, Types::Mailbox &mbox )
00369 {
00370 Types::AddrSpec addrSpec;
00371 mbox.setName( displayName );
00372 const char *cursor = address.constData();
00373 if ( !parseAngleAddr( cursor, cursor + address.length(), addrSpec ) ) {
00374 if ( !parseAddrSpec( cursor, cursor + address.length(), addrSpec ) ) {
00375 kWarning() << "Invalid address";
00376 return false;
00377 }
00378 }
00379 mbox.setAddress( addrSpec );
00380 return true;
00381 }
00382
00383
00384
00385
00386
00387 kmime_mk_trivial_ctor_with_dptr( MailboxList, Address )
00388 kmime_mk_dptr_ctor( MailboxList, Address )
00389
00390 QByteArray MailboxList::as7BitString( bool withHeaderType ) const
00391 {
00392 const Q_D(MailboxList);
00393 if ( isEmpty() ) {
00394 return QByteArray();
00395 }
00396
00397 QByteArray rv;
00398 if ( withHeaderType ) {
00399 rv = typeIntro();
00400 }
00401 foreach ( const Types::Mailbox &mbox, d->mailboxList ) {
00402 rv += mbox.as7BitString( d->encCS );
00403 rv += ", ";
00404 }
00405 rv.resize( rv.length() - 2 );
00406 return rv;
00407 }
00408
00409 void MailboxList::fromUnicodeString( const QString &s, const QByteArray &b )
00410 {
00411 Q_D(MailboxList);
00412 d->encCS = cachedCharset( b );
00413 from7BitString( encodeRFC2047Sentence( s, b ) );
00414 }
00415
00416 QString MailboxList::asUnicodeString() const
00417 {
00418 return prettyAddresses().join( QLatin1String( ", " ) );
00419 }
00420
00421 void MailboxList::clear()
00422 {
00423 Q_D(MailboxList);
00424 d->mailboxList.clear();
00425 }
00426
00427 bool MailboxList::isEmpty() const
00428 {
00429 return d_func()->mailboxList.isEmpty();
00430 }
00431
00432 void MailboxList::addAddress( const Types::Mailbox &mbox )
00433 {
00434 Q_D(MailboxList);
00435 d->mailboxList.append( mbox );
00436 }
00437
00438 void MailboxList::addAddress( const QByteArray &address,
00439 const QString &displayName )
00440 {
00441 Q_D(MailboxList);
00442 Types::Mailbox mbox;
00443 if ( stringToMailbox( address, displayName, mbox ) ) {
00444 d->mailboxList.append( mbox );
00445 }
00446 }
00447
00448 QList< QByteArray > MailboxList::addresses() const
00449 {
00450 QList<QByteArray> rv;
00451 foreach ( const Types::Mailbox &mbox, d_func()->mailboxList ) {
00452 rv.append( mbox.address() );
00453 }
00454 return rv;
00455 }
00456
00457 QStringList MailboxList::displayNames() const
00458 {
00459 QStringList rv;
00460 foreach ( const Types::Mailbox &mbox, d_func()->mailboxList ) {
00461 rv.append( mbox.name() );
00462 }
00463 return rv;
00464 }
00465
00466 QStringList MailboxList::prettyAddresses() const
00467 {
00468 QStringList rv;
00469 foreach ( const Types::Mailbox &mbox, d_func()->mailboxList ) {
00470 rv.append( mbox.prettyAddress() );
00471 }
00472 return rv;
00473 }
00474
00475 Types::Mailbox::List MailboxList::mailboxes() const
00476 {
00477 return d_func()->mailboxList;
00478 }
00479
00480 bool MailboxList::parse( const char* &scursor, const char *const send,
00481 bool isCRLF )
00482 {
00483 Q_D(MailboxList);
00484
00485
00486
00487
00488
00489 QList<Types::Address> maybeAddressList;
00490 if ( !parseAddressList( scursor, send, maybeAddressList, isCRLF ) ) {
00491 return false;
00492 }
00493
00494 d->mailboxList.clear();
00495
00496
00497 QList<Types::Address>::Iterator it;
00498 for ( it = maybeAddressList.begin(); it != maybeAddressList.end() ; ++it ) {
00499 if ( !(*it).displayName.isEmpty() ) {
00500 KMIME_WARN << "mailbox groups in header disallowing them! Name: \""
00501 << (*it).displayName << "\"" << endl;
00502 }
00503 d->mailboxList += (*it).mailboxList;
00504 }
00505 return true;
00506 }
00507
00508
00509
00510
00511
00512
00513 kmime_mk_trivial_ctor_with_dptr( SingleMailbox, MailboxList )
00514
00515
00516 bool SingleMailbox::parse( const char* &scursor, const char *const send,
00517 bool isCRLF )
00518 {
00519 Q_D(MailboxList);
00520 if ( !MailboxList::parse( scursor, send, isCRLF ) ) {
00521 return false;
00522 }
00523
00524 if ( d->mailboxList.count() > 1 ) {
00525 KMIME_WARN << "multiple mailboxes in header allowing only a single one!"
00526 << endl;
00527 }
00528 return true;
00529 }
00530
00531
00532
00533
00534
00535
00536 kmime_mk_trivial_ctor_with_dptr( AddressList, Address )
00537 kmime_mk_dptr_ctor( AddressList, Address )
00538
00539
00540 QByteArray AddressList::as7BitString( bool withHeaderType ) const
00541 {
00542 const Q_D(AddressList);
00543 if ( d->addressList.isEmpty() ) {
00544 return QByteArray();
00545 }
00546
00547 QByteArray rv;
00548 if ( withHeaderType ) {
00549 rv = typeIntro();
00550 }
00551 foreach ( const Types::Address &addr, d->addressList ) {
00552 foreach ( const Types::Mailbox &mbox, addr.mailboxList ) {
00553 rv += mbox.as7BitString( d->encCS );
00554 rv += ", ";
00555 }
00556 }
00557 rv.resize( rv.length() - 2 );
00558 return rv;
00559 }
00560
00561 void AddressList::fromUnicodeString( const QString &s, const QByteArray &b )
00562 {
00563 Q_D(AddressList);
00564 d->encCS = cachedCharset( b );
00565 from7BitString( encodeRFC2047Sentence( s, b ) );
00566 }
00567
00568 QString AddressList::asUnicodeString() const
00569 {
00570 return prettyAddresses().join( QLatin1String( ", " ) );
00571 }
00572
00573 void AddressList::clear()
00574 {
00575 Q_D(AddressList);
00576 d->addressList.clear();
00577 }
00578
00579 bool AddressList::isEmpty() const
00580 {
00581 return d_func()->addressList.isEmpty();
00582 }
00583
00584 void AddressList::addAddress( const Types::Mailbox &mbox )
00585 {
00586 Q_D(AddressList);
00587 Types::Address addr;
00588 addr.mailboxList.append( mbox );
00589 d->addressList.append( addr );
00590 }
00591
00592 void AddressList::addAddress( const QByteArray &address,
00593 const QString &displayName )
00594 {
00595 Q_D(AddressList);
00596 Types::Address addr;
00597 Types::Mailbox mbox;
00598 if ( stringToMailbox( address, displayName, mbox ) ) {
00599 addr.mailboxList.append( mbox );
00600 d->addressList.append( addr );
00601 }
00602 }
00603
00604 QList< QByteArray > AddressList::addresses() const
00605 {
00606 QList<QByteArray> rv;
00607 foreach ( const Types::Address &addr, d_func()->addressList ) {
00608 foreach ( const Types::Mailbox &mbox, addr.mailboxList ) {
00609 rv.append( mbox.address() );
00610 }
00611 }
00612 return rv;
00613 }
00614
00615 QStringList AddressList::displayNames() const
00616 {
00617 QStringList rv;
00618 foreach ( const Types::Address &addr, d_func()->addressList ) {
00619 foreach ( const Types::Mailbox &mbox, addr.mailboxList ) {
00620 rv.append( mbox.name() );
00621 }
00622 }
00623 return rv;
00624 }
00625
00626 QStringList AddressList::prettyAddresses() const
00627 {
00628 QStringList rv;
00629 foreach ( const Types::Address &addr, d_func()->addressList ) {
00630 foreach ( const Types::Mailbox &mbox, addr.mailboxList ) {
00631 rv.append( mbox.prettyAddress() );
00632 }
00633 }
00634 return rv;
00635 }
00636
00637 Types::Mailbox::List AddressList::mailboxes() const
00638 {
00639 Types::Mailbox::List rv;
00640 foreach ( const Types::Address &addr, d_func()->addressList ) {
00641 foreach ( const Types::Mailbox &mbox, addr.mailboxList ) {
00642 rv.append( mbox );
00643 }
00644 }
00645 return rv;
00646 }
00647
00648 bool AddressList::parse( const char* &scursor, const char *const send,
00649 bool isCRLF )
00650 {
00651 Q_D(AddressList);
00652 QList<Types::Address> maybeAddressList;
00653 if ( !parseAddressList( scursor, send, maybeAddressList, isCRLF ) ) {
00654 return false;
00655 }
00656
00657 d->addressList = maybeAddressList;
00658 return true;
00659 }
00660
00661
00662
00663
00664
00665
00666 kmime_mk_trivial_ctor_with_dptr( Token, Structured )
00667 kmime_mk_dptr_ctor( Token, Structured )
00668
00669
00670 QByteArray Token::as7BitString( bool withHeaderType ) const
00671 {
00672 if ( isEmpty() ) {
00673 return QByteArray();
00674 }
00675 if ( withHeaderType ) {
00676 return typeIntro() + d_func()->token;
00677 }
00678 return d_func()->token;
00679 }
00680
00681 void Token::clear()
00682 {
00683 Q_D(Token);
00684 d->token.clear();
00685 }
00686
00687 bool Token::isEmpty() const
00688 {
00689 return d_func()->token.isEmpty();
00690 }
00691
00692 QByteArray Token::token() const
00693 {
00694 return d_func()->token;
00695 }
00696
00697 void Token::setToken( const QByteArray &t )
00698 {
00699 Q_D(Token);
00700 d->token = t;
00701 }
00702
00703 bool Token::parse( const char* &scursor, const char *const send, bool isCRLF )
00704 {
00705 Q_D(Token);
00706 clear();
00707 eatCFWS( scursor, send, isCRLF );
00708
00709 if ( scursor == send ) {
00710 return false;
00711 }
00712
00713 QPair<const char*,int> maybeToken;
00714 if ( !parseToken( scursor, send, maybeToken, false ) ) {
00715 return false;
00716 }
00717 d->token = QByteArray( maybeToken.first, maybeToken.second );
00718
00719
00720 eatCFWS( scursor, send, isCRLF );
00721 if ( scursor != send ) {
00722 KMIME_WARN << "trailing garbage after token in header allowing "
00723 "only a single token!" << endl;
00724 }
00725 return true;
00726 }
00727
00728
00729
00730
00731
00732
00733 kmime_mk_trivial_ctor_with_dptr( PhraseList, Structured )
00734
00735
00736 QByteArray PhraseList::as7BitString( bool withHeaderType ) const
00737 {
00738 const Q_D(PhraseList);
00739 if ( isEmpty() ) {
00740 return QByteArray();
00741 }
00742
00743 QByteArray rv;
00744 if ( withHeaderType ) {
00745 rv = typeIntro();
00746 }
00747
00748 for ( int i = 0; i < d->phraseList.count(); ++i ) {
00749
00750 rv += encodeRFC2047String( d->phraseList[i], d->encCS, false, false );
00751 if ( i != d->phraseList.count() - 1 ) {
00752 rv += ", ";
00753 }
00754 }
00755
00756 return rv;
00757 }
00758
00759 QString PhraseList::asUnicodeString() const
00760 {
00761 return d_func()->phraseList.join( QLatin1String( ", " ) );
00762 }
00763
00764 void PhraseList::clear()
00765 {
00766 Q_D(PhraseList);
00767 d->phraseList.clear();
00768 }
00769
00770 bool PhraseList::isEmpty() const
00771 {
00772 return d_func()->phraseList.isEmpty();
00773 }
00774
00775 QStringList PhraseList::phrases() const
00776 {
00777 return d_func()->phraseList;
00778 }
00779
00780 bool PhraseList::parse( const char* &scursor, const char *const send,
00781 bool isCRLF )
00782 {
00783 Q_D(PhraseList);
00784 d->phraseList.clear();
00785
00786 while ( scursor != send ) {
00787 eatCFWS( scursor, send, isCRLF );
00788
00789 if ( scursor == send ) {
00790 return true;
00791 }
00792
00793 if ( *scursor == ',' ) {
00794 scursor++;
00795 continue;
00796 }
00797
00798 QString maybePhrase;
00799 if ( !parsePhrase( scursor, send, maybePhrase, isCRLF ) ) {
00800 return false;
00801 }
00802 d->phraseList.append( maybePhrase );
00803
00804 eatCFWS( scursor, send, isCRLF );
00805
00806 if ( scursor == send ) {
00807 return true;
00808 }
00809
00810 if ( *scursor == ',' ) {
00811 scursor++;
00812 }
00813 }
00814 return true;
00815 }
00816
00817
00818
00819
00820
00821
00822 kmime_mk_trivial_ctor_with_dptr( DotAtom, Structured )
00823
00824
00825 QByteArray DotAtom::as7BitString( bool withHeaderType ) const
00826 {
00827 if ( isEmpty() ) {
00828 return QByteArray();
00829 }
00830
00831 QByteArray rv;
00832 if ( withHeaderType ) {
00833 rv += typeIntro();
00834 }
00835
00836 rv += d_func()->dotAtom.toLatin1();
00837 return rv;
00838 }
00839
00840 QString DotAtom::asUnicodeString() const
00841 {
00842 return d_func()->dotAtom;
00843 }
00844
00845 void DotAtom::clear()
00846 {
00847 Q_D(DotAtom);
00848 d->dotAtom.clear();
00849 }
00850
00851 bool DotAtom::isEmpty() const
00852 {
00853 return d_func()->dotAtom.isEmpty();
00854 }
00855
00856 bool DotAtom::parse( const char* &scursor, const char *const send,
00857 bool isCRLF )
00858 {
00859 Q_D(DotAtom);
00860 QString maybeDotAtom;
00861 if ( !parseDotAtom( scursor, send, maybeDotAtom, isCRLF ) ) {
00862 return false;
00863 }
00864
00865 d->dotAtom = maybeDotAtom;
00866
00867 eatCFWS( scursor, send, isCRLF );
00868 if ( scursor != send ) {
00869 KMIME_WARN << "trailing garbage after dot-atom in header allowing "
00870 "only a single dot-atom!" << endl;
00871 }
00872 return true;
00873 }
00874
00875
00876
00877
00878
00879
00880 kmime_mk_trivial_ctor_with_dptr( Parametrized, Structured )
00881 kmime_mk_dptr_ctor( Parametrized, Structured )
00882
00883
00884 QByteArray Parametrized::as7BitString( bool withHeaderType ) const
00885 {
00886 const Q_D(Parametrized);
00887 if ( isEmpty() ) {
00888 return QByteArray();
00889 }
00890
00891 QByteArray rv;
00892 if ( withHeaderType ) {
00893 rv += typeIntro();
00894 }
00895
00896 bool first = true;
00897 for ( QMap<QString,QString>::ConstIterator it = d->parameterHash.constBegin();
00898 it != d->parameterHash.constEnd(); ++it )
00899 {
00900 if ( !first ) {
00901 rv += "; ";
00902 } else {
00903 first = false;
00904 }
00905 if ( isUsAscii( it.value() ) ) {
00906 rv += it.key().toLatin1() + '=';
00907 QByteArray tmp = it.value().toLatin1();
00908 addQuotes( tmp, true );
00909 rv += tmp;
00910 } else {
00911 if( useOutlookAttachmentEncoding() ) {
00912 rv += it.key().toLatin1() + '=';
00913 kDebug() << "doing:" << it.value() << QLatin1String( d->encCS );
00914 rv += "\"" + encodeRFC2047String( it.value(), d->encCS ) + "\"";
00915 } else {
00916 rv += it.key().toLatin1() + "*=";
00917 rv += encodeRFC2231String( it.value(), d->encCS );
00918 }
00919 }
00920 }
00921
00922 return rv;
00923 }
00924
00925 QString Parametrized::parameter( const QString &key ) const
00926 {
00927 return d_func()->parameterHash.value( key.toLower() );
00928 }
00929
00930 bool Parametrized::hasParameter( const QString &key ) const
00931 {
00932 return d_func()->parameterHash.contains( key.toLower() );
00933 }
00934
00935 void Parametrized::setParameter( const QString &key, const QString &value )
00936 {
00937 Q_D(Parametrized);
00938 d->parameterHash.insert( key.toLower(), value );
00939 }
00940
00941 bool Parametrized::isEmpty() const
00942 {
00943 return d_func()->parameterHash.isEmpty();
00944 }
00945
00946 void Parametrized::clear()
00947 {
00948 Q_D(Parametrized);
00949 d->parameterHash.clear();
00950 }
00951
00952 bool Parametrized::parse( const char *& scursor, const char * const send,
00953 bool isCRLF )
00954 {
00955 Q_D(Parametrized);
00956 d->parameterHash.clear();
00957 QByteArray charset;
00958 if ( !parseParameterListWithCharset( scursor, send, d->parameterHash, charset, isCRLF ) ) {
00959 return false;
00960 }
00961 d->encCS = charset;
00962 return true;
00963 }
00964
00965
00966
00967
00968
00969
00970 kmime_mk_trivial_ctor_with_dptr( Ident, Address )
00971 kmime_mk_dptr_ctor( Ident, Address )
00972
00973
00974 QByteArray Ident::as7BitString( bool withHeaderType ) const
00975 {
00976 const Q_D(Ident);
00977 if ( d->msgIdList.isEmpty() ) {
00978 return QByteArray();
00979 }
00980
00981 QByteArray rv;
00982 if ( withHeaderType ) {
00983 rv = typeIntro();
00984 }
00985 foreach ( const Types::AddrSpec &addr, d->msgIdList ) {
00986 rv += '<';
00987 rv += addr.asString().toLatin1();
00988 rv += "> ";
00989 }
00990 rv.resize( rv.length() - 1 );
00991 return rv;
00992 }
00993
00994 void Ident::clear()
00995 {
00996 Q_D(Ident);
00997 d->msgIdList.clear();
00998 d->cachedIdentifier.clear();
00999 }
01000
01001 bool Ident::isEmpty() const
01002 {
01003 return d_func()->msgIdList.isEmpty();
01004 }
01005
01006 bool Ident::parse( const char* &scursor, const char * const send, bool isCRLF )
01007 {
01008 Q_D(Ident);
01009
01010
01011
01012
01013
01014
01015
01016 d->msgIdList.clear();
01017 d->cachedIdentifier.clear();
01018
01019 while ( scursor != send ) {
01020 eatCFWS( scursor, send, isCRLF );
01021
01022 if ( scursor == send ) {
01023 return true;
01024 }
01025
01026 if ( *scursor == ',' ) {
01027 scursor++;
01028 continue;
01029 }
01030
01031 AddrSpec maybeMsgId;
01032 if ( !parseAngleAddr( scursor, send, maybeMsgId, isCRLF ) ) {
01033 return false;
01034 }
01035 d->msgIdList.append( maybeMsgId );
01036
01037 eatCFWS( scursor, send, isCRLF );
01038
01039 if ( scursor == send ) {
01040 return true;
01041 }
01042
01043 if ( *scursor == ',' ) {
01044 scursor++;
01045 }
01046 }
01047 return true;
01048 }
01049
01050 QList<QByteArray> Ident::identifiers() const
01051 {
01052 QList<QByteArray> rv;
01053 foreach ( const Types::AddrSpec &addr, d_func()->msgIdList ) {
01054 rv.append( addr.asString().toLatin1() );
01055 }
01056 return rv;
01057 }
01058
01059 void Ident::appendIdentifier( const QByteArray &id )
01060 {
01061 Q_D(Ident);
01062 QByteArray tmp = id;
01063 if ( !tmp.startsWith( '<' ) ) {
01064 tmp.prepend( '<' );
01065 }
01066 if ( !tmp.endsWith( '>' ) ) {
01067 tmp.append( '>' );
01068 }
01069 AddrSpec msgId;
01070 const char *cursor = tmp.constData();
01071 if ( parseAngleAddr( cursor, cursor + tmp.length(), msgId ) ) {
01072 d->msgIdList.append( msgId );
01073 } else {
01074 kWarning() << "Unable to parse address spec!";
01075 }
01076 }
01077
01078
01079
01080
01081
01082
01083 kmime_mk_trivial_ctor_with_dptr( SingleIdent, Ident )
01084 kmime_mk_dptr_ctor( SingleIdent, Ident )
01085
01086
01087 QByteArray SingleIdent::identifier() const
01088 {
01089 if ( d_func()->msgIdList.isEmpty() ) {
01090 return QByteArray();
01091 }
01092
01093 if ( d_func()->cachedIdentifier.isEmpty() ) {
01094 const Types::AddrSpec &addr = d_func()->msgIdList.first();
01095 d_func()->cachedIdentifier = addr.asString().toLatin1();
01096 }
01097
01098 return d_func()->cachedIdentifier;
01099 }
01100
01101 void SingleIdent::setIdentifier( const QByteArray &id )
01102 {
01103 Q_D(SingleIdent);
01104 d->msgIdList.clear();
01105 d->cachedIdentifier.clear();
01106 appendIdentifier( id );
01107 }
01108
01109 bool SingleIdent::parse( const char* &scursor, const char * const send,
01110 bool isCRLF )
01111 {
01112 Q_D(SingleIdent);
01113 if ( !Ident::parse( scursor, send, isCRLF ) ) {
01114 return false;
01115 }
01116
01117 if ( d->msgIdList.count() > 1 ) {
01118 KMIME_WARN << "more than one msg-id in header "
01119 << "allowing only a single one!" << endl;
01120 }
01121 return true;
01122 }
01123
01124
01125
01126 }
01127
01128
01129
01130
01131 kmime_mk_trivial_ctor_with_name_and_dptr( ReturnPath, Generics::Address, Return-Path )
01132
01133
01134 QByteArray ReturnPath::as7BitString( bool withHeaderType ) const
01135 {
01136 if ( isEmpty() ) {
01137 return QByteArray();
01138 }
01139
01140 QByteArray rv;
01141 if ( withHeaderType ) {
01142 rv += typeIntro();
01143 }
01144 rv += '<' + d_func()->mailbox.as7BitString( d_func()->encCS ) + '>';
01145 return rv;
01146 }
01147
01148 void ReturnPath::clear()
01149 {
01150 Q_D(ReturnPath);
01151 d->mailbox.setAddress( Types::AddrSpec() );
01152 d->mailbox.setName( QString() );
01153 }
01154
01155 bool ReturnPath::isEmpty() const
01156 {
01157 const Q_D(ReturnPath);
01158 return !d->mailbox.hasAddress() && !d->mailbox.hasName();
01159 }
01160
01161 bool ReturnPath::parse( const char* &scursor, const char * const send,
01162 bool isCRLF )
01163 {
01164 Q_D(ReturnPath);
01165 eatCFWS( scursor, send, isCRLF );
01166 if ( scursor == send ) {
01167 return false;
01168 }
01169
01170 const char * oldscursor = scursor;
01171
01172 Mailbox maybeMailbox;
01173 if ( !parseMailbox( scursor, send, maybeMailbox, isCRLF ) ) {
01174
01175 scursor = oldscursor;
01176 if ( *scursor != '<' ) {
01177 return false;
01178 }
01179 scursor++;
01180 eatCFWS( scursor, send, isCRLF );
01181 if ( scursor == send || *scursor != '>' ) {
01182 return false;
01183 }
01184 scursor++;
01185
01186
01187 AddrSpec emptyAddrSpec;
01188 maybeMailbox.setName( QString() );
01189 maybeMailbox.setAddress( emptyAddrSpec );
01190 } else {
01191
01192 if ( maybeMailbox.hasName() ) {
01193 KMIME_WARN << "display-name \"" << maybeMailbox.name()
01194 << "\" in Return-Path!" << endl;
01195 }
01196 }
01197 d->mailbox = maybeMailbox;
01198
01199
01200 eatCFWS( scursor, send, isCRLF );
01201
01202 if ( scursor != send ) {
01203 KMIME_WARN << "trailing garbage after angle-addr in Return-Path!" << endl;
01204 }
01205 return true;
01206 }
01207
01208
01209
01210
01211
01212
01213
01214 Generic::Generic() : Generics::Unstructured( new GenericPrivate )
01215 {
01216 }
01217
01218 Generic::Generic( const char *t ) : Generics::Unstructured( new GenericPrivate )
01219 {
01220 setType( t );
01221 }
01222
01223 Generic::Generic( const char *t, Content *p )
01224 : Generics::Unstructured( new GenericPrivate, p )
01225 {
01226 setType( t );
01227 }
01228
01229 Generic::Generic( const char *t, Content *p, const QByteArray &s )
01230 : Generics::Unstructured( new GenericPrivate, p )
01231 {
01232 from7BitString( s );
01233 setType( t );
01234 }
01235
01236 Generic::Generic( const char *t, Content *p, const QString &s, const QByteArray &cs )
01237 : Generics::Unstructured( new GenericPrivate, p )
01238 {
01239 fromUnicodeString( s, cs );
01240 setType( t );
01241 }
01242
01243 Generic::~Generic()
01244 {
01245 }
01246
01247 void Generic::clear()
01248 {
01249 Q_D(Generic);
01250 delete[] d->type;
01251 d->type = 0;
01252 Unstructured::clear();
01253 }
01254
01255 bool Generic::isEmpty() const
01256 {
01257 return d_func()->type == 0 || Unstructured::isEmpty();
01258 }
01259
01260 const char *Generic::type() const
01261 {
01262 return d_func()->type;
01263 }
01264
01265 void Generic::setType( const char *type )
01266 {
01267 Q_D(Generic);
01268 if ( d->type ) {
01269 delete[] d->type;
01270 }
01271 if ( type ) {
01272 d->type = new char[strlen( type )+1];
01273 strcpy( d->type, type );
01274 } else {
01275 d->type = 0;
01276 }
01277 }
01278
01279
01280
01281
01282
01283
01284 kmime_mk_trivial_ctor_with_name( MessageID, Generics::SingleIdent, Message-ID )
01285
01286
01287 void MessageID::generate( const QByteArray &fqdn )
01288 {
01289 setIdentifier( '<' + uniqueString() + '@' + fqdn + '>' );
01290 }
01291
01292
01293
01294
01295
01296
01297 kmime_mk_trivial_ctor_with_name_and_dptr( Control, Generics::Structured, Control )
01298
01299
01300 QByteArray Control::as7BitString( bool withHeaderType ) const
01301 {
01302 const Q_D(Control);
01303 if ( isEmpty() ) {
01304 return QByteArray();
01305 }
01306
01307 QByteArray rv;
01308 if ( withHeaderType ) {
01309 rv += typeIntro();
01310 }
01311
01312 rv += d->name;
01313 if ( !d->parameter.isEmpty() ) {
01314 rv += ' ' + d->parameter;
01315 }
01316 return rv;
01317 }
01318
01319 void Control::clear()
01320 {
01321 Q_D(Control);
01322 d->name.clear();
01323 d->parameter.clear();
01324 }
01325
01326 bool Control::isEmpty() const
01327 {
01328 return d_func()->name.isEmpty();
01329 }
01330
01331 QByteArray Control::controlType() const
01332 {
01333 return d_func()->name;
01334 }
01335
01336 QByteArray Control::parameter() const
01337 {
01338 return d_func()->parameter;
01339 }
01340
01341 bool Control::isCancel() const
01342 {
01343 return d_func()->name.toLower() == "cancel";
01344 }
01345
01346 void Control::setCancel( const QByteArray &msgid )
01347 {
01348 Q_D(Control);
01349 d->name = "cancel";
01350 d->parameter = msgid;
01351 }
01352
01353 bool Control::parse( const char* &scursor, const char *const send, bool isCRLF )
01354 {
01355 Q_D(Control);
01356 clear();
01357 eatCFWS( scursor, send, isCRLF );
01358 if ( scursor == send ) {
01359 return false;
01360 }
01361 const char *start = scursor;
01362 while ( scursor != send && !isspace( *scursor ) ) {
01363 ++scursor;
01364 }
01365 d->name = QByteArray( start, scursor - start );
01366 eatCFWS( scursor, send, isCRLF );
01367 d->parameter = QByteArray( scursor, send - scursor );
01368 return true;
01369 }
01370
01371
01372
01373
01374
01375
01376 kmime_mk_trivial_ctor_with_name_and_dptr( MailCopiesTo,
01377 Generics::AddressList, Mail-Copies-To )
01378
01379
01380 QByteArray MailCopiesTo::as7BitString( bool withHeaderType ) const
01381 {
01382 QByteArray rv;
01383 if ( withHeaderType ) {
01384 rv += typeIntro();
01385 }
01386 if ( !AddressList::isEmpty() ) {
01387 rv += AddressList::as7BitString( false );
01388 } else {
01389 if ( d_func()->alwaysCopy ) {
01390 rv += "poster";
01391 } else if ( d_func()->neverCopy ) {
01392 rv += "nobody";
01393 }
01394 }
01395 return rv;
01396 }
01397
01398 QString MailCopiesTo::asUnicodeString() const
01399 {
01400 if ( !AddressList::isEmpty() ) {
01401 return AddressList::asUnicodeString();
01402 }
01403 if ( d_func()->alwaysCopy ) {
01404 return QLatin1String( "poster" );
01405 }
01406 if ( d_func()->neverCopy ) {
01407 return QLatin1String( "nobody" );
01408 }
01409 return QString();
01410 }
01411
01412 void MailCopiesTo::clear()
01413 {
01414 Q_D(MailCopiesTo);
01415 AddressList::clear();
01416 d->alwaysCopy = false;
01417 d->neverCopy = false;
01418 }
01419
01420 bool MailCopiesTo::isEmpty() const
01421 {
01422 return AddressList::isEmpty() && !(d_func()->alwaysCopy || d_func()->neverCopy);
01423 }
01424
01425 bool MailCopiesTo::alwaysCopy() const
01426 {
01427 return !AddressList::isEmpty() || d_func()->alwaysCopy;
01428 }
01429
01430 void MailCopiesTo::setAlwaysCopy()
01431 {
01432 Q_D(MailCopiesTo);
01433 clear();
01434 d->alwaysCopy = true;
01435 }
01436
01437 bool MailCopiesTo::neverCopy() const
01438 {
01439 return d_func()->neverCopy;
01440 }
01441
01442 void MailCopiesTo::setNeverCopy()
01443 {
01444 Q_D(MailCopiesTo);
01445 clear();
01446 d->neverCopy = true;
01447 }
01448
01449 bool MailCopiesTo::parse( const char *& scursor, const char * const send,
01450 bool isCRLF )
01451 {
01452 Q_D(MailCopiesTo);
01453 clear();
01454 if ( send - scursor == 5 ) {
01455 if ( qstrnicmp( "never", scursor, 5 ) == 0 ) {
01456 d->neverCopy = true;
01457 return true;
01458 }
01459 }
01460 if ( send - scursor == 6 ) {
01461 if ( qstrnicmp( "always", scursor, 6 ) == 0 || qstrnicmp( "poster", scursor, 6 ) == 0 ) {
01462 d->alwaysCopy = true;
01463 return true;
01464 }
01465 if ( qstrnicmp( "nobody", scursor, 6 ) == 0 ) {
01466 d->neverCopy = true;
01467 return true;
01468 }
01469 }
01470 return AddressList::parse( scursor, send, isCRLF );
01471 }
01472
01473
01474
01475
01476
01477
01478 kmime_mk_trivial_ctor_with_name_and_dptr( Date, Generics::Structured, Date )
01479
01480
01481 QByteArray Date::as7BitString( bool withHeaderType ) const
01482 {
01483 if ( isEmpty() ) {
01484 return QByteArray();
01485 }
01486
01487 QByteArray rv;
01488 if ( withHeaderType ) {
01489 rv += typeIntro();
01490 }
01491 rv += d_func()->dateTime.toString( KDateTime::RFCDateDay ).toLatin1();
01492 return rv;
01493 }
01494
01495 void Date::clear()
01496 {
01497 Q_D(Date);
01498 d->dateTime = KDateTime();
01499 }
01500
01501 bool Date::isEmpty() const
01502 {
01503 return d_func()->dateTime.isNull() || !d_func()->dateTime.isValid();
01504 }
01505
01506 KDateTime Date::dateTime() const
01507 {
01508 return d_func()->dateTime;
01509 }
01510
01511 void Date::setDateTime( const KDateTime &dt )
01512 {
01513 Q_D(Date);
01514 d->dateTime = dt;
01515 }
01516
01517 int Date::ageInDays() const
01518 {
01519 QDate today = QDate::currentDate();
01520 return dateTime().date().daysTo(today);
01521 }
01522
01523 bool Date::parse( const char* &scursor, const char *const send, bool isCRLF )
01524 {
01525 Q_D(Date);
01526 return parseDateTime( scursor, send, d->dateTime, isCRLF );
01527 }
01528
01529
01530
01531
01532
01533
01534 kmime_mk_trivial_ctor_with_name_and_dptr( Newsgroups, Generics::Structured, Newsgroups )
01535 kmime_mk_trivial_ctor_with_name( FollowUpTo, Newsgroups, Followup-To )
01536
01537
01538 QByteArray Newsgroups::as7BitString( bool withHeaderType ) const
01539 {
01540 const Q_D(Newsgroups);
01541 if ( isEmpty() ) {
01542 return QByteArray();
01543 }
01544
01545 QByteArray rv;
01546 if ( withHeaderType ) {
01547 rv += typeIntro();
01548 }
01549
01550 for ( int i = 0; i < d->groups.count(); ++i ) {
01551 rv += d->groups[ i ];
01552 if ( i != d->groups.count() - 1 ) {
01553 rv += ',';
01554 }
01555 }
01556 return rv;
01557 }
01558
01559 void Newsgroups::fromUnicodeString( const QString &s, const QByteArray &b )
01560 {
01561 Q_UNUSED( b );
01562 Q_D(Newsgroups);
01563 from7BitString( s.toUtf8() );
01564 d->encCS = cachedCharset( "UTF-8" );
01565 }
01566
01567 QString Newsgroups::asUnicodeString() const
01568 {
01569 return QString::fromUtf8( as7BitString( false ) );
01570 }
01571
01572 void Newsgroups::clear()
01573 {
01574 Q_D(Newsgroups);
01575 d->groups.clear();
01576 }
01577
01578 bool Newsgroups::isEmpty() const
01579 {
01580 return d_func()->groups.isEmpty();
01581 }
01582
01583 QList<QByteArray> Newsgroups::groups() const
01584 {
01585 return d_func()->groups;
01586 }
01587
01588 void Newsgroups::setGroups( const QList<QByteArray> &groups )
01589 {
01590 Q_D(Newsgroups);
01591 d->groups = groups;
01592 }
01593
01594 bool Newsgroups::isCrossposted() const
01595 {
01596 return d_func()->groups.count() >= 2;
01597 }
01598
01599 bool Newsgroups::parse( const char* &scursor, const char *const send, bool isCRLF )
01600 {
01601 Q_D(Newsgroups);
01602 clear();
01603 forever {
01604 eatCFWS( scursor, send, isCRLF );
01605 if ( scursor != send && *scursor == ',' ) {
01606 ++scursor;
01607 }
01608 eatCFWS( scursor, send, isCRLF );
01609 if ( scursor == send ) {
01610 return true;
01611 }
01612 const char *start = scursor;
01613 while ( scursor != send && !isspace( *scursor ) && *scursor != ',' ) {
01614 ++scursor;
01615 }
01616 QByteArray group( start, scursor - start );
01617 d->groups.append( group );
01618 }
01619 return true;
01620 }
01621
01622
01623
01624
01625
01626
01627 kmime_mk_trivial_ctor_with_name_and_dptr( Lines, Generics::Structured, Lines )
01628
01629
01630 QByteArray Lines::as7BitString( bool withHeaderType ) const
01631 {
01632 if ( isEmpty() ) {
01633 return QByteArray();
01634 }
01635
01636 QByteArray num;
01637 num.setNum( d_func()->lines );
01638
01639 if ( withHeaderType ) {
01640 return typeIntro() + num;
01641 }
01642 return num;
01643 }
01644
01645 QString Lines::asUnicodeString() const
01646 {
01647 if ( isEmpty() ) {
01648 return QString();
01649 }
01650 return QString::number( d_func()->lines );
01651 }
01652
01653 void Lines::clear()
01654 {
01655 Q_D(Lines);
01656 d->lines = -1;
01657 }
01658
01659 bool Lines::isEmpty() const
01660 {
01661 return d_func()->lines == -1;
01662 }
01663
01664 int Lines::numberOfLines() const
01665 {
01666 return d_func()->lines;
01667 }
01668
01669 void Lines::setNumberOfLines( int lines )
01670 {
01671 Q_D(Lines);
01672 d->lines = lines;
01673 }
01674
01675 bool Lines::parse( const char* &scursor, const char* const send, bool isCRLF )
01676 {
01677 Q_D(Lines);
01678 eatCFWS( scursor, send, isCRLF );
01679 if ( parseDigits( scursor, send, d->lines ) == 0 ) {
01680 clear();
01681 return false;
01682 }
01683 return true;
01684 }
01685
01686
01687
01688
01689
01690
01691 kmime_mk_trivial_ctor_with_name_and_dptr( ContentType, Generics::Parametrized,
01692 Content-Type )
01693
01694
01695 bool ContentType::isEmpty() const
01696 {
01697 return d_func()->mimeType.isEmpty();
01698 }
01699
01700 void ContentType::clear()
01701 {
01702 Q_D(ContentType);
01703 d->category = CCsingle;
01704 d->mimeType.clear();
01705 d->mimeSubType.clear();
01706 Parametrized::clear();
01707 }
01708
01709 QByteArray ContentType::as7BitString( bool withHeaderType ) const
01710 {
01711 if ( isEmpty() ) {
01712 return QByteArray();
01713 }
01714
01715 QByteArray rv;
01716 if ( withHeaderType ) {
01717 rv += typeIntro();
01718 }
01719
01720 rv += mimeType();
01721 if ( !Parametrized::isEmpty() ) {
01722 rv += "; " + Parametrized::as7BitString( false );
01723 }
01724
01725 return rv;
01726 }
01727
01728 QByteArray ContentType::mimeType() const
01729 {
01730 Q_D(const ContentType);
01731 QByteArray mt;
01732 mt.reserve( d->mimeType.size() + d->mimeSubType.size() + 1 );
01733 mt.append( d->mimeType );
01734 mt.append( '/' );
01735 mt.append( d->mimeSubType );
01736 return mt;
01737 }
01738
01739 QByteArray ContentType::mediaType() const
01740 {
01741 return d_func()->mimeType;
01742 }
01743
01744 QByteArray ContentType::subType() const
01745 {
01746 return d_func()->mimeSubType;
01747 }
01748
01749 void ContentType::setMimeType( const QByteArray &mimeType )
01750 {
01751 Q_D(ContentType);
01752 int pos = mimeType.indexOf( '/' );
01753 if ( pos < 0 ) {
01754 d->mimeType = mimeType;
01755 d->mimeSubType.clear();
01756 } else {
01757 d->mimeType = mimeType.left( pos );
01758 d->mimeSubType = mimeType.mid( pos + 1 );
01759 }
01760 Parametrized::clear();
01761
01762 if ( isMultipart() ) {
01763 d->category = CCcontainer;
01764 } else {
01765 d->category = CCsingle;
01766 }
01767 }
01768
01769 bool ContentType::isMediatype( const char *mediatype ) const
01770 {
01771 return strncasecmp( mediaType().constData(), mediatype, strlen( mediatype ) ) == 0;
01772 }
01773
01774 bool ContentType::isSubtype( const char *subtype ) const
01775 {
01776 return strncasecmp( subType().constData(), subtype, strlen( subtype ) ) == 0;
01777 }
01778
01779 bool ContentType::isText() const
01780 {
01781 return ( strncasecmp( mediaType().constData(), "text", 4 ) == 0
01782 || isEmpty() );
01783 }
01784
01785 bool ContentType::isPlainText() const
01786 {
01787 return ( strcasecmp( mimeType().constData(), "text/plain" ) == 0
01788 || isEmpty() );
01789 }
01790
01791 bool ContentType::isHTMLText() const
01792 {
01793 return strcasecmp( mimeType().constData(), "text/html" ) == 0;
01794 }
01795
01796 bool ContentType::isImage() const
01797 {
01798 return strncasecmp( mediaType().constData(), "image", 5 ) == 0;
01799 }
01800
01801 bool ContentType::isMultipart() const
01802 {
01803 return strncasecmp( mediaType().constData(), "multipart", 9 ) == 0;
01804 }
01805
01806 bool ContentType::isPartial() const
01807 {
01808 return strcasecmp( mimeType().constData(), "message/partial" ) == 0;
01809 }
01810
01811 QByteArray ContentType::charset() const
01812 {
01813 QByteArray ret = parameter( QLatin1String( "charset" ) ).toLatin1();
01814 if ( ret.isEmpty() || forceDefaultCharset() ) {
01815
01816 ret = defaultCharset();
01817 }
01818 return ret;
01819 }
01820
01821 void ContentType::setCharset( const QByteArray &s )
01822 {
01823 setParameter( QLatin1String( "charset" ), QString::fromLatin1( s ) );
01824 }
01825
01826 QByteArray ContentType::boundary() const
01827 {
01828 return parameter( QLatin1String( "boundary" ) ).toLatin1();
01829 }
01830
01831 void ContentType::setBoundary( const QByteArray &s )
01832 {
01833 setParameter( QLatin1String( "boundary" ), QString::fromLatin1( s ) );
01834 }
01835
01836 QString ContentType::name() const
01837 {
01838 return parameter( QLatin1String( "name" ) );
01839 }
01840
01841 void ContentType::setName( const QString &s, const QByteArray &cs )
01842 {
01843 Q_D(ContentType);
01844 d->encCS = cs;
01845 setParameter( QLatin1String( "name" ), s );
01846 }
01847
01848 QByteArray ContentType::id() const
01849 {
01850 return parameter( QLatin1String( "id" ) ).toLatin1();
01851 }
01852
01853 void ContentType::setId( const QByteArray &s )
01854 {
01855 setParameter( QLatin1String( "id" ), QString::fromLatin1( s ) );
01856 }
01857
01858 int ContentType::partialNumber() const
01859 {
01860 QByteArray p = parameter( QLatin1String( "number" ) ).toLatin1();
01861 if ( !p.isEmpty() ) {
01862 return p.toInt();
01863 } else {
01864 return -1;
01865 }
01866 }
01867
01868 int ContentType::partialCount() const
01869 {
01870 QByteArray p = parameter( QLatin1String( "total" ) ).toLatin1();
01871 if ( !p.isEmpty() ) {
01872 return p.toInt();
01873 } else {
01874 return -1;
01875 }
01876 }
01877
01878 contentCategory ContentType::category() const
01879 {
01880 return d_func()->category;
01881 }
01882
01883 void ContentType::setCategory( contentCategory c )
01884 {
01885 Q_D(ContentType);
01886 d->category = c;
01887 }
01888
01889 void ContentType::setPartialParams( int total, int number )
01890 {
01891 setParameter( QLatin1String( "number" ), QString::number( number ) );
01892 setParameter( QLatin1String( "total" ), QString::number( total ) );
01893 }
01894
01895 bool ContentType::parse( const char* &scursor, const char * const send,
01896 bool isCRLF )
01897 {
01898 Q_D(ContentType);
01899
01900
01901 clear();
01902 eatCFWS( scursor, send, isCRLF );
01903 if ( scursor == send ) {
01904 return false;
01905 }
01906
01907
01908 QPair<const char*,int> maybeMimeType;
01909 if ( !parseToken( scursor, send, maybeMimeType, false ) ) {
01910 return false;
01911 }
01912 d->mimeType = QByteArray( maybeMimeType.first, maybeMimeType.second ).toLower();
01913
01914
01915 eatCFWS( scursor, send, isCRLF );
01916 if ( scursor == send || *scursor != '/' ) {
01917 return false;
01918 }
01919 scursor++;
01920 eatCFWS( scursor, send, isCRLF );
01921 if ( scursor == send ) {
01922 return false;
01923 }
01924
01925 QPair<const char*,int> maybeSubType;
01926 if ( !parseToken( scursor, send, maybeSubType, false ) ) {
01927 return false;
01928 }
01929 d->mimeSubType = QByteArray( maybeSubType.first, maybeSubType.second ).toLower();
01930
01931
01932 eatCFWS( scursor, send, isCRLF );
01933 if ( scursor == send ) {
01934 goto success;
01935 }
01936
01937 if ( *scursor != ';' ) {
01938 return false;
01939 }
01940 scursor++;
01941
01942 if ( !Parametrized::parse( scursor, send, isCRLF ) ) {
01943 return false;
01944 }
01945
01946
01947 success:
01948 if ( isMultipart() ) {
01949 d->category = CCcontainer;
01950 } else {
01951 d->category = CCsingle;
01952 }
01953 return true;
01954 }
01955
01956
01957
01958
01959
01960 kmime_mk_trivial_ctor_with_name_and_dptr( ContentID, SingleIdent, Content-ID )
01961 kmime_mk_dptr_ctor( ContentID, SingleIdent )
01962
01963 bool ContentID::parse( const char* &scursor, const char *const send, bool isCRLF )
01964 {
01965 Q_D ( ContentID );
01966
01967
01968
01969 const char* origscursor = scursor;
01970 if ( !SingleIdent::parse ( scursor, send, isCRLF ) )
01971 {
01972 scursor = origscursor;
01973 d->msgIdList.clear();
01974 d->cachedIdentifier.clear();
01975
01976 while ( scursor != send )
01977 {
01978 eatCFWS ( scursor, send, isCRLF );
01979
01980 if ( scursor == send )
01981 {
01982 return true;
01983 }
01984
01985 if ( *scursor == ',' )
01986 {
01987 scursor++;
01988 continue;
01989 }
01990
01991 AddrSpec maybeContentId;
01992
01993 if ( scursor == send || *scursor != '<' )
01994 {
01995 return false;
01996 }
01997 scursor++;
01998
01999 eatCFWS ( scursor, send, isCRLF );
02000 if ( scursor == send )
02001 {
02002 return false;
02003 }
02004
02005
02006 QString result;
02007 if( !parseAtom(scursor, send, result, false) ) {
02008 return false;
02009 }
02010
02011 eatCFWS ( scursor, send, isCRLF );
02012 if ( scursor == send || *scursor != '>' )
02013 {
02014 return false;
02015 }
02016 scursor++;
02017
02018
02019 maybeContentId.localPart = result;
02020 d->msgIdList.append ( maybeContentId );
02021
02022 eatCFWS ( scursor, send, isCRLF );
02023
02024 if ( scursor == send )
02025 {
02026 return true;
02027 }
02028
02029 if ( *scursor == ',' )
02030 {
02031 scursor++;
02032 }
02033 }
02034 return true;
02035 }
02036 else
02037 {
02038 return true;
02039 }
02040 }
02041
02042
02043
02044
02045
02046
02047 kmime_mk_trivial_ctor_with_name_and_dptr( ContentTransferEncoding,
02048 Generics::Token, Content-Transfer-Encoding )
02049
02050
02051 typedef struct { const char *s; int e; } encTableType;
02052
02053 static const encTableType encTable[] =
02054 {
02055 { "7Bit", CE7Bit },
02056 { "8Bit", CE8Bit },
02057 { "quoted-printable", CEquPr },
02058 { "base64", CEbase64 },
02059 { "x-uuencode", CEuuenc },
02060 { "binary", CEbinary },
02061 { 0, 0}
02062 };
02063
02064 void ContentTransferEncoding::clear()
02065 {
02066 Q_D(ContentTransferEncoding);
02067 d->decoded = true;
02068 d->cte = CE7Bit;
02069 Token::clear();
02070 }
02071
02072 contentEncoding ContentTransferEncoding::encoding() const
02073 {
02074 return d_func()->cte;
02075 }
02076
02077 void ContentTransferEncoding::setEncoding( contentEncoding e )
02078 {
02079 Q_D(ContentTransferEncoding);
02080 d->cte = e;
02081
02082 for ( int i = 0; encTable[i].s != 0; ++i ) {
02083 if ( d->cte == encTable[i].e ) {
02084 setToken( encTable[i].s );
02085 break;
02086 }
02087 }
02088 }
02089
02090 bool ContentTransferEncoding::decoded() const
02091 {
02092 return d_func()->decoded;
02093 }
02094
02095 void ContentTransferEncoding::setDecoded( bool decoded )
02096 {
02097 Q_D(ContentTransferEncoding);
02098 d->decoded = decoded;
02099 }
02100
02101 bool ContentTransferEncoding::needToEncode() const
02102 {
02103 const Q_D(ContentTransferEncoding);
02104 return d->decoded && (d->cte == CEquPr || d->cte == CEbase64);
02105 }
02106
02107 bool ContentTransferEncoding::parse( const char *& scursor,
02108 const char * const send, bool isCRLF )
02109 {
02110 Q_D(ContentTransferEncoding);
02111 clear();
02112 if ( !Token::parse( scursor, send, isCRLF ) ) {
02113 return false;
02114 }
02115
02116
02117 for ( int i = 0; encTable[i].s != 0; ++i ) {
02118 if ( strcasecmp( token().constData(), encTable[i].s ) == 0 ) {
02119 d->cte = ( contentEncoding )encTable[i].e;
02120 break;
02121 }
02122 }
02123 d->decoded = ( d->cte == CE7Bit || d->cte == CE8Bit );
02124 return true;
02125 }
02126
02127
02128
02129
02130
02131
02132 kmime_mk_trivial_ctor_with_name_and_dptr( ContentDisposition,
02133 Generics::Parametrized, Content-Disposition )
02134
02135
02136 QByteArray ContentDisposition::as7BitString( bool withHeaderType ) const
02137 {
02138 if ( isEmpty() ) {
02139 return QByteArray();
02140 }
02141
02142 QByteArray rv;
02143 if ( withHeaderType ) {
02144 rv += typeIntro();
02145 }
02146
02147 if ( d_func()->disposition == CDattachment ) {
02148 rv += "attachment";
02149 } else if ( d_func()->disposition == CDinline ) {
02150 rv += "inline";
02151 } else {
02152 return QByteArray();
02153 }
02154
02155 if ( !Parametrized::isEmpty() ) {
02156 rv += "; " + Parametrized::as7BitString( false );
02157 }
02158
02159 return rv;
02160 }
02161
02162 bool ContentDisposition::isEmpty() const
02163 {
02164 return d_func()->disposition == CDInvalid;
02165 }
02166
02167 void ContentDisposition::clear()
02168 {
02169 Q_D(ContentDisposition);
02170 d->disposition = CDInvalid;
02171 Parametrized::clear();
02172 }
02173
02174 contentDisposition ContentDisposition::disposition() const
02175 {
02176 return d_func()->disposition;
02177 }
02178
02179 void ContentDisposition::setDisposition( contentDisposition disp )
02180 {
02181 Q_D(ContentDisposition);
02182 d->disposition = disp;
02183 }
02184
02185 QString KMime::Headers::ContentDisposition::filename() const
02186 {
02187 return parameter( QLatin1String( "filename" ) );
02188 }
02189
02190 void ContentDisposition::setFilename( const QString &filename )
02191 {
02192 setParameter( QLatin1String( "filename" ), filename );
02193 }
02194
02195 bool ContentDisposition::parse( const char *& scursor, const char * const send,
02196 bool isCRLF )
02197 {
02198 Q_D(ContentDisposition);
02199 clear();
02200
02201
02202 QByteArray token;
02203 eatCFWS( scursor, send, isCRLF );
02204 if ( scursor == send ) {
02205 return false;
02206 }
02207
02208 QPair<const char*,int> maybeToken;
02209 if ( !parseToken( scursor, send, maybeToken, false ) ) {
02210 return false;
02211 }
02212
02213 token = QByteArray( maybeToken.first, maybeToken.second ).toLower();
02214 if ( token == "inline" ) {
02215 d->disposition = CDinline;
02216 } else if ( token == "attachment" ) {
02217 d->disposition = CDattachment;
02218 } else {
02219 return false;
02220 }
02221
02222
02223 eatCFWS( scursor, send, isCRLF );
02224 if ( scursor == send ) {
02225 return true;
02226 }
02227
02228 if ( *scursor != ';' ) {
02229 return false;
02230 }
02231 scursor++;
02232
02233 return Parametrized::parse( scursor, send, isCRLF );
02234 }
02235
02236
02237
02238
02239 kmime_mk_trivial_ctor_with_name( Subject, Generics::Unstructured, Subject )
02240
02241
02242 bool Subject::isReply() const
02243 {
02244 return asUnicodeString().indexOf( QLatin1String( "Re:" ), 0, Qt::CaseInsensitive ) == 0;
02245 }
02246
02247 Base* createHeader( const QByteArray& type )
02248 {
02249 return HeaderFactory::self()->createHeader( type );
02250 }
02251
02252
02253
02254 kmime_mk_trivial_ctor_with_name( ContentDescription,
02255 Generics::Unstructured, Content-Description )
02256 kmime_mk_trivial_ctor_with_name( ContentLocation,
02257 Generics::Unstructured, Content-Location )
02258 kmime_mk_trivial_ctor_with_name( From, Generics::MailboxList, From )
02259 kmime_mk_trivial_ctor_with_name( Sender, Generics::SingleMailbox, Sender )
02260 kmime_mk_trivial_ctor_with_name( To, Generics::AddressList, To )
02261 kmime_mk_trivial_ctor_with_name( Cc, Generics::AddressList, Cc )
02262 kmime_mk_trivial_ctor_with_name( Bcc, Generics::AddressList, Bcc )
02263 kmime_mk_trivial_ctor_with_name( ReplyTo, Generics::AddressList, Reply-To )
02264 kmime_mk_trivial_ctor_with_name( Keywords, Generics::PhraseList, Keywords )
02265 kmime_mk_trivial_ctor_with_name( MIMEVersion, Generics::DotAtom, MIME-Version )
02266 kmime_mk_trivial_ctor_with_name( Supersedes, Generics::SingleIdent, Supersedes )
02267 kmime_mk_trivial_ctor_with_name( InReplyTo, Generics::Ident, In-Reply-To )
02268 kmime_mk_trivial_ctor_with_name( References, Generics::Ident, References )
02269 kmime_mk_trivial_ctor_with_name( Organization, Generics::Unstructured, Organization )
02270 kmime_mk_trivial_ctor_with_name( UserAgent, Generics::Unstructured, User-Agent )
02271
02272
02273 }
02274
02275 }