• Skip to content
  • Skip to link menu
KDE 4.6 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 }
00999 
01000 bool Ident::isEmpty() const
01001 {
01002   return d_func()->msgIdList.isEmpty();
01003 }
01004 
01005 bool Ident::parse( const char* &scursor, const char * const send, bool isCRLF )
01006 {
01007   Q_D(Ident);
01008   // msg-id   := "<" id-left "@" id-right ">"
01009   // id-left  := dot-atom-text / no-fold-quote / local-part
01010   // id-right := dot-atom-text / no-fold-literal / domain
01011   //
01012   // equivalent to:
01013   // msg-id   := angle-addr
01014 
01015   d->msgIdList.clear();
01016 
01017   while ( scursor != send ) {
01018     eatCFWS( scursor, send, isCRLF );
01019     // empty entry ending the list: OK.
01020     if ( scursor == send ) {
01021       return true;
01022     }
01023     // empty entry: ignore.
01024     if ( *scursor == ',' ) {
01025       scursor++;
01026       continue;
01027     }
01028 
01029     AddrSpec maybeMsgId;
01030     if ( !parseAngleAddr( scursor, send, maybeMsgId, isCRLF ) ) {
01031       return false;
01032     }
01033     d->msgIdList.append( maybeMsgId );
01034 
01035     eatCFWS( scursor, send, isCRLF );
01036     // header end ending the list: OK.
01037     if ( scursor == send ) {
01038       return true;
01039     }
01040     // regular item separator: eat it.
01041     if ( *scursor == ',' ) {
01042       scursor++;
01043     }
01044   }
01045   return true;
01046 }
01047 
01048 QList<QByteArray> Ident::identifiers() const
01049 {
01050   QList<QByteArray> rv;
01051   foreach ( const Types::AddrSpec &addr, d_func()->msgIdList ) {
01052     rv.append( addr.asString().toLatin1() ); // FIXME change parsing to create QByteArrays
01053   }
01054   return rv;
01055 }
01056 
01057 void Ident::appendIdentifier( const QByteArray &id )
01058 {
01059   Q_D(Ident);
01060   QByteArray tmp = id;
01061   if ( !tmp.startsWith( '<' ) ) {
01062     tmp.prepend( '<' );
01063   }
01064   if ( !tmp.endsWith( '>' ) ) {
01065     tmp.append( '>' );
01066   }
01067   AddrSpec msgId;
01068   const char *cursor = tmp.constData();
01069   if ( parseAngleAddr( cursor, cursor + tmp.length(), msgId ) ) {
01070     d->msgIdList.append( msgId );
01071   } else {
01072     kWarning() << "Unable to parse address spec!";
01073   }
01074 }
01075 
01076 //-----</Ident>-------------------------
01077 
01078 //-----<SingleIdent>-------------------------
01079 
01080 //@cond PRIVATE
01081 kmime_mk_trivial_ctor_with_dptr( SingleIdent, Ident )
01082 kmime_mk_dptr_ctor( SingleIdent, Ident )
01083 //@endcond
01084 
01085 QByteArray SingleIdent::identifier() const
01086 {
01087   if ( d_func()->msgIdList.isEmpty() ) {
01088     return QByteArray();
01089   }
01090   const Types::AddrSpec &addr = d_func()->msgIdList.first();
01091   return addr.asString().toLatin1(); // FIXME change parsing to create QByteArrays
01092 }
01093 
01094 void SingleIdent::setIdentifier( const QByteArray &id )
01095 {
01096   Q_D(SingleIdent);
01097   d->msgIdList.clear();
01098   appendIdentifier( id );
01099 }
01100 
01101 bool SingleIdent::parse( const char* &scursor, const char * const send,
01102                          bool isCRLF )
01103 {
01104   Q_D(SingleIdent);
01105   if ( !Ident::parse( scursor, send, isCRLF ) ) {
01106     return false;
01107   }
01108 
01109   if ( d->msgIdList.count() > 1 ) {
01110     KMIME_WARN << "more than one msg-id in header "
01111                << "allowing only a single one!" << endl;
01112   }
01113   return true;
01114 }
01115 
01116 //-----</SingleIdent>-------------------------
01117 
01118 } // namespace Generics
01119 
01120 //-----<ReturnPath>-------------------------
01121 
01122 //@cond PRIVATE
01123 kmime_mk_trivial_ctor_with_name_and_dptr( ReturnPath, Generics::Address, Return-Path )
01124 //@endcond
01125 
01126 QByteArray ReturnPath::as7BitString( bool withHeaderType ) const
01127 {
01128   if ( isEmpty() ) {
01129     return QByteArray();
01130   }
01131 
01132   QByteArray rv;
01133   if ( withHeaderType ) {
01134     rv += typeIntro();
01135   }
01136   rv += '<' + d_func()->mailbox.as7BitString( d_func()->encCS ) + '>';
01137   return rv;
01138 }
01139 
01140 void ReturnPath::clear()
01141 {
01142   Q_D(ReturnPath);
01143   d->mailbox.setAddress( Types::AddrSpec() );
01144   d->mailbox.setName( QString() );
01145 }
01146 
01147 bool ReturnPath::isEmpty() const
01148 {
01149   const Q_D(ReturnPath);
01150   return !d->mailbox.hasAddress() && !d->mailbox.hasName();
01151 }
01152 
01153 bool ReturnPath::parse( const char* &scursor, const char * const send,
01154                         bool isCRLF )
01155 {
01156   Q_D(ReturnPath);
01157   eatCFWS( scursor, send, isCRLF );
01158   if ( scursor == send ) {
01159     return false;
01160   }
01161 
01162   const char * oldscursor = scursor;
01163 
01164   Mailbox maybeMailbox;
01165   if ( !parseMailbox( scursor, send, maybeMailbox, isCRLF ) ) {
01166     // mailbox parsing failed, but check for empty brackets:
01167     scursor = oldscursor;
01168     if ( *scursor != '<' ) {
01169       return false;
01170     }
01171     scursor++;
01172     eatCFWS( scursor, send, isCRLF );
01173     if ( scursor == send || *scursor != '>' ) {
01174       return false;
01175     }
01176     scursor++;
01177 
01178     // prepare a Null mailbox:
01179     AddrSpec emptyAddrSpec;
01180     maybeMailbox.setName( QString() );
01181     maybeMailbox.setAddress( emptyAddrSpec );
01182   } else {
01183     // check that there was no display-name:
01184     if ( maybeMailbox.hasName() ) {
01185       KMIME_WARN << "display-name \"" << maybeMailbox.name()
01186                  << "\" in Return-Path!" << endl;
01187     }
01188   }
01189   d->mailbox = maybeMailbox;
01190 
01191   // see if that was all:
01192   eatCFWS( scursor, send, isCRLF );
01193   // and warn if it wasn't:
01194   if ( scursor != send ) {
01195     KMIME_WARN << "trailing garbage after angle-addr in Return-Path!" << endl;
01196   }
01197   return true;
01198 }
01199 
01200 //-----</ReturnPath>-------------------------
01201 
01202 //-----<Generic>-------------------------------
01203 
01204 // NOTE: Do *not* register Generic with HeaderFactory, since its type() is changeable.
01205 
01206 Generic::Generic() : Generics::Unstructured( new GenericPrivate )
01207 {
01208 }
01209 
01210 Generic::Generic( const char *t ) : Generics::Unstructured( new GenericPrivate )
01211 {
01212   setType( t );
01213 }
01214 
01215 Generic::Generic( const char *t, Content *p )
01216   : Generics::Unstructured( new GenericPrivate, p )
01217 {
01218   setType( t );
01219 }
01220 
01221 Generic::Generic( const char *t, Content *p, const QByteArray &s )
01222   : Generics::Unstructured( new GenericPrivate, p )
01223 {
01224   from7BitString( s );
01225   setType( t );
01226 }
01227 
01228 Generic::Generic( const char *t, Content *p, const QString &s, const QByteArray &cs )
01229   : Generics::Unstructured( new GenericPrivate, p )
01230 {
01231   fromUnicodeString( s, cs );
01232   setType( t );
01233 }
01234 
01235 Generic::~Generic()
01236 {
01237 }
01238 
01239 void Generic::clear()
01240 {
01241   Q_D(Generic);
01242   delete[] d->type;
01243   d->type = 0;
01244   Unstructured::clear();
01245 }
01246 
01247 bool Generic::isEmpty() const
01248 {
01249   return d_func()->type == 0 || Unstructured::isEmpty();
01250 }
01251 
01252 const char *Generic::type() const
01253 {
01254   return d_func()->type;
01255 }
01256 
01257 void Generic::setType( const char *type )
01258 {
01259   Q_D(Generic);
01260   if ( d->type ) {
01261     delete[] d->type;
01262   }
01263   if ( type ) {
01264     d->type = new char[strlen( type )+1];
01265     strcpy( d->type, type );
01266   } else {
01267     d->type = 0;
01268   }
01269 }
01270 
01271 //-----<Generic>-------------------------------
01272 
01273 //-----<MessageID>-----------------------------
01274 
01275 //@cond PRIVATE
01276 kmime_mk_trivial_ctor_with_name( MessageID, Generics::SingleIdent, Message-ID )
01277 //@endcond
01278 
01279 void MessageID::generate( const QByteArray &fqdn )
01280 {
01281   setIdentifier( '<' + uniqueString() + '@' + fqdn + '>' );
01282 }
01283 
01284 //-----</MessageID>----------------------------
01285 
01286 //-----<Control>-------------------------------
01287 
01288 //@cond PRIVATE
01289 kmime_mk_trivial_ctor_with_name_and_dptr( Control, Generics::Structured, Control )
01290 //@endcond
01291 
01292 QByteArray Control::as7BitString( bool withHeaderType ) const
01293 {
01294   const Q_D(Control);
01295   if ( isEmpty() ) {
01296     return QByteArray();
01297   }
01298 
01299   QByteArray rv;
01300   if ( withHeaderType ) {
01301     rv += typeIntro();
01302   }
01303 
01304   rv += d->name;
01305   if ( !d->parameter.isEmpty() ) {
01306     rv += ' ' + d->parameter;
01307   }
01308   return rv;
01309 }
01310 
01311 void Control::clear()
01312 {
01313   Q_D(Control);
01314   d->name.clear();
01315   d->parameter.clear();
01316 }
01317 
01318 bool Control::isEmpty() const
01319 {
01320   return d_func()->name.isEmpty();
01321 }
01322 
01323 QByteArray Control::controlType() const
01324 {
01325   return d_func()->name;
01326 }
01327 
01328 QByteArray Control::parameter() const
01329 {
01330   return d_func()->parameter;
01331 }
01332 
01333 bool Control::isCancel() const
01334 {
01335   return d_func()->name.toLower() == "cancel";
01336 }
01337 
01338 void Control::setCancel( const QByteArray &msgid )
01339 {
01340   Q_D(Control);
01341   d->name = "cancel";
01342   d->parameter = msgid;
01343 }
01344 
01345 bool Control::parse( const char* &scursor, const char *const send, bool isCRLF )
01346 {
01347   Q_D(Control);
01348   clear();
01349   eatCFWS( scursor, send, isCRLF );
01350   if ( scursor == send ) {
01351     return false;
01352   }
01353   const char *start = scursor;
01354   while ( scursor != send && !isspace( *scursor ) ) {
01355     ++scursor;
01356   }
01357   d->name = QByteArray( start, scursor - start );
01358   eatCFWS( scursor, send, isCRLF );
01359   d->parameter = QByteArray( scursor, send - scursor );
01360   return true;
01361 }
01362 
01363 //-----</Control>------------------------------
01364 
01365 //-----<MailCopiesTo>--------------------------
01366 
01367 //@cond PRIVATE
01368 kmime_mk_trivial_ctor_with_name_and_dptr( MailCopiesTo,
01369                                  Generics::AddressList, Mail-Copies-To )
01370 //@endcond
01371 
01372 QByteArray MailCopiesTo::as7BitString( bool withHeaderType ) const
01373 {
01374   QByteArray rv;
01375   if ( withHeaderType ) {
01376     rv += typeIntro();
01377   }
01378   if ( !AddressList::isEmpty() ) {
01379     rv += AddressList::as7BitString( false );
01380   } else {
01381     if ( d_func()->alwaysCopy ) {
01382       rv += "poster";
01383     } else if ( d_func()->neverCopy ) {
01384       rv += "nobody";
01385     }
01386   }
01387   return rv;
01388 }
01389 
01390 QString MailCopiesTo::asUnicodeString() const
01391 {
01392   if ( !AddressList::isEmpty() ) {
01393     return AddressList::asUnicodeString();
01394   }
01395   if ( d_func()->alwaysCopy ) {
01396     return QLatin1String( "poster" );
01397   }
01398   if ( d_func()->neverCopy ) {
01399     return QLatin1String( "nobody" );
01400   }
01401   return QString();
01402 }
01403 
01404 void MailCopiesTo::clear()
01405 {
01406   Q_D(MailCopiesTo);
01407   AddressList::clear();
01408   d->alwaysCopy = false;
01409   d->neverCopy = false;
01410 }
01411 
01412 bool MailCopiesTo::isEmpty() const
01413 {
01414   return AddressList::isEmpty() && !(d_func()->alwaysCopy || d_func()->neverCopy);
01415 }
01416 
01417 bool MailCopiesTo::alwaysCopy() const
01418 {
01419   return !AddressList::isEmpty() || d_func()->alwaysCopy;
01420 }
01421 
01422 void MailCopiesTo::setAlwaysCopy()
01423 {
01424   Q_D(MailCopiesTo);
01425   clear();
01426   d->alwaysCopy = true;
01427 }
01428 
01429 bool MailCopiesTo::neverCopy() const
01430 {
01431   return d_func()->neverCopy;
01432 }
01433 
01434 void MailCopiesTo::setNeverCopy()
01435 {
01436   Q_D(MailCopiesTo);
01437   clear();
01438   d->neverCopy = true;
01439 }
01440 
01441 bool MailCopiesTo::parse( const char *& scursor, const char * const send,
01442                           bool isCRLF )
01443 {
01444   Q_D(MailCopiesTo);
01445   clear();
01446   if ( send - scursor == 5 ) {
01447     if ( qstrnicmp( "never", scursor, 5 ) == 0 ) {
01448       d->neverCopy = true;
01449       return true;
01450     }
01451   }
01452   if ( send - scursor == 6 ) {
01453     if ( qstrnicmp( "always", scursor, 6 ) == 0 || qstrnicmp( "poster", scursor, 6 ) == 0 ) {
01454       d->alwaysCopy = true;
01455       return true;
01456     }
01457     if ( qstrnicmp( "nobody", scursor, 6 ) == 0 ) {
01458       d->neverCopy = true;
01459       return true;
01460     }
01461   }
01462   return AddressList::parse( scursor, send, isCRLF );
01463 }
01464 
01465 //-----</MailCopiesTo>-------------------------
01466 
01467 //-----<Date>----------------------------------
01468 
01469 //@cond PRIVATE
01470 kmime_mk_trivial_ctor_with_name_and_dptr( Date, Generics::Structured, Date )
01471 //@endcond
01472 
01473 QByteArray Date::as7BitString( bool withHeaderType ) const
01474 {
01475   if ( isEmpty() ) {
01476     return QByteArray();
01477   }
01478 
01479   QByteArray rv;
01480   if ( withHeaderType ) {
01481     rv += typeIntro();
01482   }
01483   rv += d_func()->dateTime.toString( KDateTime::RFCDateDay ).toLatin1();
01484   return rv;
01485 }
01486 
01487 void Date::clear()
01488 {
01489   Q_D(Date);
01490   d->dateTime = KDateTime();
01491 }
01492 
01493 bool Date::isEmpty() const
01494 {
01495   return d_func()->dateTime.isNull() || !d_func()->dateTime.isValid();
01496 }
01497 
01498 KDateTime Date::dateTime() const
01499 {
01500   return d_func()->dateTime;
01501 }
01502 
01503 void Date::setDateTime( const KDateTime &dt )
01504 {
01505   Q_D(Date);
01506   d->dateTime = dt;
01507 }
01508 
01509 int Date::ageInDays() const
01510 {
01511   QDate today = QDate::currentDate();
01512   return dateTime().date().daysTo(today);
01513 }
01514 
01515 bool Date::parse( const char* &scursor, const char *const send, bool isCRLF )
01516 {
01517   Q_D(Date);
01518   return parseDateTime( scursor, send, d->dateTime, isCRLF );
01519 }
01520 
01521 //-----</Date>---------------------------------
01522 
01523 //-----<Newsgroups>----------------------------
01524 
01525 //@cond PRIVATE
01526 kmime_mk_trivial_ctor_with_name_and_dptr( Newsgroups, Generics::Structured, Newsgroups )
01527 kmime_mk_trivial_ctor_with_name( FollowUpTo, Newsgroups, Followup-To )
01528 //@endcond
01529 
01530 QByteArray Newsgroups::as7BitString( bool withHeaderType ) const
01531 {
01532   const Q_D(Newsgroups);
01533   if ( isEmpty() ) {
01534     return QByteArray();
01535   }
01536 
01537   QByteArray rv;
01538   if ( withHeaderType ) {
01539     rv += typeIntro();
01540   }
01541 
01542   for ( int i = 0; i < d->groups.count(); ++i ) {
01543     rv += d->groups[ i ];
01544     if ( i != d->groups.count() - 1 ) {
01545       rv += ',';
01546     }
01547   }
01548   return rv;
01549 }
01550 
01551 void Newsgroups::fromUnicodeString( const QString &s, const QByteArray &b )
01552 {
01553   Q_UNUSED( b );
01554   Q_D(Newsgroups);
01555   from7BitString( s.toUtf8() );
01556   d->encCS = cachedCharset( "UTF-8" );
01557 }
01558 
01559 QString Newsgroups::asUnicodeString() const
01560 {
01561   return QString::fromUtf8( as7BitString( false ) );
01562 }
01563 
01564 void Newsgroups::clear()
01565 {
01566   Q_D(Newsgroups);
01567   d->groups.clear();
01568 }
01569 
01570 bool Newsgroups::isEmpty() const
01571 {
01572   return d_func()->groups.isEmpty();
01573 }
01574 
01575 QList<QByteArray> Newsgroups::groups() const
01576 {
01577   return d_func()->groups;
01578 }
01579 
01580 void Newsgroups::setGroups( const QList<QByteArray> &groups )
01581 {
01582   Q_D(Newsgroups);
01583   d->groups = groups;
01584 }
01585 
01586 bool Newsgroups::isCrossposted() const
01587 {
01588   return d_func()->groups.count() >= 2;
01589 }
01590 
01591 bool Newsgroups::parse( const char* &scursor, const char *const send, bool isCRLF )
01592 {
01593   Q_D(Newsgroups);
01594   clear();
01595   forever {
01596     eatCFWS( scursor, send, isCRLF );
01597     if ( scursor != send && *scursor == ',' ) {
01598       ++scursor;
01599     }
01600     eatCFWS( scursor, send, isCRLF );
01601     if ( scursor == send ) {
01602       return true;
01603     }
01604     const char *start = scursor;
01605     while ( scursor != send && !isspace( *scursor ) && *scursor != ',' ) {
01606       ++scursor;
01607     }
01608     QByteArray group( start, scursor - start );
01609     d->groups.append( group );
01610   }
01611   return true;
01612 }
01613 
01614 //-----</Newsgroups>---------------------------
01615 
01616 //-----<Lines>---------------------------------
01617 
01618 //@cond PRIVATE
01619 kmime_mk_trivial_ctor_with_name_and_dptr( Lines, Generics::Structured, Lines )
01620 //@endcond
01621 
01622 QByteArray Lines::as7BitString( bool withHeaderType ) const
01623 {
01624   if ( isEmpty() ) {
01625     return QByteArray();
01626   }
01627 
01628   QByteArray num;
01629   num.setNum( d_func()->lines );
01630 
01631   if ( withHeaderType ) {
01632     return typeIntro() + num;
01633   }
01634   return num;
01635 }
01636 
01637 QString Lines::asUnicodeString() const
01638 {
01639   if ( isEmpty() ) {
01640     return QString();
01641   }
01642   return QString::number( d_func()->lines );
01643 }
01644 
01645 void Lines::clear()
01646 {
01647   Q_D(Lines);
01648   d->lines = -1;
01649 }
01650 
01651 bool Lines::isEmpty() const
01652 {
01653   return d_func()->lines == -1;
01654 }
01655 
01656 int Lines::numberOfLines() const
01657 {
01658   return d_func()->lines;
01659 }
01660 
01661 void Lines::setNumberOfLines( int lines )
01662 {
01663   Q_D(Lines);
01664   d->lines = lines;
01665 }
01666 
01667 bool Lines::parse( const char* &scursor, const char* const send, bool isCRLF )
01668 {
01669   Q_D(Lines);
01670   eatCFWS( scursor, send, isCRLF );
01671   if ( parseDigits( scursor, send, d->lines )  == 0 ) {
01672     clear();
01673     return false;
01674   }
01675   return true;
01676 }
01677 
01678 //-----</Lines>--------------------------------
01679 
01680 //-----<Content-Type>--------------------------
01681 
01682 //@cond PRIVATE
01683 kmime_mk_trivial_ctor_with_name_and_dptr( ContentType, Generics::Parametrized,
01684                                  Content-Type )
01685 //@endcond
01686 
01687 bool ContentType::isEmpty() const
01688 {
01689   return d_func()->mimeType.isEmpty();
01690 }
01691 
01692 void ContentType::clear()
01693 {
01694   Q_D(ContentType);
01695   d->category = CCsingle;
01696   d->mimeType.clear();
01697   d->mimeSubType.clear();
01698   Parametrized::clear();
01699 }
01700 
01701 QByteArray ContentType::as7BitString( bool withHeaderType ) const
01702 {
01703   if ( isEmpty() ) {
01704     return QByteArray();
01705   }
01706 
01707   QByteArray rv;
01708   if ( withHeaderType ) {
01709     rv += typeIntro();
01710   }
01711 
01712   rv += mimeType();
01713   if ( !Parametrized::isEmpty() ) {
01714     rv += "; " + Parametrized::as7BitString( false );
01715   }
01716 
01717   return rv;
01718 }
01719 
01720 QByteArray ContentType::mimeType() const
01721 {
01722   Q_D(const ContentType);
01723   QByteArray mt;
01724   mt.reserve( d->mimeType.size() + d->mimeSubType.size() + 1 );
01725   mt.append( d->mimeType );
01726   mt.append( '/' );
01727   mt.append( d->mimeSubType );
01728   return mt;
01729 }
01730 
01731 QByteArray ContentType::mediaType() const
01732 {
01733   return d_func()->mimeType;
01734 }
01735 
01736 QByteArray ContentType::subType() const
01737 {
01738   return d_func()->mimeSubType;
01739 }
01740 
01741 void ContentType::setMimeType( const QByteArray &mimeType )
01742 {
01743   Q_D(ContentType);
01744   int pos = mimeType.indexOf( '/' );
01745   if ( pos < 0 ) {
01746     d->mimeType = mimeType;
01747     d->mimeSubType.clear();
01748   } else {
01749     d->mimeType = mimeType.left( pos );
01750     d->mimeSubType = mimeType.mid( pos + 1 );
01751   }
01752   Parametrized::clear();
01753 
01754   if ( isMultipart() ) {
01755     d->category = CCcontainer;
01756   } else {
01757     d->category = CCsingle;
01758   }
01759 }
01760 
01761 bool ContentType::isMediatype( const char *mediatype ) const
01762 {
01763   return strncasecmp( mediaType().constData(), mediatype, strlen( mediatype ) ) == 0;
01764 }
01765 
01766 bool ContentType::isSubtype( const char *subtype ) const
01767 {
01768   return strncasecmp( subType().constData(), subtype, strlen( subtype ) ) == 0;
01769 }
01770 
01771 bool ContentType::isText() const
01772 {
01773   return ( strncasecmp( mediaType().constData(), "text", 4 ) == 0
01774           || isEmpty() );
01775 }
01776 
01777 bool ContentType::isPlainText() const
01778 {
01779   return ( strcasecmp( mimeType().constData(), "text/plain" ) == 0
01780           || isEmpty() );
01781 }
01782 
01783 bool ContentType::isHTMLText() const
01784 {
01785   return strcasecmp( mimeType().constData(), "text/html" ) == 0;
01786 }
01787 
01788 bool ContentType::isImage() const
01789 {
01790   return strncasecmp( mediaType().constData(), "image", 5 ) == 0;
01791 }
01792 
01793 bool ContentType::isMultipart() const
01794 {
01795   return strncasecmp( mediaType().constData(), "multipart", 9 ) == 0;
01796 }
01797 
01798 bool ContentType::isPartial() const
01799 {
01800   return strcasecmp( mimeType().constData(), "message/partial" ) == 0;
01801 }
01802 
01803 QByteArray ContentType::charset() const
01804 {
01805   QByteArray ret = parameter( QLatin1String( "charset" ) ).toLatin1();
01806   if ( ret.isEmpty() || forceDefaultCharset() ) {
01807     //return the default-charset if necessary
01808     ret = defaultCharset();
01809   }
01810   return ret;
01811 }
01812 
01813 void ContentType::setCharset( const QByteArray &s )
01814 {
01815   setParameter( QLatin1String( "charset" ), QString::fromLatin1( s ) );
01816 }
01817 
01818 QByteArray ContentType::boundary() const
01819 {
01820   return parameter( QLatin1String( "boundary" ) ).toLatin1();
01821 }
01822 
01823 void ContentType::setBoundary( const QByteArray &s )
01824 {
01825   setParameter( QLatin1String( "boundary" ), QString::fromLatin1( s ) );
01826 }
01827 
01828 QString ContentType::name() const
01829 {
01830   return parameter( QLatin1String( "name" ) );
01831 }
01832 
01833 void ContentType::setName( const QString &s, const QByteArray &cs )
01834 {
01835   Q_D(ContentType);
01836   d->encCS = cs;
01837   setParameter( QLatin1String( "name" ), s );
01838 }
01839 
01840 QByteArray ContentType::id() const
01841 {
01842   return parameter( QLatin1String( "id" ) ).toLatin1();
01843 }
01844 
01845 void ContentType::setId( const QByteArray &s )
01846 {
01847   setParameter( QLatin1String( "id" ), QString::fromLatin1( s ) );
01848 }
01849 
01850 int ContentType::partialNumber() const
01851 {
01852   QByteArray p = parameter( QLatin1String( "number" ) ).toLatin1();
01853   if ( !p.isEmpty() ) {
01854     return p.toInt();
01855   } else {
01856     return -1;
01857   }
01858 }
01859 
01860 int ContentType::partialCount() const
01861 {
01862   QByteArray p = parameter( QLatin1String( "total" ) ).toLatin1();
01863   if ( !p.isEmpty() ) {
01864     return p.toInt();
01865   } else {
01866     return -1;
01867   }
01868 }
01869 
01870 contentCategory ContentType::category() const
01871 {
01872   return d_func()->category;
01873 }
01874 
01875 void ContentType::setCategory( contentCategory c )
01876 {
01877   Q_D(ContentType);
01878   d->category = c;
01879 }
01880 
01881 void ContentType::setPartialParams( int total, int number )
01882 {
01883   setParameter( QLatin1String( "number" ), QString::number( number ) );
01884   setParameter( QLatin1String( "total" ), QString::number( total ) );
01885 }
01886 
01887 bool ContentType::parse( const char* &scursor, const char * const send,
01888                          bool isCRLF )
01889 {
01890   Q_D(ContentType);
01891   // content-type: type "/" subtype *(";" parameter)
01892 
01893   clear();
01894   eatCFWS( scursor, send, isCRLF );
01895   if ( scursor == send ) {
01896     return false; // empty header
01897   }
01898 
01899   // type
01900   QPair<const char*,int> maybeMimeType;
01901   if ( !parseToken( scursor, send, maybeMimeType, false /* no 8Bit */ ) ) {
01902     return false;
01903   }
01904   d->mimeType = QByteArray( maybeMimeType.first, maybeMimeType.second ).toLower();
01905 
01906   // subtype
01907   eatCFWS( scursor, send, isCRLF );
01908   if ( scursor == send || *scursor != '/' ) {
01909     return false;
01910   }
01911   scursor++;
01912   eatCFWS( scursor, send, isCRLF );
01913   if ( scursor == send ) {
01914     return false;
01915   }
01916 
01917   QPair<const char*,int> maybeSubType;
01918   if ( !parseToken( scursor, send, maybeSubType, false /* no 8bit */ ) ) {
01919     return false;
01920   }
01921   d->mimeSubType = QByteArray( maybeSubType.first, maybeSubType.second ).toLower();
01922 
01923   // parameter list
01924   eatCFWS( scursor, send, isCRLF );
01925   if ( scursor == send ) {
01926     goto success; // no parameters
01927   }
01928 
01929   if ( *scursor != ';' ) {
01930     return false;
01931   }
01932   scursor++;
01933 
01934   if ( !Parametrized::parse( scursor, send, isCRLF ) ) {
01935     return false;
01936   }
01937 
01938   // adjust category
01939 success:
01940   if ( isMultipart() ) {
01941     d->category = CCcontainer;
01942   } else {
01943     d->category = CCsingle;
01944   }
01945   return true;
01946 }
01947 
01948 //-----</Content-Type>-------------------------
01949 
01950 //-----<ContentID>----------------------
01951 
01952 kmime_mk_trivial_ctor_with_name_and_dptr( ContentID, SingleIdent, Content-ID )
01953 kmime_mk_dptr_ctor( ContentID, SingleIdent )
01954 
01955 bool ContentID::parse( const char* &scursor, const char *const send, bool isCRLF )
01956 {
01957   Q_D ( ContentID );
01958   // Content-id := "<" contentid ">"
01959   // contentid := now whitespaces
01960 
01961   const char* origscursor = scursor;
01962   if ( !SingleIdent::parse ( scursor, send, isCRLF ) )
01963   {
01964     scursor = origscursor;
01965     d->msgIdList.clear();
01966 
01967     while ( scursor != send )
01968     {
01969       eatCFWS ( scursor, send, isCRLF );
01970       // empty entry ending the list: OK.
01971       if ( scursor == send )
01972       {
01973         return true;
01974       }
01975       // empty entry: ignore.
01976       if ( *scursor == ',' )
01977       {
01978         scursor++;
01979         continue;
01980       }
01981 
01982       AddrSpec maybeContentId;
01983       // Almost parseAngleAddr
01984       if ( scursor == send || *scursor != '<' )
01985       {
01986         return false;
01987       }
01988       scursor++; // eat '<'
01989 
01990       eatCFWS ( scursor, send, isCRLF );
01991       if ( scursor == send )
01992       {
01993         return false;
01994       }
01995 
01996       // Save chars untill '>''
01997       QString result;
01998       if( !parseAtom(scursor, send, result, false) ) {
01999         return false;
02000       }
02001 
02002       eatCFWS ( scursor, send, isCRLF );
02003       if ( scursor == send || *scursor != '>' )
02004       {
02005         return false;
02006       }
02007       scursor++;
02008       // /Almost parseAngleAddr
02009 
02010       maybeContentId.localPart = result;
02011       d->msgIdList.append ( maybeContentId );
02012 
02013       eatCFWS ( scursor, send, isCRLF );
02014       // header end ending the list: OK.
02015       if ( scursor == send )
02016       {
02017         return true;
02018       }
02019       // regular item separator: eat it.
02020       if ( *scursor == ',' )
02021       {
02022         scursor++;
02023       }
02024     }
02025     return true;
02026   }
02027   else
02028   {
02029     return true;
02030   }
02031 }
02032 
02033 //-----</ContentID>----------------------
02034 
02035 //-----<ContentTransferEncoding>----------------------------
02036 
02037 //@cond PRIVATE
02038 kmime_mk_trivial_ctor_with_name_and_dptr( ContentTransferEncoding,
02039                                  Generics::Token, Content-Transfer-Encoding )
02040 //@endcond
02041 
02042 typedef struct { const char *s; int e; } encTableType;
02043 
02044 static const encTableType encTable[] =
02045 {
02046   { "7Bit", CE7Bit },
02047   { "8Bit", CE8Bit },
02048   { "quoted-printable", CEquPr },
02049   { "base64", CEbase64 },
02050   { "x-uuencode", CEuuenc },
02051   { "binary", CEbinary },
02052   { 0, 0}
02053 };
02054 
02055 void ContentTransferEncoding::clear()
02056 {
02057   Q_D(ContentTransferEncoding);
02058   d->decoded = true;
02059   d->cte = CE7Bit;
02060   Token::clear();
02061 }
02062 
02063 contentEncoding ContentTransferEncoding::encoding() const
02064 {
02065   return d_func()->cte;
02066 }
02067 
02068 void ContentTransferEncoding::setEncoding( contentEncoding e )
02069 {
02070   Q_D(ContentTransferEncoding);
02071   d->cte = e;
02072 
02073   for ( int i = 0; encTable[i].s != 0; ++i ) {
02074     if ( d->cte == encTable[i].e ) {
02075       setToken( encTable[i].s );
02076       break;
02077     }
02078   }
02079 }
02080 
02081 bool ContentTransferEncoding::decoded() const
02082 {
02083   return d_func()->decoded;
02084 }
02085 
02086 void ContentTransferEncoding::setDecoded( bool decoded )
02087 {
02088   Q_D(ContentTransferEncoding);
02089   d->decoded = decoded;
02090 }
02091 
02092 bool ContentTransferEncoding::needToEncode() const
02093 {
02094   const Q_D(ContentTransferEncoding);
02095   return d->decoded && (d->cte == CEquPr || d->cte == CEbase64);
02096 }
02097 
02098 bool ContentTransferEncoding::parse( const char *& scursor,
02099                                      const char * const send, bool isCRLF )
02100 {
02101   Q_D(ContentTransferEncoding);
02102   clear();
02103   if ( !Token::parse( scursor, send, isCRLF ) ) {
02104     return false;
02105   }
02106 
02107   // TODO: error handling in case of an unknown encoding?
02108   for ( int i = 0; encTable[i].s != 0; ++i ) {
02109     if ( strcasecmp( token().constData(), encTable[i].s ) == 0 ) {
02110       d->cte = ( contentEncoding )encTable[i].e;
02111       break;
02112     }
02113   }
02114   d->decoded = ( d->cte == CE7Bit || d->cte == CE8Bit );
02115   return true;
02116 }
02117 
02118 //-----</ContentTransferEncoding>---------------------------
02119 
02120 //-----<ContentDisposition>--------------------------
02121 
02122 //@cond PRIVATE
02123 kmime_mk_trivial_ctor_with_name_and_dptr( ContentDisposition,
02124                                  Generics::Parametrized, Content-Disposition )
02125 //@endcond
02126 
02127 QByteArray ContentDisposition::as7BitString( bool withHeaderType ) const
02128 {
02129   if ( isEmpty() ) {
02130     return QByteArray();
02131   }
02132 
02133   QByteArray rv;
02134   if ( withHeaderType ) {
02135     rv += typeIntro();
02136   }
02137 
02138   if ( d_func()->disposition == CDattachment ) {
02139     rv += "attachment";
02140   } else if ( d_func()->disposition == CDinline ) {
02141     rv += "inline";
02142   } else {
02143     return QByteArray();
02144   }
02145 
02146   if ( !Parametrized::isEmpty() ) {
02147     rv += "; " + Parametrized::as7BitString( false );
02148   }
02149 
02150   return rv;
02151 }
02152 
02153 bool ContentDisposition::isEmpty() const
02154 {
02155   return d_func()->disposition == CDInvalid;
02156 }
02157 
02158 void ContentDisposition::clear()
02159 {
02160   Q_D(ContentDisposition);
02161   d->disposition = CDInvalid;
02162   Parametrized::clear();
02163 }
02164 
02165 contentDisposition ContentDisposition::disposition() const
02166 {
02167   return d_func()->disposition;
02168 }
02169 
02170 void ContentDisposition::setDisposition( contentDisposition disp )
02171 {
02172   Q_D(ContentDisposition);
02173   d->disposition = disp;
02174 }
02175 
02176 QString KMime::Headers::ContentDisposition::filename() const
02177 {
02178   return parameter( QLatin1String( "filename" ) );
02179 }
02180 
02181 void ContentDisposition::setFilename( const QString &filename )
02182 {
02183   setParameter( QLatin1String( "filename" ), filename );
02184 }
02185 
02186 bool ContentDisposition::parse( const char *& scursor, const char * const send,
02187                                 bool isCRLF )
02188 {
02189   Q_D(ContentDisposition);
02190   clear();
02191 
02192   // token
02193   QByteArray token;
02194   eatCFWS( scursor, send, isCRLF );
02195   if ( scursor == send ) {
02196     return false;
02197   }
02198 
02199   QPair<const char*,int> maybeToken;
02200   if ( !parseToken( scursor, send, maybeToken, false /* no 8Bit */ ) ) {
02201     return false;
02202   }
02203 
02204   token = QByteArray( maybeToken.first, maybeToken.second ).toLower();
02205   if ( token == "inline" ) {
02206     d->disposition = CDinline;
02207   } else if ( token == "attachment" ) {
02208     d->disposition = CDattachment;
02209   } else {
02210     return false;
02211   }
02212 
02213   // parameter list
02214   eatCFWS( scursor, send, isCRLF );
02215   if ( scursor == send ) {
02216     return true; // no parameters
02217   }
02218 
02219   if ( *scursor != ';' ) {
02220     return false;
02221   }
02222   scursor++;
02223 
02224   return Parametrized::parse( scursor, send, isCRLF );
02225 }
02226 
02227 //-----</ContentDisposition>-------------------------
02228 
02229 //@cond PRIVATE
02230 kmime_mk_trivial_ctor_with_name( Subject, Generics::Unstructured, Subject )
02231 //@endcond
02232 
02233 bool Subject::isReply() const
02234 {
02235   return asUnicodeString().indexOf( QLatin1String( "Re:" ), 0, Qt::CaseInsensitive ) == 0;
02236 }
02237 
02238 Base* createHeader( const QByteArray& type )
02239 {
02240   return HeaderFactory::self()->createHeader( type );
02241 }
02242 
02243 
02244 //@cond PRIVATE
02245 kmime_mk_trivial_ctor_with_name( ContentDescription,
02246                                  Generics::Unstructured, Content-Description )
02247 kmime_mk_trivial_ctor_with_name( ContentLocation,
02248                                 Generics::Unstructured, Content-Location )
02249 kmime_mk_trivial_ctor_with_name( From, Generics::MailboxList, From )
02250 kmime_mk_trivial_ctor_with_name( Sender, Generics::SingleMailbox, Sender )
02251 kmime_mk_trivial_ctor_with_name( To, Generics::AddressList, To )
02252 kmime_mk_trivial_ctor_with_name( Cc, Generics::AddressList, Cc )
02253 kmime_mk_trivial_ctor_with_name( Bcc, Generics::AddressList, Bcc )
02254 kmime_mk_trivial_ctor_with_name( ReplyTo, Generics::AddressList, Reply-To )
02255 kmime_mk_trivial_ctor_with_name( Keywords, Generics::PhraseList, Keywords )
02256 kmime_mk_trivial_ctor_with_name( MIMEVersion, Generics::DotAtom, MIME-Version )
02257 kmime_mk_trivial_ctor_with_name( Supersedes, Generics::SingleIdent, Supersedes )
02258 kmime_mk_trivial_ctor_with_name( InReplyTo, Generics::Ident, In-Reply-To )
02259 kmime_mk_trivial_ctor_with_name( References, Generics::Ident, References )
02260 kmime_mk_trivial_ctor_with_name( Organization, Generics::Unstructured, Organization )
02261 kmime_mk_trivial_ctor_with_name( UserAgent, Generics::Unstructured, User-Agent )
02262 //@endcond
02263 
02264 } // namespace Headers
02265 
02266 } // namespace KMime

KMIME Library

Skip menu "KMIME Library"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • 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.4
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