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