• Skip to content
  • Skip to link menu
KDE 4.7 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • KDE Home
  • Contact Us
 

KMIME Library

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

KMIME Library

Skip menu "KMIME Library"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Related Pages

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.7.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal