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