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