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