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